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
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
end

View file

@ -50,16 +50,21 @@ module Shell
return 0 if line.strip.empty? # no input, no-op
logger.verbose "Processing command: #{line.inspect}"
args = word_expander.expand(line)
cmd = args.shift
logger.verbose "Parsed command: #{cmd} #{args.inspect}"
if builtins.builtin?(cmd)
logger.verbose "Executing builtin #{cmd}"
builtins.exec(cmd, args)
else
logger.verbose "Shelling out for #{cmd}"
job_control.exec_command(cmd, args)
commands = parse_line(line)
result = nil
commands.each do |command|
args = word_expander.expand(command)
program = args.shift
logger.verbose "Parsed command: #{program} #{args.inspect}"
if builtins.builtin?(program)
logger.verbose "Executing builtin #{program}"
result = builtins.exec(program, args)
else
logger.verbose "Shelling out for #{program}"
result = job_control.exec_command(program, args)
end
end
result
rescue Errno => e
warn "#{red("[ERROR]")} #{e.message}"
-1
@ -69,5 +74,64 @@ module Shell
def prompt(pwd)
"#{blue(pwd)}#{white("%")} #{CLEAR}"
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

View file

@ -108,11 +108,11 @@ class ShellTest < Minitest::Test
#########################
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
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
def test_builtin_cd_dash