yap-shell 0.3.1 → 0.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 23d1c68c8e4cb9e3531fef656445654b3e5fd0d7
4
- data.tar.gz: 59e2297008fecdfe423b9c97d1e897bd138f9e31
3
+ metadata.gz: 70c4b7a17173c5d2f16dd2d318ad7fca64121c2b
4
+ data.tar.gz: f17c759ac10afbb5ed4d9bac3c47cdfc2e8590f8
5
5
  SHA512:
6
- metadata.gz: 764180407fb136d9495b713805d7b1ac372405faa4a4505bffaa1b4bc29e84151172547f560c31e60c66463cd993fe9ca446cb4cd8828c43da5abf18e2027acc
7
- data.tar.gz: d41da1cc4a590125e529a746c3d182a9da4764e9f0f7da37a37f62b87e5eb1075883556c302ed4b07a6e8f81afe2164d5d07509864f060d193ca17fdbb89b799
6
+ metadata.gz: e998bdac5eccd88ff29438bed0dc970371453a11e300049988b328174940a179c94d3f3ce90e061500ff3c87022517baa7380ae7d88d41304c31c234d092fea9
7
+ data.tar.gz: 6c7b6164c54f5dc7a3a1cca6a2a78d15dd7a31af58782cb7a7f4b0ff57cce86d3893aa920d668d3f054602a48e80be5b7ef331ca1720af0ca637d766c2ee3e69
data/Gemfile CHANGED
@@ -6,4 +6,4 @@ gemspec
6
6
  # gem 'yap-shell-parser', git: 'git@github.com:zdennis/yap-shell-parser.git'
7
7
  # gem "rawline", git: 'git@github.com:zdennis/rawline.git', branch: 'issues/input-issues'
8
8
  # gem "rawline", path: '/Users/zdennis/source/opensource_projects/rawline'
9
- # gem "pry-byebug"
9
+ gem "pry-byebug"
@@ -0,0 +1,16 @@
1
+ # History Addon
2
+
3
+ The History addon is provides primitive history capabilities:
4
+
5
+ * Loads history from ~/.yap/history when yap is loaded
6
+ * Saves history to ~/.yap/history when yap exits
7
+ * Saving is an append-only operation
8
+ * ~/.yap/history is in YAML format
9
+
10
+ ## Shell Functions
11
+
12
+ The history addon provides the `history` shell function that prints the contents of the history.
13
+
14
+ ## Limitations
15
+
16
+ The history addon currently does not support any kind of advanced history operations.
@@ -1,101 +1,55 @@
1
- require 'forwardable'
2
- require 'term/ansicolor'
3
- require 'ostruct'
4
-
5
1
  class History < Addon
6
- require 'history/buffer'
7
- require 'history/events'
8
-
9
- Color = Object.extend Term::ANSIColor
10
-
11
- class << self
12
- attr_accessor :history_item_formatter, :ignore_history_item
13
- end
14
-
15
- self.ignore_history_item = ->(item:) do
16
- item.command == "exit"
17
- end
18
-
19
- self.history_item_formatter = ->(item:, options:{}) do
20
- if item.duration
21
- sprintf(
22
- "%#{options[:max_position_width]}d %-s %s",
23
- item.position,
24
- item.command,
25
- Color.negative(Color.intense_black(item.duration))
26
- )
27
- else
28
- sprintf("%#{options[:max_position_width]}d %-s", item.position, item.command)
29
- end
30
- end
2
+ attr_reader :file
3
+ attr_reader :position
31
4
 
32
5
  def initialize_world(world)
33
6
  @world = world
34
- load_history
35
-
36
- world.editor.bind(:ctrl_h) { show_history(@world.editor) }
37
7
 
38
- world.func(:history) do |args:, stdin:, stdout:, stderr:|
39
- first_arg = args.first
40
- case first_arg
41
- when String
42
- if first_arg.start_with?("/")
43
- regex = first_arg.gsub(/(^\|\/$)/, '')
44
- ignore_history_item = ->(item:, options:{}) do
45
- item.command !~ /#{regex}/
46
- end
47
- else
48
- ignore_history_item = ->(item:, options:{}) do
49
- item.command !~ /#{first_arg}/
50
- end
51
- end
52
- show_history(world.editor, redraw_prompt:false, ignore_history_item:ignore_history_item)
53
- else
54
- show_history(world.editor, redraw_prompt:false)
55
- end
56
- end
57
- end
8
+ @file = world.configuration.path_for('history')
9
+ @position = 0
58
10
 
59
- def show_history(editor, redraw_prompt:true, ignore_history_item:nil, history_item_formatter:nil)
60
- editor.puts @history
61
- end
11
+ load_history
62
12
 
63
- def executing(command:, started_at:)
64
- # raise "Cannot acknowledge execution beginning of a command when no group has been started!" unless history.last
65
- end
13
+ world.func(:history) do |args:, stdin:, stdout:, stderr:|
14
+ history_length = @world.editor.history.length
15
+ first_arg = args.first.to_i
16
+ size = first_arg > 0 ? first_arg + 1 : history_length
66
17
 
67
- def executed(command:, stopped_at:)
68
- # raise "Cannot complete execution of a command when no command has been started!" unless history.last
18
+ # start from -2 since we don't want to include the current history
19
+ # command being run.
20
+ stdout.puts @world.editor.history[history_length-size..-2]
21
+ end
69
22
  end
70
23
 
71
24
  def save
72
- File.open(history_file, "a") do |file|
25
+ File.open(file, "a") do |file|
73
26
  # Don't write the YAML header because we're going to append to the
74
27
  # history file, not overwrite. YAML works fine without it.
75
- file.write @world.editor.history.to_yaml(@history_start_position..-1).gsub(/^---.*/, '')
28
+ unwritten_history = @world.editor.history.to_a[@position..-1]
29
+ if unwritten_history.any?
30
+ contents = unwritten_history
31
+ .each_with_object([]) { |line, arr| arr << line unless line == arr.last }
32
+ .map { |str| str.respond_to?(:without_ansi) ? str.without_ansi : str }
33
+ .to_yaml
34
+ .gsub(/^---.*?^/m, '')
35
+ file.write contents
36
+ end
76
37
  end
77
38
  end
78
39
 
79
40
  private
80
41
 
81
- def history
82
- @history
83
- end
84
-
85
- def history_file
86
- @history_file ||= File.expand_path('~') + '/.yap-history'
87
- end
88
-
89
42
  def load_history
90
- @world.editor.history = @history = History::Buffer.new(Float::INFINITY)
91
- @history_start_position = 0
92
-
93
43
  at_exit { save }
94
44
 
95
- return unless File.exists?(history_file) && File.readable?(history_file)
45
+ if File.exists?(file) && File.readable?(file)
46
+ history = YAML.load_file(file) || []
47
+
48
+ # History starts at the end of the history loaded from file.
49
+ @position = history.length
96
50
 
97
- history_elements = YAML.load_file(history_file) || []
98
- @history_start_position = history_elements.length
99
- @world.editor.history.replace(history_elements)
51
+ # Rely on the builtin history for now.
52
+ @world.editor.history.replace(history)
53
+ end
100
54
  end
101
55
  end
@@ -1,4 +1,6 @@
1
1
  class KeyboardMacros < Addon
2
+ require 'keyboard_macros/cycle'
3
+
2
4
  DEFAULT_TRIGGER_KEY = :ctrl_g
3
5
  DEFAULT_CANCEL_KEY = " "
4
6
  DEFAULT_TIMEOUT_IN_MS = 500
@@ -35,7 +37,8 @@ class KeyboardMacros < Addon
35
37
  configuration = Configuration.new(
36
38
  keymap: world.editor.terminal.keys,
37
39
  trigger_key: trigger_key,
38
- cancellation: Cancellation.new(cancel_key: cancel_key, &cancel_blk)
40
+ cancellation: Cancellation.new(cancel_key: cancel_key, &cancel_blk),
41
+ editor: world.editor,
39
42
  )
40
43
 
41
44
  blk.call configuration if blk
@@ -43,7 +46,8 @@ class KeyboardMacros < Addon
43
46
  world.unbind(trigger_key)
44
47
  world.bind(trigger_key) do
45
48
  begin
46
- @stack << configuration
49
+ @previous_result = nil
50
+ @stack << OpenStruct.new(configuration: configuration)
47
51
  configuration.start.call if configuration.start
48
52
  world.editor.keyboard_input_processors.push(self)
49
53
  world.editor.input.wait_timeout_in_seconds = 0.1
@@ -55,28 +59,47 @@ class KeyboardMacros < Addon
55
59
  @configurations << configuration
56
60
  end
57
61
 
62
+ def cycle(name, &cycle_thru_blk)
63
+ @cycles ||= {}
64
+ if block_given?
65
+ cycle = KeyboardMacros::Cycle.new(
66
+ cycle_proc: cycle_thru_blk,
67
+ on_cycle_proc: -> (old_value, new_value) {
68
+ @world.editor.delete_n_characters(old_value.to_s.length)
69
+ process_result(new_value)
70
+ }
71
+ )
72
+ @cycles[name] = cycle
73
+ else
74
+ @cycles.fetch(name)
75
+ end
76
+ end
77
+
58
78
  #
59
79
  # InputProcessor Methods
60
80
  #
61
81
 
62
82
  def read_bytes(bytes)
63
- configuration = @stack.last
64
- bytes.each do |byte|
83
+ if @stack.last
84
+ current_definition = @stack.last
85
+ configuration = current_definition.configuration
86
+ end
87
+
88
+ bytes.each_with_index do |byte, i|
65
89
  definition = configuration[byte]
66
90
  if !definition
67
91
  cancel_processing if cancel_on_unknown_sequences
68
92
  break
69
93
  end
94
+
70
95
  configuration = definition.configuration
71
- if configuration
72
- configuration.start.call if configuration.start
73
- @stack << configuration
74
- end
96
+ configuration.start.call if configuration.start
97
+ @stack << definition
75
98
 
76
99
  result = definition.process
77
100
 
78
101
  if result =~ /\n$/
79
- world.editor.write result.chomp
102
+ world.editor.write result.chomp, add_to_line_history: false
80
103
  world.editor.event_loop.clear @event_id if @event_id
81
104
  cancel_processing
82
105
  world.editor.newline # add_to_history
@@ -84,18 +107,31 @@ class KeyboardMacros < Addon
84
107
  break
85
108
  end
86
109
 
87
- @stack.pop if definition.fragment?
110
+ if i == bytes.length - 1
111
+ while @stack.last && @stack.last.fragment?
112
+ @stack.pop
113
+ end
114
+ end
88
115
 
89
116
  if @event_id
90
117
  world.editor.event_loop.clear @event_id
91
118
  @event_id = queue_up_remove_input_processor
92
119
  end
93
- world.editor.write result if result.is_a?(String)
120
+
121
+ process_result(result)
94
122
  end
95
123
  end
96
124
 
97
125
  private
98
126
 
127
+ def process_result(result)
128
+ if result.is_a?(String)
129
+ $z.puts "WRITING: #{result}"
130
+ @world.editor.write result, add_to_line_history: false
131
+ @previous_result = result
132
+ end
133
+ end
134
+
99
135
  def queue_up_remove_input_processor(&blk)
100
136
  return unless @timeout_in_ms
101
137
 
@@ -111,8 +147,8 @@ class KeyboardMacros < Addon
111
147
 
112
148
  def cancel_processing
113
149
  @event_id = nil
114
- @stack.reverse.each do |configuration|
115
- configuration.stop.call if configuration.stop
150
+ @stack.reverse.each do |definition|
151
+ definition.configuration.stop.call if definition.configuration.stop
116
152
  end
117
153
  @stack.clear
118
154
  if world.editor.keyboard_input_processors.last == self
@@ -137,13 +173,15 @@ class KeyboardMacros < Addon
137
173
  class Configuration
138
174
  attr_reader :cancellation, :trigger_key, :keymap
139
175
 
140
- def initialize(cancellation: nil, keymap: {}, trigger_key: nil)
176
+ def initialize(cancellation: nil, editor:, keymap: {}, trigger_key: nil)
141
177
  @cancellation = cancellation
178
+ @editor = editor
142
179
  @keymap = keymap
143
180
  @trigger_key = trigger_key
144
181
  @storage = {}
145
182
  @on_start_blk = nil
146
183
  @on_stop_blk = nil
184
+ @cycles = {}
147
185
 
148
186
  if @cancellation
149
187
  define @cancellation.cancel_key, -> { @cancellation.call }
@@ -160,13 +198,25 @@ class KeyboardMacros < Addon
160
198
  @on_stop_blk
161
199
  end
162
200
 
163
- def fragment(sequence, result)
164
- define(sequence, result).tap do |definition|
165
- definition.fragment!
201
+ def cycle(name, &cycle_thru_blk)
202
+ if block_given?
203
+ cycle = KeyboardMacros::Cycle.new(
204
+ cycle_proc: cycle_thru_blk,
205
+ on_cycle_proc: -> (old_value, new_value) {
206
+ @editor.delete_n_characters(old_value.to_s.length)
207
+ }
208
+ )
209
+ @cycles[name] = cycle
210
+ else
211
+ @cycles.fetch(name)
166
212
  end
167
213
  end
168
214
 
169
- def define(sequence, result, &blk)
215
+ def fragment(sequence, result)
216
+ define(sequence, result, fragment: true)
217
+ end
218
+
219
+ def define(sequence, result=nil, fragment: false, &blk)
170
220
  unless result.respond_to?(:call)
171
221
  string_result = result
172
222
  result = -> { string_result }
@@ -178,6 +228,7 @@ class KeyboardMacros < Addon
178
228
  self,
179
229
  sequence.bytes,
180
230
  result,
231
+ fragment: fragment,
181
232
  &blk
182
233
  )
183
234
  when Symbol
@@ -187,10 +238,11 @@ class KeyboardMacros < Addon
187
238
  fail "Cannot bind unknown sequence #{sequence.inspect}"
188
239
  },
189
240
  result,
241
+ fragment: fragment,
190
242
  &blk
191
243
  )
192
244
  when Regexp
193
- define_sequence_for_regex(sequence, result, &blk)
245
+ define_sequence_for_regex(sequence, result, fragment: fragment, &blk)
194
246
  else
195
247
  raise NotImplementedError, <<-EOT.gsub(/^\s*/, '')
196
248
  Don't know how to define macro for sequence: #{sequence.inspect}
@@ -206,67 +258,87 @@ class KeyboardMacros < Addon
206
258
  @storage[key] = definition
207
259
  end
208
260
 
261
+ def inspect
262
+ str = @storage.map{ |k,v| "#{k}=#{v.inspect}" }.join("\n ")
263
+ num_items = @storage.reduce(0) { |s, arr| s + arr.length }
264
+ "<Configuration num_items=#{num_items} stored_keys=#{str}>"
265
+ end
266
+
209
267
  private
210
268
 
211
- def define_sequence_for_regex(regex, result, &blk)
269
+ def define_sequence_for_regex(regex, result, fragment: false, &blk)
212
270
  @storage[regex] = Definition.new(
213
271
  configuration: Configuration.new(
214
272
  cancellation: @cancellation,
215
- keymap: @keymap
273
+ keymap: @keymap,
274
+ editor: @editor
216
275
  ),
276
+ fragment: fragment,
217
277
  sequence: regex,
218
278
  result: result,
219
279
  &blk
220
280
  )
221
281
  end
222
282
 
223
- def recursively_define_sequence_for_bytes(configuration, bytes, result, &blk)
283
+ def recursively_define_sequence_for_bytes(configuration, bytes, result, fragment: false, &blk)
224
284
  byte, rest = bytes[0], bytes[1..-1]
225
285
  if rest.any?
226
- definition = Definition.new(
227
- configuration: Configuration.new(
228
- cancellation: @cancellation,
229
- keymap: @keymap
230
- ),
231
- sequence: byte,
232
- result: nil,
233
- &blk
234
- )
286
+ definition = if configuration[byte]
287
+ configuration[byte]
288
+ else
289
+ Definition.new(
290
+ configuration: Configuration.new(
291
+ cancellation: @cancellation,
292
+ keymap: @keymap,
293
+ editor: @editor
294
+ ),
295
+ fragment: fragment,
296
+ sequence: byte,
297
+ result: nil
298
+ )
299
+ end
300
+ blk.call(definition.configuration) if blk
235
301
  configuration[byte] = definition
236
302
  recursively_define_sequence_for_bytes(
237
303
  definition.configuration,
238
304
  rest,
239
305
  result,
306
+ fragment: fragment,
240
307
  &blk
241
308
  )
242
309
  else
243
- configuration[byte] = Definition.new(
244
- configuration: Configuration.new(keymap: @keymap),
310
+ definition = Definition.new(
311
+ configuration: Configuration.new(
312
+ keymap: @keymap,
313
+ editor: @editor
314
+ ),
315
+ fragment: fragment,
245
316
  sequence: byte,
246
- result: result,
247
- &blk
317
+ result: result
248
318
  )
319
+ configuration[byte] = definition
320
+ blk.call(definition.configuration) if blk
321
+ definition
249
322
  end
250
323
  end
251
324
  end
252
325
 
253
326
  class Definition
254
- attr_reader :bytes, :configuration, :result, :sequence
327
+ attr_reader :configuration, :result, :sequence
255
328
 
256
- def initialize(configuration: nil, sequence:, result: nil, &blk)
257
- @fragment = false
329
+ def initialize(configuration: nil, fragment: false, sequence:, result: nil)
330
+ @fragment = fragment
258
331
  @configuration = configuration
259
332
  @sequence = sequence
260
333
  @result = result
261
- blk.call(@configuration) if blk
262
334
  end
263
335
 
264
- def fragment?
265
- @fragment
336
+ def inspect
337
+ "<Definition fragment=#{@fragment.inspect} sequence=#{@sequence.inspect} result=#{@result.inspect} configuration=#{@configuration.inspect}>"
266
338
  end
267
339
 
268
- def fragment!
269
- @fragment = true
340
+ def fragment?
341
+ @fragment
270
342
  end
271
343
 
272
344
  def matches?(byte)
@@ -0,0 +1,38 @@
1
+ class KeyboardMacros
2
+ class Cycle
3
+ def initialize(cycle_proc:, on_cycle_proc: nil)
4
+ @cycle_proc = cycle_proc
5
+ @on_cycle_proc = on_cycle_proc
6
+ @previous_result = nil
7
+ reset
8
+ end
9
+
10
+ def next
11
+ @index = -1 if @index >= cycle_values.length - 1
12
+ on_cycle cycle_values[@index += 1]
13
+ end
14
+
15
+ def previous
16
+ @index = cycle_values.length if @index < 0
17
+ on_cycle cycle_values[@index -= 1]
18
+ end
19
+
20
+ def reset
21
+ @index = -1
22
+ @previous_result = nil
23
+ @cycle_values = nil
24
+ end
25
+
26
+ private
27
+
28
+ def cycle_values
29
+ @cycle_values ||= @cycle_proc.call
30
+ end
31
+
32
+ def on_cycle(new_value)
33
+ @on_cycle_proc.call(@previous_result, new_value) if @on_cycle_proc
34
+ @previous_result = new_value
35
+ new_value
36
+ end
37
+ end
38
+ end
@@ -22,7 +22,7 @@ class PromptUpdates < Addon
22
22
  private
23
23
 
24
24
  def determine_branch
25
- `git branch`.scan(/\*\s*(.*)$/).flatten.first
25
+ `git branch 2>/dev/null`.scan(/\*\s*(.*)$/).flatten.first
26
26
  end
27
27
 
28
28
  end
@@ -0,0 +1,151 @@
1
+ class TabCompletion
2
+ class BasicCompletion
3
+ class << self
4
+ attr_accessor :priority
5
+ end
6
+ self.priority = 1
7
+
8
+ attr_reader :world
9
+
10
+ def initialize(world:, word_break_characters:, path:nil)
11
+ @world = world
12
+ @word_break_characters = word_break_characters
13
+ path ||= @world.env["PATH"]
14
+ @paths = path.split(":")
15
+ end
16
+
17
+ def completions_for(word, words, word_index)
18
+ completions_by_name = {}
19
+ if looking_for_command?(word, words, word_index)
20
+ # Lowest Priority
21
+ completions_by_name.merge! command_completion_matches_for(word, words)
22
+
23
+ # Low Priority
24
+ completions_by_name.merge! builtin_completion_matches_for(word, words)
25
+
26
+ # Medium Priority
27
+ completions_by_name.merge! executable_filename_completion_matches_for(word, words)
28
+
29
+ # High Priority
30
+ completions_by_name.merge! shell_command_completion_matches_for(word, words)
31
+
32
+ # Highest Priority
33
+ completions_by_name.merge! alias_completion_matches_for(word, words)
34
+ else
35
+ completions_by_name.merge! filename_completion_matches_for(word, words)
36
+ end
37
+ completions_by_name.merge! environment_variable_completions_for(word, words)
38
+ completions_by_name.values
39
+ end
40
+
41
+ private
42
+
43
+ def looking_for_command?(word, words, word_index)
44
+ return false unless word_index
45
+ return true if word_index == 0
46
+ return true if words[word_index - 1] =~ /[;&]/
47
+ false
48
+ end
49
+
50
+ def alias_completion_matches_for(word, words)
51
+ @world.aliases.names.each_with_object({}) do |name, result|
52
+ if name =~ /^#{Regexp.escape(word)}/
53
+ result[name] ||= CompletionResult.new(
54
+ type: :alias,
55
+ text: name
56
+ )
57
+ end
58
+ end
59
+ end
60
+
61
+ def builtin_completion_matches_for(word, words)
62
+ @world.builtins.each_with_object({}) do |builtin, result|
63
+ if builtin =~ /^#{Regexp.escape(word)}/
64
+ result[builtin] ||= CompletionResult.new(
65
+ type: :builtin,
66
+ text: builtin
67
+ )
68
+ end
69
+ end
70
+ end
71
+
72
+ def command_completion_matches_for(word, words)
73
+ @paths.each_with_object({}) do |path, matches|
74
+ glob = File.join(path, "#{word}*")
75
+ arr = Dir[glob].select { |path| File.executable?(path) && File.file?(path) }
76
+ arr.map { |path| File.basename(path) }.uniq.each do |command|
77
+ matches[command] = CompletionResult.new(type: :command, text: command)
78
+ end
79
+ end
80
+ end
81
+
82
+ def environment_variable_completions_for(word, words)
83
+ return {} unless word =~ /^\$/
84
+ prefix, word_sans_prefix = word[0], word[1..-1]
85
+ @world.env.keys.each_with_object({}) do |env_var, result|
86
+ if env_var =~ /^#{Regexp.escape(word_sans_prefix)}/
87
+ result[env_var] ||= CompletionResult.new(
88
+ type: :env_var,
89
+ text: prefix + env_var
90
+ )
91
+ end
92
+ end
93
+ end
94
+
95
+ def executable_filename_completion_matches_for(word, words)
96
+ glob = "#{word}*"
97
+ glob.gsub!("~", world.env["HOME"])
98
+ Dir.glob(glob, File::FNM_CASEFOLD).each_with_object({}) do |path, result|
99
+ text = path.gsub(filtered_work_break_characters_rgx, '\\\\\1')
100
+ descriptive_text = File.basename(text)
101
+ if !File.directory?(path) && File.executable?(path)
102
+ result[path] = CompletionResult.new(
103
+ type: :command,
104
+ text: text,
105
+ descriptive_text: descriptive_text
106
+ )
107
+ end
108
+ end
109
+ end
110
+
111
+ def shell_command_completion_matches_for(word, words)
112
+ @world.shell_commands.each_with_object({}) do |shell_command, result|
113
+ if shell_command =~ /^#{Regexp.escape(word)}/
114
+ result[shell_command] ||= CompletionResult.new(
115
+ type: :shell_command,
116
+ text: shell_command
117
+ )
118
+ end
119
+ end
120
+ end
121
+
122
+ def filename_completion_matches_for(word, line)
123
+ glob = "#{word}*"
124
+ glob.gsub!("~", world.env["HOME"])
125
+ Dir.glob(glob, File::FNM_CASEFOLD).each_with_object({}) do |path, result|
126
+ text = path.gsub(filtered_work_break_characters_rgx, '\\\\\1')
127
+ descriptive_text = File.basename(text)
128
+ result[path] = if File.directory?(path)
129
+ CompletionResult.new(type: :directory, text: text, descriptive_text: descriptive_text)
130
+ elsif File.symlink?(path)
131
+ CompletionResult.new(type: :symlink, text: text, descriptive_text: descriptive_text)
132
+ elsif File.file?(path) && File.executable?(path)
133
+ CompletionResult.new(type: :command, text: text, descriptive_text: descriptive_text)
134
+ else
135
+ CompletionResult.new(type: :file, text: text, descriptive_text: descriptive_text)
136
+ end
137
+ end
138
+ end
139
+
140
+ # Remove file separator and the back-slash from word break characters when determining
141
+ # the pre-word-context
142
+ def filtered_word_break_characters
143
+ @word_break_characters.sub(File::Separator, "").sub('\\', '')
144
+ end
145
+
146
+ def filtered_work_break_characters_rgx
147
+ /([#{Regexp.escape(filtered_word_break_characters)}])/
148
+ end
149
+
150
+ end
151
+ end