textbringer 24 → 25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/exe/txtb +1 -0
- data/lib/textbringer/buffer.rb +19 -11
- data/lib/textbringer/commands/misc.rb +19 -0
- data/lib/textbringer/commands/windows.rb +14 -0
- data/lib/textbringer/config.rb +2 -1
- data/lib/textbringer/face.rb +71 -15
- data/lib/textbringer/gamegrid.rb +2 -6
- data/lib/textbringer/highlight_context.rb +21 -0
- data/lib/textbringer/mode.rb +25 -0
- data/lib/textbringer/modes/gamegrid_mode.rb +6 -1
- data/lib/textbringer/modes/ruby_mode.rb +298 -181
- data/lib/textbringer/theme.rb +180 -0
- data/lib/textbringer/themes/catppuccin.rb +105 -0
- data/lib/textbringer/themes/github.rb +89 -0
- data/lib/textbringer/themes/gruvbox.rb +84 -0
- data/lib/textbringer/themes/molokai.rb +67 -0
- data/lib/textbringer/themes/sonokai.rb +63 -0
- data/lib/textbringer/themes/tokyonight.rb +70 -0
- data/lib/textbringer/version.rb +1 -1
- data/lib/textbringer/window.rb +28 -41
- data/lib/textbringer.rb +2 -0
- data/textbringer.gemspec +1 -0
- metadata +23 -5
- data/lib/textbringer/faces/basic.rb +0 -8
- data/lib/textbringer/faces/completion.rb +0 -4
- data/lib/textbringer/faces/dired.rb +0 -6
- data/lib/textbringer/faces/programming.rb +0 -6
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
require "
|
|
1
|
+
require "set"
|
|
2
|
+
require "prism"
|
|
2
3
|
|
|
3
4
|
module Textbringer
|
|
4
5
|
CONFIG[:ruby_indent_level] = 2
|
|
@@ -10,81 +11,6 @@ module Textbringer
|
|
|
10
11
|
(?:Gem|Rake|Cap|Thor|Vagrant|Guard|Pod)file)\z/ix
|
|
11
12
|
self.interpreter_name_pattern = /ruby/i
|
|
12
13
|
|
|
13
|
-
define_syntax :comment, /
|
|
14
|
-
(?: \#.*(?:\\\n.*)*(?:\z|(?<!\\)\n) ) |
|
|
15
|
-
(?: ^=begin (?:.|\n)* (?> ^=end \b ) )
|
|
16
|
-
/x
|
|
17
|
-
|
|
18
|
-
define_syntax :keyword, /
|
|
19
|
-
(?<![$@.]) \b (?: (?:
|
|
20
|
-
class | module | def | undef | begin | rescue | ensure | end |
|
|
21
|
-
if | unless | then | elsif | else | case | when | while | until |
|
|
22
|
-
for | break | next | redo | retry | in | do | return | yield |
|
|
23
|
-
super | self | nil | true | false | and | or | not | alias
|
|
24
|
-
) \b (?![!?]) | defined\? )
|
|
25
|
-
/x
|
|
26
|
-
|
|
27
|
-
define_syntax :string, /
|
|
28
|
-
(?: (?<! [a-zA-Z] ) \?
|
|
29
|
-
(:?
|
|
30
|
-
[^\\\s] |
|
|
31
|
-
\\ [0-7]{1,3} |
|
|
32
|
-
\\x [0-9a-fA-F]{2} |
|
|
33
|
-
\\u [0-9a-fA-F]{4} |
|
|
34
|
-
\\u \{ [0-9a-fA-F]+ \} |
|
|
35
|
-
\\C - . |
|
|
36
|
-
\\M - . |
|
|
37
|
-
\\ .
|
|
38
|
-
)
|
|
39
|
-
) |
|
|
40
|
-
(?: %[qQrwWsiIx]?\{ (?: [^\\}] | \\ . )* \} ) |
|
|
41
|
-
(?: %[qQrwWsiIx]?\( (?: [^\\)] | \\ . )* \) ) |
|
|
42
|
-
(?: %[qQrwWsiIx]?\[ (?: [^\\\]] | \\ . )* \] ) |
|
|
43
|
-
(?: %[qQrwWsiIx]?< (?: [^\\>] | \\ . )* > ) |
|
|
44
|
-
(?:
|
|
45
|
-
%[qQrwWsiIx]?
|
|
46
|
-
(?<string_delimiter>[^{(\[<a-zA-Z0-9\s\u{0100}-\u{10ffff}])
|
|
47
|
-
(?: (?! \k<string_delimiter> ) [^\\] | \\ . )*
|
|
48
|
-
\k<string_delimiter>
|
|
49
|
-
) |
|
|
50
|
-
(?:
|
|
51
|
-
(?<! \$ )
|
|
52
|
-
" (?: [^\\"] | \\ . )* "
|
|
53
|
-
) |
|
|
54
|
-
(?:
|
|
55
|
-
(?<! \$ )
|
|
56
|
-
' (?: [^\\'] | \\ . )* '
|
|
57
|
-
) |
|
|
58
|
-
(?:
|
|
59
|
-
(?<! [$.] | def | def \s )
|
|
60
|
-
` (?: [^\\`] | \\ . )* `
|
|
61
|
-
) |
|
|
62
|
-
(?:
|
|
63
|
-
(?<=
|
|
64
|
-
^ |
|
|
65
|
-
\b and | \b or | \b while | \b until | \b unless | \b if |
|
|
66
|
-
\b elsif | \b when | \b not | \b then | \b else |
|
|
67
|
-
[;~=!|&(,\[<>?:*+-]
|
|
68
|
-
) \s*
|
|
69
|
-
\/ (?: [^\\\/] | \\ . )* \/[iomxneus]*
|
|
70
|
-
) |
|
|
71
|
-
(?:
|
|
72
|
-
(?<! class | class \s | [\]})"'.] | :: | \w )
|
|
73
|
-
<<[\-~]?(?<heredoc_quote>['"`]?)
|
|
74
|
-
(?<heredoc_terminator>
|
|
75
|
-
(?> [_a-zA-Z\u{0100}-\u{10ffff}]
|
|
76
|
-
[_a-zA-Z0-9\u{0100}-\u{10ffff}]* )
|
|
77
|
-
)
|
|
78
|
-
\k<heredoc_quote>
|
|
79
|
-
(?> (?:.|\n)*? ^ [\ \t]* \k<heredoc_terminator> $ )
|
|
80
|
-
) |
|
|
81
|
-
(?:
|
|
82
|
-
(?<! : ) :
|
|
83
|
-
[_a-zA-Z\u{0100}-\u{10ffff}]
|
|
84
|
-
[_a-zA-Z0-9\u{0100}-\u{10ffff}]*
|
|
85
|
-
)
|
|
86
|
-
/x
|
|
87
|
-
|
|
88
14
|
def comment_start
|
|
89
15
|
"#"
|
|
90
16
|
end
|
|
@@ -93,17 +19,28 @@ module Textbringer
|
|
|
93
19
|
super(buffer)
|
|
94
20
|
@buffer[:indent_level] = CONFIG[:ruby_indent_level]
|
|
95
21
|
@buffer[:indent_tabs_mode] = CONFIG[:ruby_indent_tabs_mode]
|
|
22
|
+
@prism_version = nil
|
|
23
|
+
@prism_tokens = nil
|
|
24
|
+
@prism_ast = nil
|
|
25
|
+
@prism_method_call_locs = nil
|
|
26
|
+
@literal_levels = nil
|
|
27
|
+
@literal_levels_version = nil
|
|
96
28
|
end
|
|
97
29
|
|
|
98
30
|
def forward_definition(n = number_prefix_arg || 1)
|
|
99
|
-
|
|
31
|
+
ensure_prism_tokens
|
|
32
|
+
tokens = @prism_tokens.filter_map { |token, _state|
|
|
33
|
+
type = token.type
|
|
34
|
+
next if type == :EOF
|
|
35
|
+
[token.location.start_line, type]
|
|
36
|
+
}
|
|
100
37
|
@buffer.forward_line
|
|
101
38
|
n.times do |i|
|
|
102
|
-
tokens = tokens.drop_while { |
|
|
39
|
+
tokens = tokens.drop_while { |l, type|
|
|
103
40
|
l < @buffer.current_line ||
|
|
104
|
-
|
|
41
|
+
!DEFINITION_KEYWORDS.include?(type)
|
|
105
42
|
}
|
|
106
|
-
|
|
43
|
+
line, = tokens.first
|
|
107
44
|
if line.nil?
|
|
108
45
|
@buffer.end_of_buffer
|
|
109
46
|
break
|
|
@@ -117,14 +54,19 @@ module Textbringer
|
|
|
117
54
|
end
|
|
118
55
|
|
|
119
56
|
def backward_definition(n = number_prefix_arg || 1)
|
|
120
|
-
|
|
57
|
+
ensure_prism_tokens
|
|
58
|
+
tokens = @prism_tokens.filter_map { |token, _state|
|
|
59
|
+
type = token.type
|
|
60
|
+
next if type == :EOF
|
|
61
|
+
[token.location.start_line, type]
|
|
62
|
+
}.reverse
|
|
121
63
|
@buffer.beginning_of_line
|
|
122
64
|
n.times do |i|
|
|
123
|
-
tokens = tokens.drop_while { |
|
|
65
|
+
tokens = tokens.drop_while { |l, type|
|
|
124
66
|
l >= @buffer.current_line ||
|
|
125
|
-
|
|
67
|
+
!DEFINITION_KEYWORDS.include?(type)
|
|
126
68
|
}
|
|
127
|
-
|
|
69
|
+
line, = tokens.first
|
|
128
70
|
if line.nil?
|
|
129
71
|
@buffer.beginning_of_buffer
|
|
130
72
|
break
|
|
@@ -175,8 +117,171 @@ module Textbringer
|
|
|
175
117
|
end
|
|
176
118
|
end
|
|
177
119
|
|
|
120
|
+
def highlight(ctx)
|
|
121
|
+
ensure_prism_tokens
|
|
122
|
+
return unless @prism_tokens
|
|
123
|
+
ensure_method_call_locs
|
|
124
|
+
base_pos = ctx.buffer.point_min
|
|
125
|
+
hl_start = ctx.highlight_start
|
|
126
|
+
hl_end = ctx.highlight_end
|
|
127
|
+
in_symbol = false
|
|
128
|
+
after_def = false
|
|
129
|
+
after_class_or_module = false
|
|
130
|
+
@prism_tokens.each do |token_info|
|
|
131
|
+
token = token_info[0]
|
|
132
|
+
type = token.type
|
|
133
|
+
offset = token.location.start_offset
|
|
134
|
+
length = token.location.length
|
|
135
|
+
pos = base_pos + offset
|
|
136
|
+
pos_end = pos + length
|
|
137
|
+
break if pos >= hl_end
|
|
138
|
+
if pos_end > hl_start
|
|
139
|
+
face_name = PRISM_TOKEN_FACES[type]
|
|
140
|
+
if in_symbol
|
|
141
|
+
face_name = :string if face_name.nil? || face_name == :constant ||
|
|
142
|
+
face_name == :operator
|
|
143
|
+
elsif after_def
|
|
144
|
+
face_name = :function_name if type == :IDENTIFIER ||
|
|
145
|
+
type == :CONSTANT || type == :METHOD_NAME ||
|
|
146
|
+
PRISM_TOKEN_FACES[type] == :operator
|
|
147
|
+
elsif face_name == :constant &&
|
|
148
|
+
(after_class_or_module || token.location.slice.match?(/\p{Lower}/))
|
|
149
|
+
face_name = :type
|
|
150
|
+
elsif @prism_method_call_locs.key?(offset)
|
|
151
|
+
face_name = :function_name
|
|
152
|
+
end
|
|
153
|
+
if face_name && (face = Face[face_name])
|
|
154
|
+
ctx.highlight(pos, pos_end, face)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
in_symbol = type == :SYMBOL_BEGIN
|
|
158
|
+
after_def = type == :KEYWORD_DEF ||
|
|
159
|
+
(after_def && (type == :KEYWORD_SELF || type == :DOT ||
|
|
160
|
+
type == :NEWLINE || type == :IGNORED_NEWLINE ||
|
|
161
|
+
type == :COMMENT))
|
|
162
|
+
after_class_or_module = (type == :KEYWORD_CLASS || type == :KEYWORD_MODULE) ||
|
|
163
|
+
(after_class_or_module && !(type == :NEWLINE || type == :SEMICOLON))
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
178
167
|
private
|
|
179
168
|
|
|
169
|
+
PRISM_TOKEN_FACES = {
|
|
170
|
+
# Keywords
|
|
171
|
+
KEYWORD_ALIAS: :keyword, KEYWORD_AND: :keyword, KEYWORD_BEGIN: :keyword,
|
|
172
|
+
KEYWORD_BEGIN_UPCASE: :keyword, KEYWORD_BREAK: :keyword,
|
|
173
|
+
KEYWORD_CASE: :keyword, KEYWORD_CLASS: :keyword, KEYWORD_DEF: :keyword,
|
|
174
|
+
KEYWORD_DEFINED: :keyword, KEYWORD_DO: :keyword,
|
|
175
|
+
KEYWORD_DO_LOOP: :keyword, KEYWORD_ELSE: :keyword,
|
|
176
|
+
KEYWORD_ELSIF: :keyword, KEYWORD_END: :keyword,
|
|
177
|
+
KEYWORD_END_UPCASE: :keyword, KEYWORD_ENSURE: :keyword,
|
|
178
|
+
KEYWORD_FALSE: :builtin, KEYWORD_FOR: :keyword, KEYWORD_IF: :keyword,
|
|
179
|
+
KEYWORD_IF_MODIFIER: :keyword, KEYWORD_IN: :keyword,
|
|
180
|
+
KEYWORD_MODULE: :keyword, KEYWORD_NEXT: :keyword,
|
|
181
|
+
KEYWORD_NIL: :builtin,
|
|
182
|
+
KEYWORD_NOT: :keyword, KEYWORD_OR: :keyword, KEYWORD_REDO: :keyword,
|
|
183
|
+
KEYWORD_RESCUE: :keyword, KEYWORD_RESCUE_MODIFIER: :keyword,
|
|
184
|
+
KEYWORD_RETRY: :keyword, KEYWORD_RETURN: :keyword,
|
|
185
|
+
KEYWORD_SELF: :builtin, KEYWORD_SUPER: :builtin,
|
|
186
|
+
KEYWORD_THEN: :keyword, KEYWORD_TRUE: :builtin,
|
|
187
|
+
KEYWORD_UNDEF: :keyword,
|
|
188
|
+
KEYWORD_UNLESS: :keyword, KEYWORD_UNLESS_MODIFIER: :keyword,
|
|
189
|
+
KEYWORD_UNTIL: :keyword, KEYWORD_UNTIL_MODIFIER: :keyword,
|
|
190
|
+
KEYWORD_WHEN: :keyword, KEYWORD_WHILE: :keyword,
|
|
191
|
+
KEYWORD_WHILE_MODIFIER: :keyword, KEYWORD_YIELD: :keyword,
|
|
192
|
+
KEYWORD___FILE__: :builtin, KEYWORD___LINE__: :builtin,
|
|
193
|
+
KEYWORD___ENCODING__: :builtin,
|
|
194
|
+
|
|
195
|
+
# Comments
|
|
196
|
+
COMMENT: :comment, EMBDOC_BEGIN: :comment, EMBDOC_LINE: :comment,
|
|
197
|
+
EMBDOC_END: :comment,
|
|
198
|
+
|
|
199
|
+
# Strings and string-like
|
|
200
|
+
STRING_BEGIN: :string, STRING_CONTENT: :string, STRING_END: :string,
|
|
201
|
+
SYMBOL_BEGIN: :string, REGEXP_BEGIN: :string, REGEXP_END: :string,
|
|
202
|
+
HEREDOC_START: :string, HEREDOC_END: :string,
|
|
203
|
+
LABEL: :property,
|
|
204
|
+
|
|
205
|
+
# Numbers
|
|
206
|
+
INTEGER: :number, FLOAT: :number,
|
|
207
|
+
INTEGER_RATIONAL: :number, FLOAT_RATIONAL: :number,
|
|
208
|
+
INTEGER_IMAGINARY: :number, FLOAT_IMAGINARY: :number,
|
|
209
|
+
INTEGER_RATIONAL_IMAGINARY: :number, FLOAT_RATIONAL_IMAGINARY: :number,
|
|
210
|
+
|
|
211
|
+
# Constants
|
|
212
|
+
CONSTANT: :constant,
|
|
213
|
+
|
|
214
|
+
# Variables
|
|
215
|
+
INSTANCE_VARIABLE: :variable, CLASS_VARIABLE: :variable,
|
|
216
|
+
GLOBAL_VARIABLE: :variable,
|
|
217
|
+
|
|
218
|
+
# Operators
|
|
219
|
+
PLUS: :operator, MINUS: :operator, STAR: :operator, SLASH: :operator,
|
|
220
|
+
PERCENT: :operator, STAR_STAR: :operator,
|
|
221
|
+
EQUAL: :operator, EQUAL_EQUAL: :operator, BANG_EQUAL: :operator,
|
|
222
|
+
LESS: :operator, GREATER: :operator,
|
|
223
|
+
LESS_EQUAL: :operator, GREATER_EQUAL: :operator,
|
|
224
|
+
LESS_EQUAL_GREATER: :operator, EQUAL_EQUAL_EQUAL: :operator,
|
|
225
|
+
EQUAL_TILDE: :operator, BANG_TILDE: :operator,
|
|
226
|
+
AMPERSAND_AMPERSAND: :operator, PIPE_PIPE: :operator,
|
|
227
|
+
BANG: :operator, TILDE: :operator,
|
|
228
|
+
LESS_LESS: :operator, GREATER_GREATER: :operator,
|
|
229
|
+
AMPERSAND: :operator, PIPE: :operator, CARET: :operator,
|
|
230
|
+
PLUS_EQUAL: :operator, MINUS_EQUAL: :operator,
|
|
231
|
+
STAR_EQUAL: :operator, SLASH_EQUAL: :operator,
|
|
232
|
+
PERCENT_EQUAL: :operator, STAR_STAR_EQUAL: :operator,
|
|
233
|
+
AMPERSAND_EQUAL: :operator, PIPE_EQUAL: :operator,
|
|
234
|
+
CARET_EQUAL: :operator,
|
|
235
|
+
AMPERSAND_AMPERSAND_EQUAL: :operator, PIPE_PIPE_EQUAL: :operator,
|
|
236
|
+
LESS_LESS_EQUAL: :operator, GREATER_GREATER_EQUAL: :operator,
|
|
237
|
+
DOT_DOT: :operator, DOT_DOT_DOT: :operator,
|
|
238
|
+
EQUAL_GREATER: :operator, UMINUS: :operator, UPLUS: :operator,
|
|
239
|
+
USTAR: :operator, USTAR_STAR: :operator, UAMPERSAND: :operator,
|
|
240
|
+
|
|
241
|
+
# Punctuation
|
|
242
|
+
DOT: :punctuation, COLON_COLON: :punctuation,
|
|
243
|
+
SEMICOLON: :punctuation, COMMA: :punctuation,
|
|
244
|
+
PARENTHESIS_LEFT: :punctuation, PARENTHESIS_RIGHT: :punctuation,
|
|
245
|
+
BRACKET_LEFT: :punctuation, BRACKET_LEFT_ARRAY: :punctuation,
|
|
246
|
+
BRACKET_RIGHT: :punctuation,
|
|
247
|
+
BRACE_LEFT: :punctuation, BRACE_RIGHT: :punctuation,
|
|
248
|
+
QUESTION_MARK: :punctuation, COLON: :punctuation,
|
|
249
|
+
LAMBDA_BEGIN: :punctuation,
|
|
250
|
+
|
|
251
|
+
# Method names (e.g. block_given?, is_a?)
|
|
252
|
+
METHOD_NAME: :function_name,
|
|
253
|
+
}.freeze
|
|
254
|
+
|
|
255
|
+
DEFINITION_KEYWORDS = %i[KEYWORD_CLASS KEYWORD_MODULE KEYWORD_DEF].to_set
|
|
256
|
+
|
|
257
|
+
LITERAL_BEGIN_TYPES = %i[STRING_BEGIN HEREDOC_START REGEXP_BEGIN EMBDOC_BEGIN].to_set
|
|
258
|
+
LITERAL_END_TYPES = %i[STRING_END HEREDOC_END REGEXP_END EMBDOC_END].to_set
|
|
259
|
+
|
|
260
|
+
CONTINUATION_OPERATOR_TYPES = %i[
|
|
261
|
+
PLUS MINUS STAR SLASH PERCENT STAR_STAR
|
|
262
|
+
EQUAL EQUAL_EQUAL BANG_EQUAL
|
|
263
|
+
LESS GREATER LESS_EQUAL GREATER_EQUAL LESS_EQUAL_GREATER
|
|
264
|
+
EQUAL_TILDE BANG_TILDE
|
|
265
|
+
AMPERSAND_AMPERSAND PIPE_PIPE
|
|
266
|
+
BANG TILDE
|
|
267
|
+
LESS_LESS GREATER_GREATER
|
|
268
|
+
AMPERSAND CARET
|
|
269
|
+
PLUS_EQUAL MINUS_EQUAL STAR_EQUAL SLASH_EQUAL PERCENT_EQUAL
|
|
270
|
+
STAR_STAR_EQUAL AMPERSAND_EQUAL PIPE_EQUAL CARET_EQUAL
|
|
271
|
+
AMPERSAND_AMPERSAND_EQUAL PIPE_PIPE_EQUAL
|
|
272
|
+
LESS_LESS_EQUAL GREATER_GREATER_EQUAL
|
|
273
|
+
EQUAL_GREATER
|
|
274
|
+
].to_set
|
|
275
|
+
|
|
276
|
+
BLOCK_END = {
|
|
277
|
+
EMBEXPR_BEGIN: :EMBEXPR_END,
|
|
278
|
+
BRACE_LEFT: :BRACE_RIGHT,
|
|
279
|
+
PARENTHESIS_LEFT: :PARENTHESIS_RIGHT,
|
|
280
|
+
BRACKET_LEFT: :BRACKET_RIGHT,
|
|
281
|
+
BRACKET_LEFT_ARRAY: :BRACKET_RIGHT,
|
|
282
|
+
LAMBDA_BEGIN: :BRACE_RIGHT,
|
|
283
|
+
}
|
|
284
|
+
|
|
180
285
|
INDENT_BEG_RE = /^([ \t]*)(class|module|def|if|unless|case|while|until|for|begin)\b/
|
|
181
286
|
|
|
182
287
|
def space_width(s)
|
|
@@ -187,8 +292,7 @@ module Textbringer
|
|
|
187
292
|
loop do
|
|
188
293
|
@buffer.re_search_backward(INDENT_BEG_RE)
|
|
189
294
|
space = @buffer.match_string(1)
|
|
190
|
-
|
|
191
|
-
if PartialLiteralAnalyzer.in_literal?(s)
|
|
295
|
+
if in_literal?(@buffer.point)
|
|
192
296
|
next
|
|
193
297
|
end
|
|
194
298
|
return space_width(space)
|
|
@@ -199,19 +303,12 @@ module Textbringer
|
|
|
199
303
|
end
|
|
200
304
|
|
|
201
305
|
def lex(source)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
tokens.concat(lexer.lex)
|
|
209
|
-
last_line = tokens.dig(-1, 0, 0)
|
|
210
|
-
return tokens if last_line.nil? || last_line >= line_count
|
|
211
|
-
s = source.sub(/(.*\n?){#{last_line}}/, "")
|
|
212
|
-
return tokens if last_line + 1 <= lineno
|
|
213
|
-
lineno = last_line + 1
|
|
214
|
-
end
|
|
306
|
+
Prism.lex(source).value.filter_map { |token, _state|
|
|
307
|
+
type = token.type
|
|
308
|
+
next if type == :EOF
|
|
309
|
+
loc = token.location
|
|
310
|
+
[[loc.start_line, loc.start_column], type, token.value]
|
|
311
|
+
}
|
|
215
312
|
end
|
|
216
313
|
|
|
217
314
|
def calculate_indentation
|
|
@@ -227,19 +324,20 @@ module Textbringer
|
|
|
227
324
|
start_line = @buffer.current_line
|
|
228
325
|
tokens = lex(@buffer.substring(start_pos, bol_pos))
|
|
229
326
|
_, event, text = tokens.last
|
|
230
|
-
if event == :
|
|
327
|
+
if event == :NEWLINE || event == :IGNORED_NEWLINE
|
|
231
328
|
_, event, text = tokens[-2]
|
|
232
329
|
end
|
|
233
|
-
if event == :
|
|
234
|
-
event == :
|
|
235
|
-
event == :
|
|
236
|
-
|
|
237
|
-
event == :
|
|
330
|
+
if event == :STRING_BEGIN ||
|
|
331
|
+
event == :HEREDOC_START ||
|
|
332
|
+
(event == :HEREDOC_END && text.empty?) ||
|
|
333
|
+
event == :REGEXP_BEGIN ||
|
|
334
|
+
event == :STRING_CONTENT ||
|
|
335
|
+
event == :HEREDOC_CONTENT
|
|
238
336
|
return nil
|
|
239
337
|
end
|
|
240
338
|
i, extra_end_count = find_nearest_beginning_token(tokens)
|
|
241
339
|
(line, column), event, = i ? tokens[i] : nil
|
|
242
|
-
if event == :
|
|
340
|
+
if event == :PARENTHESIS_LEFT && tokens.dig(i + 1, 1) != :IGNORED_NEWLINE
|
|
243
341
|
return column + 1
|
|
244
342
|
end
|
|
245
343
|
if line
|
|
@@ -268,101 +366,87 @@ module Textbringer
|
|
|
268
366
|
if @buffer.looking_at?(/[ \t]*([}\])]|(end|else|elsif|when|in|rescue|ensure)\b)/)
|
|
269
367
|
indentation -= @buffer[:indent_level]
|
|
270
368
|
end
|
|
271
|
-
_, last_event,
|
|
272
|
-
e != :
|
|
369
|
+
_, last_event, = tokens.reverse_each.find { |_, e, _|
|
|
370
|
+
e != :NEWLINE && e != :IGNORED_NEWLINE
|
|
273
371
|
}
|
|
274
372
|
if start_with_period ||
|
|
275
|
-
(last_event
|
|
276
|
-
|
|
277
|
-
last_event == :
|
|
278
|
-
(last_event == :
|
|
279
|
-
event != :
|
|
280
|
-
|
|
373
|
+
CONTINUATION_OPERATOR_TYPES.include?(last_event) ||
|
|
374
|
+
last_event == :KEYWORD_AND || last_event == :KEYWORD_OR ||
|
|
375
|
+
last_event == :DOT ||
|
|
376
|
+
(last_event == :COMMA && event != :BRACE_LEFT &&
|
|
377
|
+
event != :PARENTHESIS_LEFT && event != :BRACKET_LEFT &&
|
|
378
|
+
event != :BRACKET_LEFT_ARRAY) ||
|
|
379
|
+
last_event == :LABEL
|
|
281
380
|
indentation += @buffer[:indent_level]
|
|
282
381
|
end
|
|
283
382
|
indentation
|
|
284
383
|
end
|
|
285
384
|
end
|
|
286
385
|
|
|
287
|
-
BLOCK_END = {
|
|
288
|
-
'#{' => "}",
|
|
289
|
-
"{" => "}",
|
|
290
|
-
"(" => ")",
|
|
291
|
-
"[" => "]"
|
|
292
|
-
}
|
|
293
|
-
|
|
294
386
|
def find_nearest_beginning_token(tokens)
|
|
295
387
|
stack = []
|
|
296
388
|
(tokens.size - 1).downto(0) do |i|
|
|
297
389
|
(line, ), event, text = tokens[i]
|
|
298
390
|
case event
|
|
299
|
-
when :
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
if text == "def" && endless_method_def?(tokens, i)
|
|
310
|
-
next
|
|
311
|
-
end
|
|
312
|
-
if stack.empty?
|
|
313
|
-
return i
|
|
314
|
-
end
|
|
315
|
-
if stack.last != "end"
|
|
316
|
-
raise EditorError, "#{@buffer.name}:#{line}: Unmatched #{text}"
|
|
317
|
-
end
|
|
318
|
-
stack.pop
|
|
319
|
-
when "end"
|
|
320
|
-
stack.push(text)
|
|
391
|
+
when :KEYWORD_CLASS, :KEYWORD_MODULE, :KEYWORD_DEF,
|
|
392
|
+
:KEYWORD_IF, :KEYWORD_UNLESS, :KEYWORD_CASE,
|
|
393
|
+
:KEYWORD_DO, :KEYWORD_DO_LOOP, :KEYWORD_FOR,
|
|
394
|
+
:KEYWORD_WHILE, :KEYWORD_UNTIL, :KEYWORD_BEGIN
|
|
395
|
+
if i > 0
|
|
396
|
+
_, prev_event, _ = tokens[i - 1]
|
|
397
|
+
next if prev_event == :SYMBOL_BEGIN
|
|
398
|
+
end
|
|
399
|
+
if event == :KEYWORD_DEF && endless_method_def?(tokens, i)
|
|
400
|
+
next
|
|
321
401
|
end
|
|
322
|
-
when :on_rbrace, :on_rparen, :on_rbracket, :on_embexpr_end
|
|
323
|
-
stack.push(text)
|
|
324
|
-
when :on_lbrace, :on_lparen, :on_lbracket, :on_tlambeg, :on_embexpr_beg
|
|
325
402
|
if stack.empty?
|
|
326
403
|
return i
|
|
327
404
|
end
|
|
328
|
-
if stack.last !=
|
|
405
|
+
if stack.last != :KEYWORD_END
|
|
406
|
+
raise EditorError, "#{@buffer.name}:#{line}: Unmatched #{text}"
|
|
407
|
+
end
|
|
408
|
+
stack.pop
|
|
409
|
+
when :KEYWORD_END
|
|
410
|
+
if i > 0
|
|
411
|
+
_, prev_event, _ = tokens[i - 1]
|
|
412
|
+
next if prev_event == :SYMBOL_BEGIN
|
|
413
|
+
end
|
|
414
|
+
stack.push(:KEYWORD_END)
|
|
415
|
+
when :BRACE_RIGHT, :PARENTHESIS_RIGHT, :BRACKET_RIGHT, :EMBEXPR_END
|
|
416
|
+
stack.push(event)
|
|
417
|
+
when :BRACE_LEFT, :PARENTHESIS_LEFT, :BRACKET_LEFT,
|
|
418
|
+
:BRACKET_LEFT_ARRAY, :LAMBDA_BEGIN, :EMBEXPR_BEGIN
|
|
419
|
+
if stack.empty?
|
|
420
|
+
return i
|
|
421
|
+
end
|
|
422
|
+
if stack.last != BLOCK_END[event]
|
|
329
423
|
raise EditorError, "#{@buffer.name}:#{line}: Unmatched #{text}"
|
|
330
424
|
end
|
|
331
425
|
stack.pop
|
|
332
426
|
end
|
|
333
427
|
end
|
|
334
|
-
return nil, stack.
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
def modifier?(tokens, i)
|
|
338
|
-
(line,), = tokens[i]
|
|
339
|
-
ts = tokens[0...i].reverse_each.take_while { |(l,_),| l == line }
|
|
340
|
-
t = ts.find { |_, e| e != :on_sp }
|
|
341
|
-
t && !(t[1] == :on_op && t[2] == "=")
|
|
428
|
+
return nil, stack.count { |t| t != :PARENTHESIS_RIGHT && t != :BRACKET_RIGHT }
|
|
342
429
|
end
|
|
343
430
|
|
|
344
431
|
def endless_method_def?(tokens, i)
|
|
345
432
|
ts = tokens.drop(i + 1)
|
|
346
|
-
ts.shift while ts[0][1] == :on_sp
|
|
347
433
|
_, event = ts.shift
|
|
348
|
-
return false if event != :
|
|
349
|
-
|
|
350
|
-
if ts[0][1] == :on_lparen
|
|
434
|
+
return false if event != :IDENTIFIER && event != :METHOD_NAME
|
|
435
|
+
if ts[0][1] == :PARENTHESIS_LEFT
|
|
351
436
|
ts.shift
|
|
352
437
|
count = 1
|
|
353
438
|
while count > 0
|
|
354
439
|
_, event = ts.shift
|
|
355
440
|
return false if event.nil?
|
|
356
441
|
case event
|
|
357
|
-
when :
|
|
358
|
-
count +=1
|
|
359
|
-
when :
|
|
360
|
-
count -=1
|
|
442
|
+
when :PARENTHESIS_LEFT
|
|
443
|
+
count += 1
|
|
444
|
+
when :PARENTHESIS_RIGHT
|
|
445
|
+
count -= 1
|
|
361
446
|
end
|
|
362
447
|
end
|
|
363
|
-
ts.shift while ts[0][1] == :on_sp
|
|
364
448
|
end
|
|
365
|
-
ts[0][1] == :
|
|
449
|
+
ts[0][1] == :EQUAL
|
|
366
450
|
rescue NoMethodError # no token
|
|
367
451
|
return false
|
|
368
452
|
end
|
|
@@ -395,31 +479,64 @@ module Textbringer
|
|
|
395
479
|
nil
|
|
396
480
|
end
|
|
397
481
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
482
|
+
def in_literal?(byte_offset)
|
|
483
|
+
ensure_prism_tokens
|
|
484
|
+
ensure_literal_levels
|
|
485
|
+
return false if @literal_levels.empty?
|
|
486
|
+
i = @literal_levels.bsearch_index { |offset, _| offset > byte_offset }
|
|
487
|
+
i = i ? i - 1 : @literal_levels.size - 1
|
|
488
|
+
return false if i < 0
|
|
489
|
+
@literal_levels[i][1] > 0
|
|
490
|
+
end
|
|
402
491
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
492
|
+
def ensure_prism_tokens
|
|
493
|
+
return if @prism_version == @buffer.version
|
|
494
|
+
source = @buffer.to_s
|
|
495
|
+
if source.valid_encoding?
|
|
496
|
+
result = Prism.parse_lex(source)
|
|
497
|
+
@prism_ast, @prism_tokens = result.value
|
|
498
|
+
else
|
|
499
|
+
@prism_ast = nil
|
|
500
|
+
@prism_tokens = []
|
|
407
501
|
end
|
|
502
|
+
@prism_method_call_locs = nil
|
|
503
|
+
@prism_version = @buffer.version
|
|
504
|
+
@literal_levels_version = nil
|
|
505
|
+
end
|
|
408
506
|
|
|
409
|
-
|
|
507
|
+
def ensure_method_call_locs
|
|
508
|
+
return if @prism_method_call_locs
|
|
509
|
+
@prism_method_call_locs = {}
|
|
510
|
+
return unless @prism_ast
|
|
511
|
+
collect_method_call_locs(@prism_ast)
|
|
512
|
+
end
|
|
410
513
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
514
|
+
def collect_method_call_locs(node)
|
|
515
|
+
if node.is_a?(Prism::CallNode) && node.message_loc
|
|
516
|
+
name_str = node.name.to_s
|
|
517
|
+
unless name_str.match?(/\A[^a-zA-Z_]/) || name_str.end_with?("@")
|
|
518
|
+
loc = node.message_loc
|
|
519
|
+
@prism_method_call_locs[loc.start_offset] = true
|
|
415
520
|
end
|
|
416
521
|
end
|
|
522
|
+
node.compact_child_nodes.each { |child| collect_method_call_locs(child) }
|
|
523
|
+
end
|
|
417
524
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
525
|
+
def ensure_literal_levels
|
|
526
|
+
return if @literal_levels_version == @prism_version
|
|
527
|
+
level = 0
|
|
528
|
+
@literal_levels = []
|
|
529
|
+
@prism_tokens&.each do |token, _state|
|
|
530
|
+
type = token.type
|
|
531
|
+
if LITERAL_BEGIN_TYPES.include?(type)
|
|
532
|
+
level += 1
|
|
533
|
+
elsif LITERAL_END_TYPES.include?(type)
|
|
534
|
+
next if type == :HEREDOC_END && token.value.empty?
|
|
535
|
+
level -= 1
|
|
421
536
|
end
|
|
537
|
+
@literal_levels << [token.location.start_offset, level]
|
|
422
538
|
end
|
|
539
|
+
@literal_levels_version = @prism_version
|
|
423
540
|
end
|
|
424
541
|
end
|
|
425
542
|
end
|