Skip to content

Commit 537edb1

Browse files
committed
fix: nested shells
1 parent b6577f8 commit 537edb1

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

lib/coderay/scanners/bash.rb

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ def initialize(*args)
6666
@state = :initial
6767
@quote = nil
6868
@shell = false
69+
@brace_shell = 0
70+
@quote_brace_shell = 0
6971
end
7072

7173
def scan_tokens encoder, options
@@ -106,12 +108,13 @@ def scan_tokens encoder, options
106108
next
107109
elsif match = scan(/`/)
108110
if @shell
111+
encoder.text_token(match, :delimiter)
109112
encoder.end_group :shell
110113
else
111114
encoder.begin_group :shell
115+
encoder.text_token(match, :delimiter)
112116
end
113117
@shell = (not @shell)
114-
encoder.text_token(match, :delimiter)
115118
next
116119
elsif match = scan(/'[^']*'?/)
117120
kind = :string
@@ -137,8 +140,19 @@ def scan_tokens encoder, options
137140
end
138141
kind = IDENT_KIND[var]
139142
kind = :instance_variable if kind == :ident
140-
elsif match = scan(/ \$\( [^\)]+ \) /ox)
141-
kind = :shell
143+
#elsif match = scan(/ \$\( [^\)]+ \) /ox)
144+
elsif match = scan(/ \$\( /ox)
145+
@brace_shell += 1
146+
encoder.begin_group :shell
147+
encoder.text_token(match, :delimiter)
148+
next
149+
elsif match = scan(/ \) /ox)
150+
if @brace_shell > 0
151+
encoder.text_token(match, :delimiter)
152+
encoder.end_group :shell
153+
@brace_shell -= 1
154+
next
155+
end
142156
elsif match = scan(PRE_CONSTANTS)
143157
kind = :predefined_constant
144158
elsif match = scan(/[^\s'"]*[A-Za-z_][A-Za-z_0-9]*\+?=/)
@@ -202,6 +216,20 @@ def scan_tokens encoder, options
202216
kind = :predefined_constant
203217
elsif match = scan(/ (?: \$\(\(.*?\)\) ) /x)
204218
kind = :global_variable
219+
elsif match = scan(/ \$\( /ox)
220+
encoder.begin_group :shell
221+
encoder.text_token(match, :delimiter)
222+
@quote_brace_shell += 1
223+
next
224+
elsif match = scan(/\)/)
225+
if @quote_brace_shell > 0
226+
encoder.text_token(match, :delimiter)
227+
encoder.end_group :shell
228+
@quote_brace_shell -= 1
229+
next
230+
else
231+
kind = :content
232+
end
205233
elsif match = scan(/ \$ (?: (?: \{ [^\}]* \}) | (?: [A-Za-z_0-9]+ ) ) /x)
206234
match =~ /(\$\{?)([^\}]*)(\}?)/
207235
pre=$1
@@ -215,7 +243,7 @@ def scan_tokens encoder, options
215243
end
216244
kind = IDENT_KIND[match]
217245
kind = :instance_variable if kind == :ident
218-
elsif match = scan(/[^#{@quote}\\]+/)
246+
elsif match = scan(/[^\)\$#{@quote}\\]+/)
219247
kind = :content
220248
else match = scan(/.+/)
221249
# this shouldn't be

test/nested_shells.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
blueberry=$(date -d "$(stat -c $(%z) blueberry.exe)")

test/test.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def test_0010_ErbBash
2222
)
2323
end
2424

25-
def test_0011_ErbBash_Ignoring_Errors
25+
def test_0020_ErbBash_Ignoring_Errors
2626
eb_file = File.join($current_dir, "erb_bash.sh")
2727
assert_equal(
2828
#["#!/bin/sh", :directive, "\n", :end_line, "\n", :end_line, "perl", :ident, " ", :space, "-", :operator, "e", :ident, "'s/to=5/to=10/'", :string, " ", :space, "/", :plain, "test", :method, "/", :plain, "file", :ident, "\n", :end_line, "echo", :method, " ", :space, :begin_group, :string, "\"", :delimiter, "Parsed at ", :content, :begin_group, :inline, "<%=", :inline_delimiter, " ", :space, "Time", :constant, ".", :operator, "now", :ident, " ", :space, "%>", :inline_delimiter, :end_group, :inline, "\"", :delimiter, :end_group, :string, "\n", :end_line, "echo", :method, " ", :space, :begin_group, :string, "\"", :delimiter, "Executed at `Date`", :content, "\"", :delimiter, :end_group, :string, "\n", :end_line, "command", :method, " ", :space, "'open quote", :plain, "\n", :end_line, "other_command", :ident, "\n", :end_line],
@@ -31,12 +31,20 @@ def test_0011_ErbBash_Ignoring_Errors
3131
)
3232
end
3333

34-
def test_0011_ErbBash_Ignoring_Errors
34+
def test_0030_heredoc
3535
file = File.join($current_dir, "heredoc.sh")
3636
assert_equal(
3737
["#/bin/bash", :comment, "\n", :end_line, "\n", :end_line, "cat", :ident, " ", :space, :begin_group, :string, "<<EOF", :delimiter, "\n", :end_line, "little brown fox jumps over lazy dog\n ", :content, "EOF", :delimiter, :end_group, :string, "\n", :end_line, "\n", :end_line, "echo", :method, " ", :space, :begin_group, :string, "\"", :delimiter, "end", :content, "\"", :delimiter, :end_group, :string, "\n", :end_line],
3838
CodeRay.scan(File.read(file), :bash).tokens
3939
)
4040
end
4141

42+
def test_0040_nested_shell
43+
file = File.join($current_dir, "nested_shells.sh")
44+
assert_equal(
45+
["blueberry", :instance_variable, "=", :operator, :begin_group, :shell, "$(", :delimiter, "date", :ident, " ", :space, "-", :operator, "d", :ident, " ", :space, :begin_group, :string, "\"", :delimiter, :begin_group, :shell, "$(", :delimiter, "stat -c ", :content, :begin_group, :shell, "$(", :delimiter, "%z", :content, ")", :delimiter, :end_group, :shell, " blueberry.exe", :content, ")", :delimiter, :end_group, :shell, "\"", :delimiter, :end_group, :string, ")", :delimiter, :end_group, :shell, "\n", :end_line],
46+
CodeRay.scan(File.read(file), :bash).tokens
47+
)
48+
end
49+
4250
end

0 commit comments

Comments
 (0)