Start ditching wordexp in Ruby

This commit is contained in:
Sami Samhuri 2026-01-02 16:15:49 -08:00
parent 79ba26c76b
commit 9ae167ac4a
No known key found for this signature in database
3 changed files with 82 additions and 12 deletions

View file

@ -51,7 +51,13 @@ module Shell
end end
def builtin_cd(args) def builtin_cd(args)
Dir.chdir args.first dir = args.first
if dir.nil?
Dir.chdir Dir.home
else
Dir.chdir dir
end
ENV["PWD"] = Dir.pwd
0 0
end end

View file

@ -50,16 +50,21 @@ module Shell
return 0 if line.strip.empty? # no input, no-op return 0 if line.strip.empty? # no input, no-op
logger.verbose "Processing command: #{line.inspect}" logger.verbose "Processing command: #{line.inspect}"
args = word_expander.expand(line) commands = parse_line(line)
cmd = args.shift result = nil
logger.verbose "Parsed command: #{cmd} #{args.inspect}" commands.each do |command|
if builtins.builtin?(cmd) args = word_expander.expand(command)
logger.verbose "Executing builtin #{cmd}" program = args.shift
builtins.exec(cmd, args) logger.verbose "Parsed command: #{program} #{args.inspect}"
else if builtins.builtin?(program)
logger.verbose "Shelling out for #{cmd}" logger.verbose "Executing builtin #{program}"
job_control.exec_command(cmd, args) result = builtins.exec(program, args)
else
logger.verbose "Shelling out for #{program}"
result = job_control.exec_command(program, args)
end
end end
result
rescue Errno => e rescue Errno => e
warn "#{red("[ERROR]")} #{e.message}" warn "#{red("[ERROR]")} #{e.message}"
-1 -1
@ -69,5 +74,64 @@ module Shell
def prompt(pwd) def prompt(pwd)
"#{blue(pwd)}#{white("%")} #{CLEAR}" "#{blue(pwd)}#{white("%")} #{CLEAR}"
end end
def parse_line(line)
commands = []
command = "".dup
state = :unquoted
line.each_char do |c|
case state
when :unquoted
case c
when ";"
commands << command
command = "".dup
when "'"
command << c
state = :single_quoted
when "\""
command << c
state = :double_quoted
when "\\"
command << c
state = :escaped
else
command << c
end
when :single_quoted
command << c
state = :unquoted if c == "'"
when :double_quoted
case c
when "\\"
state = :double_quoted_escape
else
command << c
end
state = :unquoted if c == "\""
when :double_quoted_escape
case c
when "\"", "\\", "$", "`"
# no-op
else
command << "\\" # POSIX behaviour, backslash remains
end
command << c
state = :double_quoted
when :escaped
command << c
state = :unquoted
else
raise "Unknown state #{state}"
end
end
commands << command
commands
end
end end
end end

View file

@ -108,11 +108,11 @@ class ShellTest < Minitest::Test
######################### #########################
def test_builtin_cd_no_args def test_builtin_cd_no_args
skip "cannot easily implement without sequencing with ; or &&" assert_equal Dir.home, `#{A1_PATH} -c 'cd; echo $PWD'`.strip
end end
def test_builtin_cd def test_builtin_cd
skip "cannot easily implement without sequencing with ; or &&" assert_equal File.join(Dir.pwd, "blah"), `#{A1_PATH} -c 'mkdir -p blah; cd blah; echo $PWD; cd ..; rm -rf blah'`.strip
end end
def test_builtin_cd_dash def test_builtin_cd_dash