1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
module Rugments
module Lexers
class Sed < RegexLexer
title 'sed'
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
class Regex < RegexLexer
state :root do
rule /\\./, Str::Escape
rule /\[/, Punctuation, :brackets
rule /[$^.*]/, Operator
rule /[()]/, Punctuation
rule /./, Str::Regex
end
state :brackets do
rule /\^?/ do
token Punctuation
goto :brackets_int
end
end
state :brackets_int do
# ranges
rule /.-./, Name::Variable
rule /\]/, Punctuation, :pop!
rule /./, Str::Regex
end
end
class Replacement < RegexLexer
state :root do
rule /\\./m, Str::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/) { token Comment; reset_stack }
rule(/\n/) { token Text; reset_stack }
rule(/;/) { token Punctuation; reset_stack }
end
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]
goto :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
groups Keyword, Text; goto :text
end
rule /[pd]/, Keyword
# commands that take a number argument
rule /([qQl])(\s+)(\d+)/i do
groups Keyword, Text, Num
pop!
end
# no-argument commands
rule /[={}dDgGhHlnpPqx]/, Keyword, :pop!
# commands that take a filename argument
rule /([rRwW])(\s+)(\S+)/ do
groups Keyword, Text, Name
pop!
end
# commands that take a label argument
rule /([:btT])(\s+)(\S+)/ do
groups Keyword, Text, 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]+/, Str
rule /\\\n/, Str::Escape
rule /\\/, Str
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
|