textbringer 24 → 26
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/README.ja.md +24 -0
- data/README.md +24 -0
- data/exe/txtb +1 -0
- data/lib/textbringer/buffer.rb +19 -11
- data/lib/textbringer/color.rb +46 -0
- data/lib/textbringer/commands/misc.rb +57 -36
- 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/input_methods/skk_input_method.rb +1 -1
- data/lib/textbringer/mode.rb +25 -0
- data/lib/textbringer/modes/dired_mode.rb +0 -1
- data/lib/textbringer/modes/gamegrid_mode.rb +6 -1
- data/lib/textbringer/modes/ruby_mode.rb +307 -182
- data/lib/textbringer/theme.rb +180 -0
- data/lib/textbringer/themes/catppuccin.rb +106 -0
- data/lib/textbringer/themes/github.rb +86 -0
- data/lib/textbringer/themes/gruvbox.rb +85 -0
- data/lib/textbringer/themes/molokai.rb +65 -0
- data/lib/textbringer/themes/sonokai.rb +67 -0
- data/lib/textbringer/themes/tokyonight.rb +70 -0
- data/lib/textbringer/utils.rb +16 -0
- data/lib/textbringer/version.rb +1 -1
- data/lib/textbringer/window.rb +28 -41
- data/lib/textbringer.rb +2 -0
- data/screenshot.png +0 -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,23 @@ 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_name_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
|
-
tokens =
|
|
31
|
+
tokens = filter_prism_tokens_line_and_type
|
|
100
32
|
@buffer.forward_line
|
|
101
33
|
n.times do |i|
|
|
102
|
-
tokens = tokens.drop_while { |
|
|
34
|
+
tokens = tokens.drop_while { |l, type|
|
|
103
35
|
l < @buffer.current_line ||
|
|
104
|
-
|
|
36
|
+
!DEFINITION_KEYWORDS.include?(type)
|
|
105
37
|
}
|
|
106
|
-
|
|
38
|
+
line, = tokens.first
|
|
107
39
|
if line.nil?
|
|
108
40
|
@buffer.end_of_buffer
|
|
109
41
|
break
|
|
@@ -117,14 +49,14 @@ module Textbringer
|
|
|
117
49
|
end
|
|
118
50
|
|
|
119
51
|
def backward_definition(n = number_prefix_arg || 1)
|
|
120
|
-
tokens =
|
|
52
|
+
tokens = filter_prism_tokens_line_and_type.reverse
|
|
121
53
|
@buffer.beginning_of_line
|
|
122
54
|
n.times do |i|
|
|
123
|
-
tokens = tokens.drop_while { |
|
|
55
|
+
tokens = tokens.drop_while { |l, type|
|
|
124
56
|
l >= @buffer.current_line ||
|
|
125
|
-
|
|
57
|
+
!DEFINITION_KEYWORDS.include?(type)
|
|
126
58
|
}
|
|
127
|
-
|
|
59
|
+
line, = tokens.first
|
|
128
60
|
if line.nil?
|
|
129
61
|
@buffer.beginning_of_buffer
|
|
130
62
|
break
|
|
@@ -175,8 +107,167 @@ module Textbringer
|
|
|
175
107
|
end
|
|
176
108
|
end
|
|
177
109
|
|
|
110
|
+
def highlight(ctx)
|
|
111
|
+
ensure_prism_tokens
|
|
112
|
+
return unless @prism_tokens
|
|
113
|
+
ensure_method_name_locs
|
|
114
|
+
base_pos = ctx.buffer.point_min
|
|
115
|
+
hl_start = ctx.highlight_start
|
|
116
|
+
hl_end = ctx.highlight_end
|
|
117
|
+
in_symbol = false
|
|
118
|
+
after_class_or_module = false
|
|
119
|
+
@prism_tokens.each do |token_info|
|
|
120
|
+
token = token_info[0]
|
|
121
|
+
type = token.type
|
|
122
|
+
offset = token.location.start_offset
|
|
123
|
+
length = token.location.length
|
|
124
|
+
pos = base_pos + offset
|
|
125
|
+
pos_end = pos + length
|
|
126
|
+
break if pos >= hl_end
|
|
127
|
+
if pos_end > hl_start
|
|
128
|
+
face_name = PRISM_TOKEN_FACES[type]
|
|
129
|
+
if in_symbol
|
|
130
|
+
face_name = :string if face_name.nil? || face_name == :constant ||
|
|
131
|
+
face_name == :keyword || face_name == :operator
|
|
132
|
+
elsif @prism_method_name_locs.key?(offset)
|
|
133
|
+
face_name = :function_name
|
|
134
|
+
elsif face_name == :constant &&
|
|
135
|
+
(after_class_or_module || token.location.slice.match?(/\p{Lower}/))
|
|
136
|
+
face_name = :type
|
|
137
|
+
end
|
|
138
|
+
if face_name && (face = Face[face_name])
|
|
139
|
+
ctx.highlight(pos, pos_end, face)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
in_symbol = type == :SYMBOL_BEGIN
|
|
143
|
+
after_class_or_module = (type == :KEYWORD_CLASS || type == :KEYWORD_MODULE) ||
|
|
144
|
+
(after_class_or_module && !(type == :NEWLINE || type == :SEMICOLON))
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
178
148
|
private
|
|
179
149
|
|
|
150
|
+
PRISM_TOKEN_FACES = {
|
|
151
|
+
# Keywords
|
|
152
|
+
KEYWORD_ALIAS: :keyword, KEYWORD_AND: :keyword, KEYWORD_BEGIN: :keyword,
|
|
153
|
+
KEYWORD_BEGIN_UPCASE: :keyword, KEYWORD_BREAK: :keyword,
|
|
154
|
+
KEYWORD_CASE: :keyword, KEYWORD_CLASS: :keyword, KEYWORD_DEF: :keyword,
|
|
155
|
+
KEYWORD_DEFINED: :keyword, KEYWORD_DO: :keyword,
|
|
156
|
+
KEYWORD_DO_LOOP: :keyword, KEYWORD_ELSE: :keyword,
|
|
157
|
+
KEYWORD_ELSIF: :keyword, KEYWORD_END: :keyword,
|
|
158
|
+
KEYWORD_END_UPCASE: :keyword, KEYWORD_ENSURE: :keyword,
|
|
159
|
+
KEYWORD_FALSE: :builtin, KEYWORD_FOR: :keyword, KEYWORD_IF: :keyword,
|
|
160
|
+
KEYWORD_IF_MODIFIER: :keyword, KEYWORD_IN: :keyword,
|
|
161
|
+
KEYWORD_MODULE: :keyword, KEYWORD_NEXT: :keyword,
|
|
162
|
+
KEYWORD_NIL: :builtin,
|
|
163
|
+
KEYWORD_NOT: :keyword, KEYWORD_OR: :keyword, KEYWORD_REDO: :keyword,
|
|
164
|
+
KEYWORD_RESCUE: :keyword, KEYWORD_RESCUE_MODIFIER: :keyword,
|
|
165
|
+
KEYWORD_RETRY: :keyword, KEYWORD_RETURN: :keyword,
|
|
166
|
+
KEYWORD_SELF: :builtin, KEYWORD_SUPER: :builtin,
|
|
167
|
+
KEYWORD_THEN: :keyword, KEYWORD_TRUE: :builtin,
|
|
168
|
+
KEYWORD_UNDEF: :keyword,
|
|
169
|
+
KEYWORD_UNLESS: :keyword, KEYWORD_UNLESS_MODIFIER: :keyword,
|
|
170
|
+
KEYWORD_UNTIL: :keyword, KEYWORD_UNTIL_MODIFIER: :keyword,
|
|
171
|
+
KEYWORD_WHEN: :keyword, KEYWORD_WHILE: :keyword,
|
|
172
|
+
KEYWORD_WHILE_MODIFIER: :keyword, KEYWORD_YIELD: :keyword,
|
|
173
|
+
KEYWORD___FILE__: :builtin, KEYWORD___LINE__: :builtin,
|
|
174
|
+
KEYWORD___ENCODING__: :builtin,
|
|
175
|
+
|
|
176
|
+
# Comments
|
|
177
|
+
COMMENT: :comment, EMBDOC_BEGIN: :comment, EMBDOC_LINE: :comment,
|
|
178
|
+
EMBDOC_END: :comment,
|
|
179
|
+
|
|
180
|
+
# Strings and string-like
|
|
181
|
+
STRING_BEGIN: :string, STRING_CONTENT: :string, STRING_END: :string,
|
|
182
|
+
SYMBOL_BEGIN: :string, REGEXP_BEGIN: :string, REGEXP_END: :string,
|
|
183
|
+
PERCENT_LOWER_I: :string, PERCENT_UPPER_I: :string,
|
|
184
|
+
PERCENT_LOWER_W: :string, PERCENT_UPPER_W: :string,
|
|
185
|
+
PERCENT_LOWER_X: :string,
|
|
186
|
+
HEREDOC_START: :string, HEREDOC_END: :string,
|
|
187
|
+
LABEL: :property,
|
|
188
|
+
|
|
189
|
+
# Numbers
|
|
190
|
+
INTEGER: :number, FLOAT: :number,
|
|
191
|
+
INTEGER_RATIONAL: :number, FLOAT_RATIONAL: :number,
|
|
192
|
+
INTEGER_IMAGINARY: :number, FLOAT_IMAGINARY: :number,
|
|
193
|
+
INTEGER_RATIONAL_IMAGINARY: :number, FLOAT_RATIONAL_IMAGINARY: :number,
|
|
194
|
+
|
|
195
|
+
# Constants
|
|
196
|
+
CONSTANT: :constant,
|
|
197
|
+
|
|
198
|
+
# Variables
|
|
199
|
+
INSTANCE_VARIABLE: :variable, CLASS_VARIABLE: :variable,
|
|
200
|
+
GLOBAL_VARIABLE: :variable,
|
|
201
|
+
|
|
202
|
+
# Operators
|
|
203
|
+
PLUS: :operator, MINUS: :operator, STAR: :operator, SLASH: :operator,
|
|
204
|
+
PERCENT: :operator, STAR_STAR: :operator,
|
|
205
|
+
EQUAL: :operator, EQUAL_EQUAL: :operator, BANG_EQUAL: :operator,
|
|
206
|
+
LESS: :operator, GREATER: :operator,
|
|
207
|
+
LESS_EQUAL: :operator, GREATER_EQUAL: :operator,
|
|
208
|
+
LESS_EQUAL_GREATER: :operator, EQUAL_EQUAL_EQUAL: :operator,
|
|
209
|
+
EQUAL_TILDE: :operator, BANG_TILDE: :operator,
|
|
210
|
+
AMPERSAND_AMPERSAND: :operator, PIPE_PIPE: :operator,
|
|
211
|
+
BANG: :operator, TILDE: :operator,
|
|
212
|
+
LESS_LESS: :operator, GREATER_GREATER: :operator,
|
|
213
|
+
AMPERSAND: :operator, PIPE: :operator, CARET: :operator,
|
|
214
|
+
PLUS_EQUAL: :operator, MINUS_EQUAL: :operator,
|
|
215
|
+
STAR_EQUAL: :operator, SLASH_EQUAL: :operator,
|
|
216
|
+
PERCENT_EQUAL: :operator, STAR_STAR_EQUAL: :operator,
|
|
217
|
+
AMPERSAND_EQUAL: :operator, PIPE_EQUAL: :operator,
|
|
218
|
+
CARET_EQUAL: :operator,
|
|
219
|
+
AMPERSAND_AMPERSAND_EQUAL: :operator, PIPE_PIPE_EQUAL: :operator,
|
|
220
|
+
LESS_LESS_EQUAL: :operator, GREATER_GREATER_EQUAL: :operator,
|
|
221
|
+
DOT_DOT: :operator, DOT_DOT_DOT: :operator,
|
|
222
|
+
EQUAL_GREATER: :operator, UMINUS: :operator, UPLUS: :operator,
|
|
223
|
+
USTAR: :operator, USTAR_STAR: :operator, UAMPERSAND: :operator,
|
|
224
|
+
|
|
225
|
+
# Punctuation
|
|
226
|
+
DOT: :punctuation, COLON_COLON: :punctuation,
|
|
227
|
+
SEMICOLON: :punctuation, COMMA: :punctuation,
|
|
228
|
+
PARENTHESIS_LEFT: :punctuation, PARENTHESIS_RIGHT: :punctuation,
|
|
229
|
+
BRACKET_LEFT: :punctuation, BRACKET_LEFT_ARRAY: :punctuation,
|
|
230
|
+
BRACKET_RIGHT: :punctuation,
|
|
231
|
+
BRACE_LEFT: :punctuation, BRACE_RIGHT: :punctuation,
|
|
232
|
+
QUESTION_MARK: :punctuation, COLON: :punctuation,
|
|
233
|
+
LAMBDA_BEGIN: :punctuation,
|
|
234
|
+
|
|
235
|
+
# Method names (e.g. block_given?, is_a?)
|
|
236
|
+
METHOD_NAME: :function_name,
|
|
237
|
+
}.freeze
|
|
238
|
+
|
|
239
|
+
DEFINITION_KEYWORDS = %i[KEYWORD_CLASS KEYWORD_MODULE KEYWORD_DEF].to_set
|
|
240
|
+
|
|
241
|
+
LITERAL_BEGIN_TYPES = %i[STRING_BEGIN HEREDOC_START REGEXP_BEGIN EMBDOC_BEGIN].to_set
|
|
242
|
+
LITERAL_END_TYPES = %i[STRING_END HEREDOC_END REGEXP_END EMBDOC_END].to_set
|
|
243
|
+
|
|
244
|
+
CONTINUATION_OPERATOR_TYPES = %i[
|
|
245
|
+
PLUS MINUS STAR SLASH PERCENT STAR_STAR
|
|
246
|
+
EQUAL EQUAL_EQUAL BANG_EQUAL
|
|
247
|
+
LESS GREATER LESS_EQUAL GREATER_EQUAL LESS_EQUAL_GREATER
|
|
248
|
+
EQUAL_TILDE BANG_TILDE
|
|
249
|
+
AMPERSAND_AMPERSAND PIPE_PIPE
|
|
250
|
+
BANG TILDE
|
|
251
|
+
LESS_LESS GREATER_GREATER
|
|
252
|
+
AMPERSAND CARET
|
|
253
|
+
PLUS_EQUAL MINUS_EQUAL STAR_EQUAL SLASH_EQUAL PERCENT_EQUAL
|
|
254
|
+
STAR_STAR_EQUAL AMPERSAND_EQUAL PIPE_EQUAL CARET_EQUAL
|
|
255
|
+
AMPERSAND_AMPERSAND_EQUAL PIPE_PIPE_EQUAL
|
|
256
|
+
LESS_LESS_EQUAL GREATER_GREATER_EQUAL
|
|
257
|
+
EQUAL_GREATER
|
|
258
|
+
].to_set
|
|
259
|
+
|
|
260
|
+
OPERATORS = %i(!= !~ =~ == === <=> > >= < <= & | ^ >> << - + % / * ** -@ +@ ~ ! [] []=)
|
|
261
|
+
|
|
262
|
+
BLOCK_END = {
|
|
263
|
+
EMBEXPR_BEGIN: :EMBEXPR_END,
|
|
264
|
+
BRACE_LEFT: :BRACE_RIGHT,
|
|
265
|
+
PARENTHESIS_LEFT: :PARENTHESIS_RIGHT,
|
|
266
|
+
BRACKET_LEFT: :BRACKET_RIGHT,
|
|
267
|
+
BRACKET_LEFT_ARRAY: :BRACKET_RIGHT,
|
|
268
|
+
LAMBDA_BEGIN: :BRACE_RIGHT,
|
|
269
|
+
}
|
|
270
|
+
|
|
180
271
|
INDENT_BEG_RE = /^([ \t]*)(class|module|def|if|unless|case|while|until|for|begin)\b/
|
|
181
272
|
|
|
182
273
|
def space_width(s)
|
|
@@ -187,8 +278,7 @@ module Textbringer
|
|
|
187
278
|
loop do
|
|
188
279
|
@buffer.re_search_backward(INDENT_BEG_RE)
|
|
189
280
|
space = @buffer.match_string(1)
|
|
190
|
-
|
|
191
|
-
if PartialLiteralAnalyzer.in_literal?(s)
|
|
281
|
+
if in_literal?(@buffer.point)
|
|
192
282
|
next
|
|
193
283
|
end
|
|
194
284
|
return space_width(space)
|
|
@@ -199,19 +289,12 @@ module Textbringer
|
|
|
199
289
|
end
|
|
200
290
|
|
|
201
291
|
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
|
|
292
|
+
Prism.lex(source).value.filter_map { |token, _state|
|
|
293
|
+
type = token.type
|
|
294
|
+
next if type == :EOF
|
|
295
|
+
loc = token.location
|
|
296
|
+
[[loc.start_line, loc.start_column], type, token.value]
|
|
297
|
+
}
|
|
215
298
|
end
|
|
216
299
|
|
|
217
300
|
def calculate_indentation
|
|
@@ -227,19 +310,20 @@ module Textbringer
|
|
|
227
310
|
start_line = @buffer.current_line
|
|
228
311
|
tokens = lex(@buffer.substring(start_pos, bol_pos))
|
|
229
312
|
_, event, text = tokens.last
|
|
230
|
-
if event == :
|
|
313
|
+
if event == :NEWLINE || event == :IGNORED_NEWLINE
|
|
231
314
|
_, event, text = tokens[-2]
|
|
232
315
|
end
|
|
233
|
-
if event == :
|
|
234
|
-
event == :
|
|
235
|
-
event == :
|
|
236
|
-
|
|
237
|
-
event == :
|
|
316
|
+
if event == :STRING_BEGIN ||
|
|
317
|
+
event == :HEREDOC_START ||
|
|
318
|
+
(event == :HEREDOC_END && text.empty?) ||
|
|
319
|
+
event == :REGEXP_BEGIN ||
|
|
320
|
+
event == :STRING_CONTENT ||
|
|
321
|
+
event == :HEREDOC_CONTENT
|
|
238
322
|
return nil
|
|
239
323
|
end
|
|
240
324
|
i, extra_end_count = find_nearest_beginning_token(tokens)
|
|
241
325
|
(line, column), event, = i ? tokens[i] : nil
|
|
242
|
-
if event == :
|
|
326
|
+
if event == :PARENTHESIS_LEFT && tokens.dig(i + 1, 1) != :IGNORED_NEWLINE
|
|
243
327
|
return column + 1
|
|
244
328
|
end
|
|
245
329
|
if line
|
|
@@ -268,101 +352,87 @@ module Textbringer
|
|
|
268
352
|
if @buffer.looking_at?(/[ \t]*([}\])]|(end|else|elsif|when|in|rescue|ensure)\b)/)
|
|
269
353
|
indentation -= @buffer[:indent_level]
|
|
270
354
|
end
|
|
271
|
-
_, last_event,
|
|
272
|
-
e != :
|
|
355
|
+
_, last_event, = tokens.reverse_each.find { |_, e, _|
|
|
356
|
+
e != :NEWLINE && e != :IGNORED_NEWLINE
|
|
273
357
|
}
|
|
274
358
|
if start_with_period ||
|
|
275
|
-
(last_event
|
|
276
|
-
|
|
277
|
-
last_event == :
|
|
278
|
-
(last_event == :
|
|
279
|
-
event != :
|
|
280
|
-
|
|
359
|
+
CONTINUATION_OPERATOR_TYPES.include?(last_event) ||
|
|
360
|
+
last_event == :KEYWORD_AND || last_event == :KEYWORD_OR ||
|
|
361
|
+
last_event == :DOT ||
|
|
362
|
+
(last_event == :COMMA && event != :BRACE_LEFT &&
|
|
363
|
+
event != :PARENTHESIS_LEFT && event != :BRACKET_LEFT &&
|
|
364
|
+
event != :BRACKET_LEFT_ARRAY) ||
|
|
365
|
+
last_event == :LABEL
|
|
281
366
|
indentation += @buffer[:indent_level]
|
|
282
367
|
end
|
|
283
368
|
indentation
|
|
284
369
|
end
|
|
285
370
|
end
|
|
286
371
|
|
|
287
|
-
BLOCK_END = {
|
|
288
|
-
'#{' => "}",
|
|
289
|
-
"{" => "}",
|
|
290
|
-
"(" => ")",
|
|
291
|
-
"[" => "]"
|
|
292
|
-
}
|
|
293
|
-
|
|
294
372
|
def find_nearest_beginning_token(tokens)
|
|
295
373
|
stack = []
|
|
296
374
|
(tokens.size - 1).downto(0) do |i|
|
|
297
375
|
(line, ), event, text = tokens[i]
|
|
298
376
|
case event
|
|
299
|
-
when :
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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)
|
|
377
|
+
when :KEYWORD_CLASS, :KEYWORD_MODULE, :KEYWORD_DEF,
|
|
378
|
+
:KEYWORD_IF, :KEYWORD_UNLESS, :KEYWORD_CASE,
|
|
379
|
+
:KEYWORD_DO, :KEYWORD_DO_LOOP, :KEYWORD_FOR,
|
|
380
|
+
:KEYWORD_WHILE, :KEYWORD_UNTIL, :KEYWORD_BEGIN
|
|
381
|
+
if i > 0
|
|
382
|
+
_, prev_event, _ = tokens[i - 1]
|
|
383
|
+
next if prev_event == :SYMBOL_BEGIN
|
|
384
|
+
end
|
|
385
|
+
if event == :KEYWORD_DEF && endless_method_def?(tokens, i)
|
|
386
|
+
next
|
|
387
|
+
end
|
|
388
|
+
if stack.empty?
|
|
389
|
+
return i
|
|
390
|
+
end
|
|
391
|
+
if stack.last != :KEYWORD_END
|
|
392
|
+
raise EditorError, "#{@buffer.name}:#{line}: Unmatched #{text}"
|
|
321
393
|
end
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
394
|
+
stack.pop
|
|
395
|
+
when :KEYWORD_END
|
|
396
|
+
if i > 0
|
|
397
|
+
_, prev_event, _ = tokens[i - 1]
|
|
398
|
+
next if prev_event == :SYMBOL_BEGIN
|
|
399
|
+
end
|
|
400
|
+
stack.push(:KEYWORD_END)
|
|
401
|
+
when :BRACE_RIGHT, :PARENTHESIS_RIGHT, :BRACKET_RIGHT, :EMBEXPR_END
|
|
402
|
+
stack.push(event)
|
|
403
|
+
when :BRACE_LEFT, :PARENTHESIS_LEFT, :BRACKET_LEFT,
|
|
404
|
+
:BRACKET_LEFT_ARRAY, :LAMBDA_BEGIN, :EMBEXPR_BEGIN
|
|
325
405
|
if stack.empty?
|
|
326
406
|
return i
|
|
327
407
|
end
|
|
328
|
-
if stack.last != BLOCK_END[
|
|
408
|
+
if stack.last != BLOCK_END[event]
|
|
329
409
|
raise EditorError, "#{@buffer.name}:#{line}: Unmatched #{text}"
|
|
330
410
|
end
|
|
331
411
|
stack.pop
|
|
332
412
|
end
|
|
333
413
|
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] == "=")
|
|
414
|
+
return nil, stack.count { |t| t != :PARENTHESIS_RIGHT && t != :BRACKET_RIGHT }
|
|
342
415
|
end
|
|
343
416
|
|
|
344
417
|
def endless_method_def?(tokens, i)
|
|
345
418
|
ts = tokens.drop(i + 1)
|
|
346
|
-
ts.shift while ts[0][1] == :on_sp
|
|
347
419
|
_, event = ts.shift
|
|
348
|
-
return false if event != :
|
|
349
|
-
|
|
350
|
-
if ts[0][1] == :on_lparen
|
|
420
|
+
return false if event != :IDENTIFIER && event != :METHOD_NAME
|
|
421
|
+
if ts[0][1] == :PARENTHESIS_LEFT
|
|
351
422
|
ts.shift
|
|
352
423
|
count = 1
|
|
353
424
|
while count > 0
|
|
354
425
|
_, event = ts.shift
|
|
355
426
|
return false if event.nil?
|
|
356
427
|
case event
|
|
357
|
-
when :
|
|
358
|
-
count +=1
|
|
359
|
-
when :
|
|
360
|
-
count -=1
|
|
428
|
+
when :PARENTHESIS_LEFT
|
|
429
|
+
count += 1
|
|
430
|
+
when :PARENTHESIS_RIGHT
|
|
431
|
+
count -= 1
|
|
361
432
|
end
|
|
362
433
|
end
|
|
363
|
-
ts.shift while ts[0][1] == :on_sp
|
|
364
434
|
end
|
|
365
|
-
ts[0][1] == :
|
|
435
|
+
ts[0][1] == :EQUAL
|
|
366
436
|
rescue NoMethodError # no token
|
|
367
437
|
return false
|
|
368
438
|
end
|
|
@@ -395,31 +465,86 @@ module Textbringer
|
|
|
395
465
|
nil
|
|
396
466
|
end
|
|
397
467
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
468
|
+
def in_literal?(byte_offset)
|
|
469
|
+
ensure_prism_tokens
|
|
470
|
+
ensure_literal_levels
|
|
471
|
+
return false if @literal_levels.empty?
|
|
472
|
+
i = @literal_levels.bsearch_index { |offset, _| offset > byte_offset }
|
|
473
|
+
i = i ? i - 1 : @literal_levels.size - 1
|
|
474
|
+
return false if i < 0
|
|
475
|
+
@literal_levels[i][1] > 0
|
|
476
|
+
end
|
|
402
477
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
478
|
+
def filter_prism_tokens_line_and_type
|
|
479
|
+
ensure_prism_tokens
|
|
480
|
+
@prism_tokens.filter_map { |token, _state|
|
|
481
|
+
type = token.type
|
|
482
|
+
next if type == :EOF
|
|
483
|
+
[token.location.start_line, type]
|
|
484
|
+
}
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
def ensure_prism_tokens
|
|
488
|
+
return if @prism_version == @buffer.version
|
|
489
|
+
source = @buffer.to_s
|
|
490
|
+
if source.valid_encoding?
|
|
491
|
+
result = Prism.parse_lex(source)
|
|
492
|
+
@prism_ast, @prism_tokens = result.value
|
|
493
|
+
else
|
|
494
|
+
@prism_ast = nil
|
|
495
|
+
@prism_tokens = []
|
|
407
496
|
end
|
|
497
|
+
@prism_method_name_locs = nil
|
|
498
|
+
@prism_version = @buffer.version
|
|
499
|
+
@literal_levels_version = nil
|
|
500
|
+
end
|
|
408
501
|
|
|
409
|
-
|
|
502
|
+
def ensure_method_name_locs
|
|
503
|
+
return if @prism_method_name_locs
|
|
504
|
+
@prism_method_name_locs = {}
|
|
505
|
+
return unless @prism_ast
|
|
506
|
+
collect_method_name_locs(@prism_ast)
|
|
507
|
+
end
|
|
410
508
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
509
|
+
def collect_method_name_locs(node)
|
|
510
|
+
if node.type == :def_node
|
|
511
|
+
@prism_method_name_locs[node.name_loc.start_offset] = true
|
|
512
|
+
elsif node.type == :alias_method_node
|
|
513
|
+
add_alias_method_name_locs(node.new_name)
|
|
514
|
+
add_alias_method_name_locs(node.old_name)
|
|
515
|
+
elsif (node.type == :call_node &&
|
|
516
|
+
!(node.call_operator_loc.nil? && OPERATORS.include?(node.name)) && # exclude operators
|
|
517
|
+
!((node.call_operator_loc.nil? || node.call_operator_loc.slice == "::") && # exclude constants
|
|
518
|
+
/\A\p{Upper}/.match?(node.name))) ||
|
|
519
|
+
node.type == :call_operator_write_node ||
|
|
520
|
+
node.type == :call_and_write_node ||
|
|
521
|
+
node.type == :call_or_write_node
|
|
522
|
+
@prism_method_name_locs[node.message_loc.start_offset] = true
|
|
523
|
+
end
|
|
524
|
+
node.compact_child_nodes.each { |child| collect_method_name_locs(child) }
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
def add_alias_method_name_locs(node)
|
|
528
|
+
if node.type == :symbol_node && node.opening_loc.nil?
|
|
529
|
+
@prism_method_name_locs[node.value_loc.start_offset] = true
|
|
416
530
|
end
|
|
531
|
+
end
|
|
417
532
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
533
|
+
def ensure_literal_levels
|
|
534
|
+
return if @literal_levels_version == @prism_version
|
|
535
|
+
level = 0
|
|
536
|
+
@literal_levels = []
|
|
537
|
+
@prism_tokens&.each do |token, _state|
|
|
538
|
+
type = token.type
|
|
539
|
+
if LITERAL_BEGIN_TYPES.include?(type)
|
|
540
|
+
level += 1
|
|
541
|
+
elsif LITERAL_END_TYPES.include?(type)
|
|
542
|
+
next if type == :HEREDOC_END && token.value.empty?
|
|
543
|
+
level -= 1
|
|
421
544
|
end
|
|
545
|
+
@literal_levels << [token.location.start_offset, level]
|
|
422
546
|
end
|
|
547
|
+
@literal_levels_version = @prism_version
|
|
423
548
|
end
|
|
424
549
|
end
|
|
425
550
|
end
|