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
168
169
170
171
172
173
|
# -*- coding: utf-8 -*- #
# frozen_string_literal: true
module Rouge
module Lexers
class Sed < RegexLexer
title "sed"
desc 'sed, the ultimate stream editor'
tag 'sed'
filenames '*.sed'
mimetypes 'text/x-sed'
def self.detect?(text)
return true if text.shebang? 'sed'
end
class Regex < RegexLexer
state :root do
rule %r/\\./, Str::Escape
rule %r/\[/, Punctuation, :brackets
rule %r/[$^.*]/, Operator
rule %r/[()]/, Punctuation
rule %r/./, Str::Regex
end
state :brackets do
rule %r/\^/ do
token Punctuation
goto :brackets_int
end
rule(//) { goto :brackets_int }
end
state :brackets_int do
# ranges
rule %r/.-./, Name::Variable
rule %r/\]/, Punctuation, :pop!
rule %r/./, Str::Regex
end
end
class Replacement < RegexLexer
state :root do
rule %r/\\./m, Str::Escape
rule %r/&/, Operator
rule %r/[^\\&]+/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 %r/\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 %r/(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 %r/(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 %r/([aic])(\s*)/ do
groups Keyword, Text; goto :text
end
rule %r/[pd]/, Keyword
# commands that take a number argument
rule %r/([qQl])(\s+)(\d+)/i do
groups Keyword, Text, Num
pop!
end
# no-argument commands
rule %r/[={}dDgGhHlnpPqx]/, Keyword, :pop!
# commands that take a filename argument
rule %r/([rRwW])(\s+)(\S+)/ do
groups Keyword, Text, Name
pop!
end
# commands that take a label argument
rule %r/([: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 %r/\d+/, addr_tok
rule %r/[$,~+!]/, 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 %r/[^\\\n]+/, Str
rule %r/\\\n/, Str::Escape
rule %r/\\/, Str
rule %r/\n/, Text, :pop!
end
state :flags do
rule %r/[gp]+/, Keyword, :pop!
# writing to a file with the subst command.
# who'da thunk...?
rule %r/([wW])(\s+)(\S+)/ do
token Keyword; token Text; token Name
end
rule(//) { pop! }
end
end
end
end
|