Commits

trunk
Switch branches/tags
All users
Until Jan 27, 2026
January 2026
Su Mo Tu We Th Fr Sa
28 29 30 31 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
1 2 3 4 5 6 7

Commits on January 2, 2026

  1. fix: apply redirects to builtins
    Builtin commands now properly respect output redirects by using
    file descriptor manipulation before execution.
    
    Test results: 157/192 passing (81.8%) in posix_compliance_test.sh
    mfwolffe committed
  2. feat: add pipeline negation and fix set builtin
    - Add pipeline negation support (! cmd inverts exit code)
    - Fix set builtin to handle -- and positional parameters
    - Add POSIX compliance test suite (10 test files)
    
    Test results: 151/192 passing (78.6%) in posix_compliance_test.sh
    mfwolffe committed
  3. feat: improve POSIX compliance (+27 tests passing)
    - Add non-colon parameter expansion variants: ${VAR-default},
      ${VAR=assigned}, ${VAR+alternate}, ${VAR?error} (check unset only)
    - Add test builtin file operators: -L/-h (symlink), -p (FIFO),
      -S (socket), -b (block), -c (char), -nt/-ot/-ef (file comparison)
    - Fix backslash stripping in glob expansion to preserve escape
      sequences like \n for printf (was breaking printf tests)
    - Add nested backtick escaping support: `echo \`inner\``
    
    Test pass rate improved from 64.1% to 69.1%
    mfwolffe committed

Commits on January 1, 2026

  1. feat: add echo builtin, history expansion, and fix shell gaps
    Major features:
    - Add echo builtin with -n, -e, -E flags (bash-compatible)
    - Implement history expansion (!!, !$, !^, !*, !-n, !n, !string)
    - Add ~user expansion with passwd lookup in cd builtin
    - Fix subshell stdin handling in pipelines (raw FD tracking)
    - Add terminal attribute save/restore for proper cleanup
    - Implement SIGHUP, SIGWINCH, SIGQUIT signal handling
    - Add login shell support (-l flag, /etc/profile sourcing)
    
    Bug fixes:
    - Fix command substitution capture using fork-based approach
    - Fix echo output capture in subprocesses (use locked stdout)
    - Update CLAUDE.md to reflect Phase 5-6 complete status
    
    New files:
    - prompt.rs: PS1/PS1_RIGHT customizable prompts
    - completion_spec.rs: per-command completion specifications
    espadonne committed
  2. espadonne committed
  3. fix(repl): auto-complete single matches without showing menu
    - Enable quick_completions: auto-selects when only one match exists
    - Enable partial_completions: fills common prefix for multiple matches
    
    Now 'cd tes<Tab>' completes directly to 'cd tests/' instead of
    showing a single-item menu.
    espadonne committed
  4. feat(repl): add fish-style arrow key navigation for completions
    - Up/Down arrows navigate vertically in the completion menu
    - Left/Right arrows navigate horizontally
    - Shift+Tab cycles backwards through completions
    - Arrow keys fall back to normal cursor movement when menu is closed
    - Enter selects completion or submits command
    espadonne committed
  5. fix: resolve compiler warnings and enable tab completion
    Warning fixes:
    - Prefix unused variables with _ (print_format, use_default_path,
      mark_no_sighup, context, prev)
    - Remove unnecessary unsafe blocks around nix::unistd::dup2 calls
    
    Tab completion fix:
    - Add ColumnarMenu for displaying completions
    - Configure Emacs keybindings with Tab triggering completion menu
    - Import MenuBuilder trait for menu configuration
    
    Tab completion now works: type partial command/filename and press Tab.
    espadonne committed
  6. feat(builtins): implement printf, mapfile, and disown
    Add three new shell builtins:
    
    - printf: Formatted output with %s, %d, %x, %o, %c, %b, %q specifiers
      and escape sequences (\n, \t, \xHH, \0nnn)
    
    - mapfile/readarray: Read lines from stdin into an indexed array
      with options -d (delimiter), -n (count), -O (origin), -s (skip), -t (trim)
    
    - disown: Remove jobs from job control with -a (all), -r (running), -h flags
    
    Also adds supporting methods to JobList: current_job_id(), previous_job(),
    disown_job(), and disown_all().
    espadonne committed
  7. feat(control): implement select loop construct
    Add full support for the bash select loop:
    - Grammar rule for select var in words; do body; done
    - SelectStatement AST node with var_name, words, and body
    - Parser implementation for select statements
    - Executor with menu display, PS3 prompt, REPLY variable
    
    The select loop displays a numbered menu, reads user selection,
    sets the loop variable to the selected item, and executes the body
    until break is called or EOF is reached.
    espadonne committed
  8. feat(extended-test): implement [[ ]] with =~ regex support
    Add full [[ expression ]] extended test support:
    - Grammar: extended_test rule with cond_expr, cond_or, cond_and, etc.
    - AST: CondExpr enum with Or, And, Not, Unary, Binary, Word variants
    - Parser: parse_extended_test and related functions
    - Executor: evaluate_cond_expr with short-circuit evaluation
    
    Operators supported:
    - Unary: -z, -n, -e, -f, -d, -r, -w, -x, -s, -L, -h, -p, -S, -b, -c
    - Binary string: ==, =, != (with glob pattern matching)
    - Binary regex: =~ (sets BASH_REMATCH array)
    - Binary numeric: -eq, -ne, -lt, -le, -gt, -ge
    - Binary file: -nt, -ot, -ef
    - Logical: && (and), || (or), ! (not), grouping with ()
    espadonne committed
  9. feat(expand): implement indirect expansion and transformation operators
    Add support for:
    - ${!var} indirect expansion (use var's value as variable name)
    - ${var@Q} quote value for reuse as input
    - ${var@E} expand escape sequences
    - ${var@U} uppercase all / ${var@u} uppercase first
    - ${var@L} lowercase all
    - ${var@P}, ${var@A}, ${var@K}, ${var@a} (basic support)
    
    Grammar updates:
    - Add ${!var} rule (distinct from ${!arr[@]} for array indices)
    - Add @op modifier for transformation operators
    
    Add 7 tests for new expansion features
    espadonne committed
  10. feat(arithmetic): implement comma operator with lowest precedence
    Add comma operator support to arithmetic expressions:
    - Tokenizer recognizes ',' as Comma token
    - Add parse_comma() as lowest precedence level (below ternary)
    - Evaluates expressions left-to-right, returns last value
    - Common pattern for side effects: (a=1, b=2, a+b)
    - Add 5 tests for comma operator behavior
    espadonne committed
  11. feat(arithmetic): add bitwise assignment operators
    Add support for bitwise compound assignment operators:
    - &= (AND assign)
    - |= (OR assign)
    - ^= (XOR assign)
    - <<= (left shift assign)
    - >>= (right shift assign)
    
    These operators work with lvalue tracking to properly modify
    variables, consistent with bash behavior.
    
    Examples:
      x=7; echo $((x &= 3))   # outputs 3
      x=5; echo $((x |= 2))   # outputs 7
      x=1; echo $((x <<= 4))  # outputs 16
    espadonne committed
  12. feat(arithmetic): implement lvalue tracking for assignments
    Add proper lvalue tracking to arithmetic expansion, enabling assignments
    and increment/decrement operators to actually modify variables.
    
    Changes:
    - Add LValue enum to distinguish values from variable references
    - All parse methods now return LValue, preserving variable identity
    - Assignment operators (=, +=, -=, *=, /=, %=, **=) store results
    - Pre-increment/decrement (++x, --x) modify and return new value
    - Post-increment/decrement (x++, x--) return old value and modify
    - NotAnLvalue error for invalid assignments (e.g., 5++, (x)=1)
    
    Examples now work correctly:
      x=5; echo $((x += 3))  # outputs 8, x is now 8
      x=5; echo $((++x))     # outputs 6, x is now 6
      x=5; echo $((x++))     # outputs 5, x is now 6
      a = b = c = 5          # chained assignment works
    
    29 comprehensive tests added covering all lvalue operations.
    espadonne committed
  13. feat(arithmetic): implement full bash-compatible arithmetic expansion
    Add 25+ operators with proper C-style precedence (17 levels) to arithmetic
    expansion engine. Changes signature from &Context to &mut Context to enable
    future assignment operator support.
    
    New operators:
    - Power: ** (right-associative)
    - Bitwise: & | ^ ~ << >>
    - Comparison: < > <= >= == != (return 0 or 1)
    - Logical: && || ! (short-circuit evaluation)
    - Assignment: = += -= *= /= %= **= (simplified, no lvalue tracking)
    - Increment/Decrement: ++ -- (pre and post, simplified)
    - Ternary: ? :
    
    Precedence levels (lowest to highest):
    1. Ternary (? :)
    2. Assignment (=, +=, etc.) - right-assoc
    3. Logical OR (||)
    4. Logical AND (&&)
    5. Bitwise OR (|)
    6. Bitwise XOR (^)
    7. Bitwise AND (&)
    8. Equality (==, !=)
    9. Relational (<, >, <=, >=)
    10. Shift (<<, >>)
    11. Addition/Subtraction (+, -)
    12. Multiplication/Division/Modulo (*, /, %)
    13. Power (**) - right-assoc
    14. Unary (!, ~, +, -)
    15. Pre-increment/decrement (++, --)
    16. Post-increment/decrement (++, --)
    17. Primary (numbers, variables, parentheses)
    
    Implementation details:
    - Multi-character tokenization with greedy matching
    - Short-circuit evaluation for && and ||
    - Comparison operators return 0 (false) or 1 (true)
    - Power uses u32 exponent (negative exponents treated as 0)
    - Shift operators use wrapping semantics
    - Assignment/increment/decrement simplified (no lvalue tracking)
    
    Files modified:
    - arithmetic.rs: Complete rewrite with 17 precedence levels
    - expand.rs: Update test cases to use &mut Context
    espadonne committed
  14. feat(coproc): implement bidirectional coprocess builtin
    Add support for the coproc builtin which allows bidirectional
    communication with background processes using pipes.
    
    Features:
    - Create coproc with custom or default name (COPROC)
    - Two pipes for bidirectional I/O (stdin/stdout)
    - File descriptors exposed as array variables (NAME[0], NAME[1])
    - Integration with job control system
    - Proper process group management
    
    Implementation:
    - Add CoprocState struct to rush_expand::Context
    - Add builtin_coproc() in rush-executor/command.rs
    - Helper methods: set_coproc_vars() and clear_coproc()
    - Automatic cleanup on coproc replacement
    
    Usage:
      coproc [NAME] command [args...]
    
    Example:
      coproc grep pattern
      echo "test" >&${COPROC[1]}
      read result <&${COPROC[0]}
    espadonne committed
  15. feat(executor): implement FIFO-based process substitution
    Implement full process substitution support using named pipes (FIFOs)
    for <(command) and >(command) syntax, enabling advanced piping patterns.
    
    Core Implementation (process_subst.rs):
    - Create named FIFOs in /tmp with unique names (rush-psub-{pid}-{counter})
    - Fork child processes to execute commands in background
    - Connect command stdout/stdin to FIFOs using dup2()
    - Global registry tracks active FIFOs and PIDs for cleanup
    - Thread-safe Mutex-based registry with proper cleanup handlers
    
    Process Substitution Input <(command):
    - Creates FIFO that provides command's stdout as readable file
    - Forks child with stdout redirected to FIFO write end
    - Parent opens FIFO read end and uses as stdin source
    - Example: diff <(ls dir1) <(ls dir2)
    
    Process Substitution Output >(command):
    - Creates FIFO that feeds into command's stdin as writable file
    - Forks child with stdin redirected from FIFO read end
    - Parent opens FIFO write end and uses as stdout target
    - Example: tee >(gzip > file.gz) >(bzip2 > file.bz2)
    
    Integration:
    - Update redirect.rs to handle ProcessSubstInput/ProcessSubstOutput
    - Open FIFOs as file handles for stdin/stdout redirection
    - Use command_executor callback for proper context handling
    - Fallback to "sh -c" if executor not available
    
    Cleanup Handlers:
    - Register atexit() handler in CLI to cleanup all FIFOs on exit
    - wait_for_all() function for non-blocking child reaping
    - Automatic FIFO removal when processes complete
    - Proper resource cleanup on fork failures
    
    Platform Support:
    - Full implementation on Unix-like systems (Linux, macOS, BSD)
    - Uses nix crate for safe syscall wrappers (mkfifo, fork, dup2)
    - Graceful error messages on non-Unix platforms
    - Added nix dependency to rush-cli
    
    Testing:
    - Verified grammar and AST parsing of process substitution syntax
    - Confirmed FIFO creation and cleanup mechanisms
    - Validated fork/exec process management
    
    This enables advanced bash-compatible patterns like:
      diff <(sort file1) <(sort file2)
      cat file | tee >(wc -l) >(grep pattern)
      comm <(ls dir1) <(ls dir2)
    espadonne committed
  16. feat(parser): add grammar and AST support for process substitution
    Add parsing infrastructure for process substitution syntax <(command)
    and >(command), preparing for FIFO-based implementation.
    
    Grammar Changes:
    - Add process_subst_input rule for <(command) syntax
    - Add process_subst_output rule for >(command) syntax
    - Reuse command_subst_content for parsing command strings
    - Position rules before standard redirects to match correctly
    
    AST Changes:
    - Add ProcessSubstInput variant to Redirect enum
    - Add ProcessSubstOutput variant to Redirect enum
    - Store command string for later execution
    
    Parser Integration:
    - Handle process_subst_input and process_subst_output rules
    - Reconstruct command content using existing infrastructure
    - Properly handle nested parentheses in commands
    
    Redirect Stubs:
    - Add placeholder implementations in redirect.rs
    - Return "not yet implemented" errors for now
    - Will be replaced with FIFO-based implementation
    
    This commit establishes the foundation for process substitution.
    The actual FIFO creation and process forking will be implemented
    in the process_subst.rs module in the next commit.
    espadonne committed
  17. feat(glob): implement extended glob negation with two-stage filtering
    Fix broken !(pattern) extended glob operator and add comprehensive
    support for extended glob patterns in both grammar and expansion.
    
    Core Implementation:
    - Add ExtGlobPattern enum with Standard and Negation variants
    - Implement two-stage filtering: expand base pattern, then exclude matches
    - Convert glob patterns to regex for precise negation matching
    - Add glob_to_regex() function for pattern conversion
    
    Grammar Changes:
    - Add extglob_pattern rule to parse !(pat), ?(pat), *(pat), +(pat), @(pat)
    - Treat extended globs as word parts for proper tokenization
    - Support extglob patterns in all word contexts
    
    Parser Integration:
    - Handle extglob_pattern rule in parse_word_part()
    - Convert extended globs to literal strings for later expansion
    
    Glob Expansion:
    - Replace broken "*" conversion for !(pattern) with proper negation logic
    - Implement expand_standard_glob() for non-negated patterns
    - Add has_glob_chars() detection for extended glob operators
    - Wire extglob option from ShellOptions through GlobOptions
    
    Option Handling:
    - Add extglob field to GlobOptions (default: false)
    - Check context.options.extglob before processing extended patterns
    - Skip extended glob processing when option is disabled
    
    Testing:
    - Verified !(*.txt) correctly excludes .txt files
    - Verified !(file.*) correctly excludes files starting with "file."
    - Verified extglob option toggle works correctly
    - Confirmed bash-compatible negation behavior
    
    Example:
      shopt -s extglob
      echo !(*.txt)  # Outputs: file.log file.md file.rs (excludes .txt files)
    
    The !(pattern) operator now works correctly with proper two-stage
    filtering instead of the broken "*" approximation.
    espadonne committed
  18. feat(arrays): implement associative arrays with declare builtin
    Add full support for associative arrays (bash-compatible hash maps) and
    the declare/typeset builtin for array and variable declarations.
    
    Core Changes:
    - Add ArrayType enum to distinguish indexed vs associative arrays
    - Modify Context.arrays to HashMap<String, ArrayType>
    - Add helper methods for array operations (get/set/length/type-checking)
    
    Declare Builtin:
    - Support flags: -a (indexed), -A (associative), -r (readonly), -x (export), -p (print)
    - Implement array creation and attribute management
    - Add proper print formatting for both array types
    
    Variable Expansion:
    - Update expand_var() to handle both array types
    - Support ${arr[key]} for associative arrays
    - Support ${arr[index]} for indexed arrays
    - Maintain backward compatibility for indexed arrays
    
    Pipeline Integration:
    - Update array assignment handling in pipeline.rs
    - Use Context helper methods for type-safe array operations
    - Support both indexed and associative array element assignments
    
    Testing:
    - Verified array creation with declare -a/-A
    - Verified element access and assignment
    - Verified array lengths and expansions
    - Verified declare -p output formatting
    espadonne committed
  19. feat: implement comprehensive subshell support
    Adds full subshell support with process isolation, background
    execution, pipeline integration, and nested command substitution.
    
    Parser changes:
    - Add Subshell AST node and PipelineElement enum
    - Add subshell grammar rule: (commands)
    - Refactor pipeline to support PipelineElement (Simple | Subshell)
    - Implement recursive command_subst_content for nested parentheses
    - Add reconstruct_command_subst_content() helper
    
    Executor changes:
    - Implement execute_subshell() using fork/waitpid
    - Add execute_subshell_background() for background jobs
    - Handle subshells in pipelines with proper pipe plumbing
    - Support subshells in background.rs for pipeline backgrounds
    - Add break/continue handling in control flow loops
    - Improve case statement with glob pattern matching
    
    CLI changes:
    - Wire up subshell execution in complete_command handler
    - Handle PipelineElement in heredoc processing
    - Update build_command_string() for job control display
    - Add create_context() helper for command executor setup
    - Add nix dependency for Unix process management
    
    Features implemented:
    ✓ Basic subshells: (command; command)
    ✓ Variable isolation in subshells
    ✓ Directory isolation (cd in subshell doesn't affect parent)
    ✓ Exit isolation (exit in subshell doesn't exit parent)
    ✓ Background subshells: (sleep 1; echo done) &
    ✓ Subshells in pipelines: (echo line1; echo line2) | grep line
    ✓ Nested command substitution: $(echo $(echo inner))
    espadonne committed
  20. feat(expand): implement internal command substitution executor
    Implements proper command substitution using rush's own parser
    and executor instead of falling back to sh -c.
    
    Changes:
    - Add command_subst_exec.rs with dedicated executor using pipes
    - Add CommandExecutorWrapper to Context for pluggable execution
    - Remove sh -c fallback (now fully bespoke implementation)
    - Fix double-close file descriptor bug in pipe handling
    - Integrate internal executor in REPL and CLI contexts
    
    Command substitution now works recursively and properly
    handles nested substitutions.
    espadonne committed
  21. feat(executor): add POSIX builtins (local, read, shift, command, wait, kill)
    Implements additional POSIX-compliant builtin commands:
    - local: declare function-local variables
    - read: read input into variables with prompt support
    - shift: shift positional parameters
    - command: execute commands bypassing functions/aliases
    - wait: wait for background jobs to complete
    - kill: send signals to processes
    
    These builtins improve bash compatibility and enable more
    sophisticated shell scripts.
    espadonne committed
  22. feat(executor): enforce readonly variable protection
    Completes readonly implementation with full enforcement:
    
    Changes:
    - Modified Context::set_var() to return Result<(), String>
    - Returns Err(name) if variable is readonly
    - Updated all set_var call sites to handle Result
    - Added readonly checks in pipeline variable assignments
    - Added readonly checks in for loop variable assignments
    - Updated all tests to use .unwrap()
    
    Enforcement:
    - Variable assignments fail with "readonly variable" error
    - Error occurs in pipeline.rs and control_flow.rs
    - Prevents modification of readonly vars throughout execution
    - Works with export and regular assignments
    
    Testing:
    - Readonly variables now properly protected
    - Attempting to modify returns permission denied error
    - Listing with readonly -p shows all protected vars
    
    This completes the readonly builtin as a full POSIX special builtin.
    espadonne committed
  23. feat(executor): implement readonly builtin (partial)
    Adds readonly variable tracking infrastructure:
    
    Features:
    - readonly: list all readonly variables
    - readonly -p: print in reusable format
    - readonly VAR=value: set and mark readonly
    - readonly VAR: mark existing variable readonly
    - Tracks readonly status in Context
    
    Implementation:
    - Added readonly_vars HashSet to Context
    - Added mark_readonly(), is_readonly(), readonly_vars() methods
    - Implemented builtin_readonly function
    - Lists readonly vars, prevents double-readonly assignment
    
    Limitation:
    - Enforcement during assignment not yet implemented
    - Variable assignments don't check readonly status yet
    - Need to add checking in pipeline execution layer
    
    This is a POSIX special builtin for variable protection.
    espadonne committed
  24. feat(executor): implement unset builtin
    Adds unset functionality for removing variables and functions:
    
    Features:
    - unset NAME...: unset variables and functions
    - unset -v NAME...: unset only variables
    - unset -f NAME...: unset only functions
    - Handles multiple names in one call
    - No error if variable/function doesn't exist (POSIX)
    
    Implementation:
    - Added builtin_unset function
    - Uses context.unset_var() for variables
    - Removes from context.functions for functions
    - By default, unsets both vars and funcs
    - Flags -v/-f restrict to one type
    
    This is a POSIX special builtin, essential for:
    - Cleaning up temporary variables
    - Removing functions from environment
    - Script cleanup and reset operations
    espadonne committed
  25. feat(executor): implement export builtin
    Adds export functionality for environment variable management:
    
    Features:
    - export: list all exported variables
    - export -p: print in reusable format
    - export VAR=value: set and export variable
    - export VAR: export existing variable
    - export -n VAR: unexport variable (keep as local)
    
    Implementation:
    - Added builtin_export function
    - Added unexport_var method to Context
    - Handles assignment and non-assignment forms
    - Lists all exported vars when called without args
    - Proper error handling for invalid options
    
    This is a POSIX special builtin, essential for:
    - Setting environment variables for child processes
    - Configuration in .bashrc/.profile
    - Script environment management
    espadonne committed
  26. feat(executor): implement true, false, and : (colon) builtins
    Adds three simple but essential POSIX builtins:
    
    Features:
    - true: Always returns success (exit 0)
    - false: Always returns failure (exit 1)
    - : (colon): Null command, always returns success
    
    These are widely used in shell scripts for:
    - Infinite loops: while :; do ... done
    - Conditional logic: true && cmd || other
    - Placeholder commands
    - Testing shell behavior
    
    Implementation:
    - Added to execute_builtin match arms
    - true and : return success_result()
    - false returns error_result()
    - Minimal implementation, maximum compatibility
    espadonne committed