lib/rouge/lexers/shell.rb in rouge-0.0.2 vs lib/rouge/lexers/shell.rb in rouge-0.0.3
- old
+ new
@@ -1,14 +1,15 @@
module Rouge
module Lexers
- ShellLexer = RegexLexer.create do
- name 'shell'
+ class ShellLexer < RegexLexer
+ tag 'shell'
aliases 'bash', 'zsh', 'ksh', 'sh'
+ extensions 'sh', 'bash', 'zsh', 'ksh'
KEYWORDS = %w(
- if fi else while do done for then return function case
- select continue until esac elif
+ if fi else while do done for then return function
+ select continue until esac elif in
).join('|')
BUILTINS = %w(
alias bg bind break builtin caller cd command compgen
complete declare dirs disown echo enable eval exec exit
@@ -16,94 +17,109 @@
local logout popd printf pushd pwd read readonly set shift
shopt source suspend test time times trap true type typeset
ulimit umask unalias unset wait
).join('|')
- lexer :basic do
+ state :basic do
rule /#.*\n/, 'Comment'
rule /\b(#{KEYWORDS})\s*\b/, 'Keyword'
+ rule /\bcase\b/, 'Keyword', :case
rule /\b(#{BUILTINS})\s*\b(?!\.)/, 'Name.Builtin'
- rule /(\b\w+)(=)/ do |_, var, eq, &out|
- out.call 'Name.Variable', var
- out.call 'Operator', eq
+ rule /(\b\w+)(=)/ do |m|
+ group 'Name.Variable'
+ group 'Operator'
end
rule /[\[\]{}()=]/, 'Operator'
rule /&&|\|\|/, 'Operator'
# rule /\|\|/, 'Operator'
rule /<<</, 'Operator' # here-string
rule /<<-?\s*(\'?)\\?(\w+)[\w\W]+?\2/, 'Literal.String'
end
- lexer :double_quotes do
- rule /"/, 'Literal.String.Double', :pop!
- rule /\\./, 'Literal.String.Escape'
+ state :double_quotes do
+ # NB: "abc$" is literally the string abc$.
+ # Here we prevent :interp from interpreting $" as a variable.
+ rule /(?:\$#?)?"/, 'Literal.String.Double', :pop!
mixin :interp
rule /[^"`\\$]+/, 'Literal.String.Double'
end
- lexer :data do
- # TODO: this should be its own sublexer so we can capture
- # interpolation and such
- rule /$?"/, 'Literal.String.Double', :double_quotes
+ state :data do
+ rule /\\./, 'Literal.String.Escape'
+ rule /\$?"/, 'Literal.String.Double', :double_quotes
# single quotes are much easier than double quotes - we can
# literally just scan until the next single quote.
# POSIX: Enclosing characters in single-quotes ( '' )
# shall preserve the literal value of each character within the
# single-quotes. A single-quote cannot occur within single-quotes.
rule /$?'[^']*'/, 'Literal.String.Single'
+ rule /\*/, 'Keyword'
+
rule /;/, 'Text'
rule /\s+/, 'Text'
- rule /[^=\s\[\]{}()$"\'`\\<]+/, 'Text'
+ rule /[^=\s{}()$"\'`\\<]+/, 'Text'
rule /\d+(?= |\Z)/, 'Number'
rule /</, 'Text'
mixin :interp
end
- lexer :curly do
+ state :curly do
rule /}/, 'Keyword', :pop!
rule /:-/, 'Keyword'
rule /[a-zA-Z0-9_]+/, 'Name.Variable'
rule /[^}:"'`$]+/, 'Punctuation'
mixin :root
end
- lexer :paren do
+ state :paren do
rule /\)/, 'Keyword', :pop!
mixin :root
end
- lexer :math do
+ state :math do
rule /\)\)/, 'Keyword', :pop!
rule %r([-+*/%^|&]|\*\*|\|\|), 'Operator'
rule /\d+/, 'Number'
mixin :root
end
- lexer :backticks do
+ state :case do
+ rule /\besac\b/, 'Keyword', :pop!
+ rule /\|/, 'Punctuation'
+ rule /\)/, 'Punctuation', :case_stanza
+ mixin :root
+ end
+
+ state :case_stanza do
+ rule /;;/, 'Punctuation', :pop!
+ mixin :root
+ end
+
+ state :backticks do
rule /`/, 'Literal.String.Backtick', :pop!
mixin :root
end
- lexer :interp do
+ state :interp do
+ rule /\\$/, 'Literal.String.Escape' # line continuation
+ rule /\\./, 'Literal.String.Escape'
rule /\$\(\(/, 'Keyword', :math
rule /\$\(/, 'Keyword', :paren
rule /\${#?/, 'Keyword', :curly
rule /`/, 'Literal.String.Backtick', :backticks
rule /\$#?(\w+|.)/, 'Name.Variable'
end
- lexer :root do
+ state :root do
mixin :basic
mixin :data
end
-
- mixin :root
end
end
end