lib/rouge/lexers/sed.rb in rouge-0.2.8 vs lib/rouge/lexers/sed.rb in rouge-0.2.9
- old
+ new
@@ -1,22 +1,167 @@
module Rouge
module Lexers
- class Sed < Lexer
- # TODO: add rules for this
- class Regex < TextLexer
- default_option :token, 'Literal.String.Regex'
+ class Sed < RegexLexer
+ desc 'sed, the ultimate stream editor'
+
+ tag 'sed'
+ filenames '*.sed'
+ mimetypes 'text/x-sed'
+
+ def self.analyze_text(text)
+ return 1 if text.shebang? 'sed'
end
- state :root do
+ class Regex < RegexLexer
+ state :root do
+ rule /\\./, 'Literal.String.Escape'
+ rule /\[/, 'Punctuation', :brackets
+ rule /[$^.*]/, 'Operator'
+ rule /[()]/, 'Punctuation'
+ rule /./, 'Literal.String.Regex'
+ end
+
+ state :brackets do
+ rule /\^?/ do
+ token 'Punctuation'
+ pop!; push :brackets_int
+ end
+ end
+
+ state :brackets_int do
+ # ranges
+ rule /.-./, 'Name.Variable'
+ rule /\]/, 'Punctuation', :pop!
+ rule /./, 'Literal.String.Regex'
+ end
+ end
+
+ class Replacement < RegexLexer
+ state :root do
+ rule /\\./m, 'Literal.String.Escape'
+ rule /&/, 'Operator'
+ rule /[^\\&]+/m, 'Text'
+ end
+ end
+
+ def regex
+ @regex ||= Regex.new(options)
+ end
+
+ def replacement
+ @replacement ||= Replacement.new(options)
+ end
+
+ start { regex.reset!; replacement.reset! }
+
+ state :whitespace do
rule /\s+/m, 'Text'
- rule /#.*?\n/, 'Comment'
+ rule(/#.*?\n/) { token 'Comment'; reset_stack }
+ rule(/\n/) { token 'Text'; reset_stack }
+ rule(/;/) { token 'Punctuation'; reset_stack }
+ end
- rule /s(.)(\\.|.*?)(\1)/ do
- token re_tok
- push :flags
- push :subst
- push :regex
+ state :root do
+ mixin :addr_range
+ end
+
+ edot = /\\.|./m
+
+ state :command do
+ mixin :whitespace
+
+ # subst and transliteration
+ rule /(s)(.)(#{edot}*?)(\2)(#{edot}*?)(\2)/m do |m|
+ token 'Keyword', m[1]
+ token 'Punctuation', m[2]
+ delegate regex, m[3]
+ token 'Punctuation', m[4]
+ delegate replacement, m[5]
+ token 'Punctuation', m[6]
+
+
+ pop!; push :flags
end
+
+ rule /(y)(.)(#{edot}*?)(\2)(#{edot}*?)(\2)/m do |m|
+ token 'Keyword', m[1]
+ token 'Punctuation', m[2]
+ delegate replacement, m[3]
+ token 'Punctuation', m[4]
+ delegate replacement, m[5]
+ token 'Punctuation', m[6]
+
+ pop!
+ end
+
+ # commands that take a text segment as an argument
+ rule /([aic])(\s*)/ do
+ group 'Keyword'; group 'Text'; pop!; push :text
+ end
+
+ rule /[pd]/, 'Keyword'
+
+ # commands that take a number argument
+ rule /([qQl])(\s+)(\d+)/i do
+ group 'Keyword'; group 'Text'; group 'Literal.Number'
+ pop!
+ end
+
+ # no-argument commands
+ rule /[={}dDgGhHlnpPqx]/, 'Keyword', :pop!
+
+ # commands that take a filename argument
+ rule /([rRwW])(\s+)(\S+)/ do
+ group 'Keyword'; group 'Text'; group 'Name'
+ pop!
+ end
+
+ # commands that take a label argument
+ rule /([:btT])(\s+)(\S+)/ do
+ group 'Keyword'; group 'Text'; group 'Name.Label'
+ pop!
+ end
+ end
+
+ state :addr_range do
+ mixin :whitespace
+
+ ### address ranges ###
+ addr_tok = 'Keyword.Namespace'
+ rule /\d+/, addr_tok
+ rule /[$,~+!]/, addr_tok
+
+ rule %r((/)(\\.|.)*?(/)) do |m|
+ token addr_tok, m[1]; delegate regex, m[2]; token addr_tok, m[3]
+ end
+
+ # alternate regex rage delimiters
+ rule %r((\\)(.)(\\.|.)*?(\2)) do |m|
+ token addr_tok, m[1] + m[2]
+ delegate regex, m[3]
+ token addr_tok, m[4]
+ end
+
+ rule(//) { push :command }
+ end
+
+ state :text do
+ rule /[^\\\n]+/, 'Literal.String'
+ rule /\\\n/, 'Literal.String.Escape'
+ rule /\\/, 'Literal.String'
+ rule /\n/, 'Text', :pop!
+ end
+
+ state :flags do
+ rule /[gp]+/, 'Keyword', :pop!
+
+ # writing to a file with the subst command.
+ # who'da thunk...?
+ rule /([wW])(\s+)(\S+)/ do
+ token 'Keyword'; token 'Text'; token 'Name'
+ end
+
+ rule(//) { pop! }
end
end
end
end