Module: VER::Methods::Control

Defined in:
lib/ver/methods/control.rb

Constant Summary collapse

REPEAT_BREAK_CMD =
[
  :repeat_command,
  :undo,
  :redo,
]
REPEAT_BREAK_MODE =
[
  :move,
  :search,
]
ENV_EXPORTERS =
%w[
  current_line current_word directory filepath line_index line_number
  scope selected_text
]

Class Method Summary collapse

Class Method Details

.chdir(text) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/ver/methods/control.rb', line 80

def chdir(text)
  text.ask 'Change to: ' do |path, action|
    case action
    when :attempt
      path = File.expand_path(path.to_s)

      begin
        Dir.chdir(path)
        VER.message 'Changed working directory to %s' % [path]
        :abort
      rescue Errno::ENOENT => ex
        VER.warn ex
      end
    end
  end
end

.clean_line(text, index, record = text) ⇒ Object



424
425
426
427
428
429
430
# File 'lib/ver/methods/control.rb', line 424

def clean_line(text, index, record = text)
  index = text.index(index)
  from, to = index.linestart, index.lineend
  line = text.get(from, to)
  bare = line.rstrip
  record.replace(from, to, bare) if bare.empty?
end

.cursor_vertical_bottom(text) ⇒ Object



65
66
67
68
69
70
71
72
73
# File 'lib/ver/methods/control.rb', line 65

def cursor_vertical_bottom(text)
  insert = text.count('1.0', 'insert', :displaylines) + 1
  last   = text.count('1.0', 'end', :displaylines)
  shown  = text.count('@0,0', "@0,#{text.winfo_height}", :displaylines)

  fraction = ((100.0 / last) * (insert - shown)) / 100

  text.yview_moveto(fraction)
end

.cursor_vertical_bottom_sol(text) ⇒ Object



75
76
77
78
# File 'lib/ver/methods/control.rb', line 75

def cursor_vertical_bottom_sol(text)
  cursor_vertical_bottom(text)
  start_of_line(text)
end

.cursor_vertical_center(text) ⇒ Object



50
51
52
53
54
55
56
57
58
# File 'lib/ver/methods/control.rb', line 50

def cursor_vertical_center(text)
  insert = text.count('1.0', 'insert', :displaylines)
  last   = text.count('1.0', 'end', :displaylines)
  shown  = text.count('@0,0', "@0,#{text.winfo_height}", :displaylines)

  fraction = ((100.0 / last) * (insert - (shown / 2))) / 100

  text.yview_moveto(fraction)
end

.cursor_vertical_center_sol(text) ⇒ Object



60
61
62
63
# File 'lib/ver/methods/control.rb', line 60

def cursor_vertical_center_sol(text)
  cursor_vertical_center(text)
  Move.start_of_line(text)
end

.cursor_vertical_top(text) ⇒ Object



36
37
38
39
40
41
42
43
# File 'lib/ver/methods/control.rb', line 36

def cursor_vertical_top(text)
  insert = text.count('1.0', 'insert', :displaylines)
  last   = text.count('1.0', 'end', :displaylines)

  fraction = ((100.0 / last) * insert) / 100

  text.yview_moveto(fraction)
end

.cursor_vertical_top_sol(text) ⇒ Object



45
46
47
48
# File 'lib/ver/methods/control.rb', line 45

def cursor_vertical_top_sol(text)
  cursor_vertical_top(text)
  Move.start_of_line(text)
end

.enter(text, old_mode, new_mode) ⇒ Object



6
7
8
# File 'lib/ver/methods/control.rb', line 6

def enter(text, old_mode, new_mode)
  clean_line(text, :insert)
end

.eval_bufferObject



385
386
387
388
389
# File 'lib/ver/methods/control.rb', line 385

def eval_buffer
  result = eval(value, TOPLEVEL_BINDING)
rescue Exception => exception
  VER.error(exception)
end

.exec_bundleObject

Set up the env for a script, then execute it. For now, I only setup the env, until we figure out a good way to find bundle commands.



197
198
199
200
201
202
203
204
# File 'lib/ver/methods/control.rb', line 197

def exec_bundle
  ENV_EXPORTERS.each do |exporter|
    ENV["VER_#{exporter.upcase}"] = ENV["TM_#{exporter.upcase}"] =
      send("exec_env_#{exporter}").to_s
  end

  yield if block_given?
end

.exec_env_current_lineObject

textual content of the current line



207
208
209
# File 'lib/ver/methods/control.rb', line 207

def exec_env_current_line
  get('insert linestart', 'insert lineend')
end

.exec_env_current_wordObject

the word in which the caret is located.



212
213
214
# File 'lib/ver/methods/control.rb', line 212

def exec_env_current_word
  get('insert wordstart', 'insert wordend')
end

.exec_env_directoryObject

the folder of the current document (may not be set).



217
218
219
# File 'lib/ver/methods/control.rb', line 217

def exec_env_directory
  filename.dirname.to_s
end

.exec_env_filepathObject

path (including file name) for the current document (may not be set).



222
223
224
# File 'lib/ver/methods/control.rb', line 222

def exec_env_filepath
  filename.to_s
end

.exec_env_line_indexObject

the index in the current line which marks the caret’s location. This index is zero-based and takes the utf-8 encoding of the line (e.g. read as TM_CURRENT_LINE) into account.



229
230
231
# File 'lib/ver/methods/control.rb', line 229

def exec_env_line_index
  index('insert').x
end

.exec_env_line_numberObject

the carets line position (counting from 1).



234
235
236
# File 'lib/ver/methods/control.rb', line 234

def exec_env_line_number
  index('insert').y
end

.exec_env_scopeObject



238
239
240
# File 'lib/ver/methods/control.rb', line 238

def exec_env_scope
  tag_names('insert').join(', ')
end

.exec_env_selected_textObject

full content of the selection (may not be set). Note that environment variables have a size limitation of roughly 64 KB, so if the user selects more than that, this variable will not reflect the actual selection (commands that need to work with the selection should generally set this to be the standard input).



247
248
249
250
251
252
253
254
255
# File 'lib/ver/methods/control.rb', line 247

def exec_env_selected_text
  content = []

  each_selected_line do |y, fx, tx|
    content << get("#{y}.#{fx}", "#{y}.#{tx}")
  end

  content.join("\n")
end

.exec_into_new(text, command = nil) ⇒ Object



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/ver/methods/control.rb', line 257

def exec_into_new(text, command = nil)
  if command
    target = text.options.home_conf_dir/'shell-result.txt'
    prepare_exec(command)
    system(command)
    target.open('w+'){|io| io.write(`#{command}`) }
    VER.find_or_create_buffer(target)
  else
    text.ask 'Command: ' do |answer, action|
      case action
      when :attempt
        begin
          exec_into_new(answer)
          :abort
        rescue => ex
          VER.warn(ex)
        end
      end
    end
  end
end

.exec_into_void(text) ⇒ Object



279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/ver/methods/control.rb', line 279

def exec_into_void(text)
  text.ask 'Command: ' do |command, action|
    case action
    when :attempt
      begin
        system(command)
        VER.message("Exit code: #{$?}")
        :abort
      rescue => ex
        VER.warn(ex)
      end
    end
  end
end

.executor(text, action = nil) ⇒ Object Also known as: ex



336
337
338
# File 'lib/ver/methods/control.rb', line 336

def executor(text, action = nil)
  VER::Executor.new(text, action: action)
end

.gsub(text, regexp, with) ⇒ Object

Substitute over all lines of the buffer



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/ver/methods/control.rb', line 308

def gsub(text, regexp, with)
  total = 0
  Undo.record text do |record|
    text.index('1.0').upto(text.index('end')) do |index|
      lineend = index.lineend
      line = text.get(index, lineend)

      if line.gsub!(regexp, with)
        record.replace(index, lineend, line)
        total += 1
      end
    end
  end

  VER.message "Performed gsub on #{total} lines"
end

.indent_line(text, count = text.prefix_count) ⇒ Object



403
404
405
406
# File 'lib/ver/methods/control.rb', line 403

def indent_line(text, count = text.prefix_count)
  indent = (' ' * text.options[:shiftwidth] * count)
  text.insert('insert linestart', indent)
end

.insert_at(text, motion, *count) ⇒ Object



14
15
16
17
# File 'lib/ver/methods/control.rb', line 14

def insert_at(text, motion, *count)
  Move.send(motion, text, *count)
  text.minor_mode(:control, :insert)
end

.insert_indented_newline_above(text) ⇒ Object



19
20
21
# File 'lib/ver/methods/control.rb', line 19

def insert_indented_newline_above(text)
  Insert.insert_indented_newline_above(text)
end

.insert_indented_newline_below(text) ⇒ Object



23
24
25
# File 'lib/ver/methods/control.rb', line 23

def insert_indented_newline_below(text)
  Insert.insert_indented_newline_below(text)
end

.join_line_backward(text) ⇒ Object



397
398
399
400
401
# File 'lib/ver/methods/control.rb', line 397

def join_line_backward(text)
  from, to = 'insert - 1 lines linestart', 'insert lineend'
  lines = text.get(from, to)
  text.replace(from, to, lines.gsub(/\s*\n\s*/, ' '))
end

.join_line_forward(text) ⇒ Object



391
392
393
394
395
# File 'lib/ver/methods/control.rb', line 391

def join_line_forward(text)
  from, to = 'insert linestart', 'insert + 1 lines lineend'
  lines = text.get(from, to)
  text.replace(from, to, lines.gsub(/\s*\n\s*/, ' '))
end

.leave(text, old_mode, new_mode) ⇒ Object



10
11
12
# File 'lib/ver/methods/control.rb', line 10

def leave(text, old_mode, new_mode)
  # clean_line(text, :insert)
end

.line_evaluate(text) ⇒ Object



360
361
362
363
364
365
# File 'lib/ver/methods/control.rb', line 360

def line_evaluate(text)
  content = text.get('insert linestart', 'insert lineend')
  stdout_capture_evaluate(content, text.filename, binding) do |res,out|
    text.insert("insert lineend", "\n%s%p" % [out, res] )
  end
end

.open_file_under_cursor(text) ⇒ Object



27
28
29
# File 'lib/ver/methods/control.rb', line 27

def open_file_under_cursor(text)
  Open.open_file_under_cursor(text)
end

.prepare_exec(text, command) ⇒ Object

Assigns env variables used in the given command.

  • $f: The current buffer’s filename

  • $d: The current buffer’s directory

  • $F: A space-separated list of all buffer filenames

  • $i: A string acquired from the user with a prompt

  • $c: The current clipboard text

  • $s: The currently selected text

Parameters:

  • command (String)

    The string containing the command executed



150
151
152
153
154
155
156
157
# File 'lib/ver/methods/control.rb', line 150

def prepare_exec(text, command)
  prepare_exec_f(text) if command =~ /\$f/
  prepare_exec_d(text) if command =~ /\$d/
  prepare_exec_F(text) if command =~ /\$F/
  prepare_exec_i(text) if command =~ /\$i/
  prepare_exec_c(text) if command =~ /\$c/
  prepare_exec_s(text) if command =~ /\$s/
end

.prepare_exec_c(text) ⇒ Object



175
176
177
# File 'lib/ver/methods/control.rb', line 175

def prepare_exec_c(text)
  p c: (ENV['c'] = clipboard_get)
end

.prepare_exec_d(text) ⇒ Object



163
164
165
# File 'lib/ver/methods/control.rb', line 163

def prepare_exec_d(text)
  p d: (ENV['d'] = filename.directory.to_s)
end

.prepare_exec_f(text) ⇒ Object



159
160
161
# File 'lib/ver/methods/control.rb', line 159

def prepare_exec_f(text)
  p f: (ENV['f'] = filename.to_s)
end

.prepare_exec_F(text) ⇒ Object



167
168
169
# File 'lib/ver/methods/control.rb', line 167

def prepare_exec_F(text)
  p F: (ENV['F'] = VER.buffers.map{|key, buffer| buffer.filename }.join(' '))
end

.prepare_exec_i(text) ⇒ Object

Raises:

  • (NotImplementedError)


171
172
173
# File 'lib/ver/methods/control.rb', line 171

def prepare_exec_i(text)
  raise NotImplementedError
end

.prepare_exec_s(text) ⇒ Object



179
180
181
182
183
184
185
186
187
# File 'lib/ver/methods/control.rb', line 179

def prepare_exec_s(text)
  content = []

  each_selected_line do |y, fx, tx|
    content << get("#{y}.#{fx}", "#{y}.#{tx}")
  end

  ENV['s'] = content.join("\n")
end

.repeat_command(text, count = text.prefix_count) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/ver/methods/control.rb', line 118

def repeat_command(text, count = text.prefix_count)
  actions = []
  text.major_mode.action_history.reverse_each do |event, mode, action|
    if actions.empty?
      next if REPEAT_BREAK_CMD.include?(action.method)
      next if REPEAT_BREAK_MODE.include?(mode.name)
    else
      break if REPEAT_BREAK_CMD.include?(action.method)
      break if REPEAT_BREAK_MODE.include?(mode.name)
    end

    actions << [action, event]
  end

  actions.reverse!

  actions.each do |action, event|
    event.prefix_arg = count
    action.call(event)
  end
end

.smart_evaluate(text) ⇒ Object



351
352
353
354
355
356
357
358
# File 'lib/ver/methods/control.rb', line 351

def smart_evaluate(text)
  if sel = text.tag_ranges(:sel)
    from, to = sel.first
    return Selection.evaluate(text) if from && to
  end

  line_evaluate(text)
end

.source_buffer(text) ⇒ Object



31
32
33
34
# File 'lib/ver/methods/control.rb', line 31

def source_buffer(text)
  VER.message("Source #{text.filename}")
  load(text.filename.to_s)
end

.stdout_capture_evaluate(code, file, binding = binding) ⇒ Object



367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/ver/methods/control.rb', line 367

def stdout_capture_evaluate(code, file, binding = binding)
  begin
    old_stdout = $stdout.dup
    rd, wr = IO.pipe
    $stdout.reopen(wr)
    result = eval(code, binding, file.to_s)
    $stdout.reopen old_stdout; wr.close
    stdout = rd.read

    yield(result, stdout)
  rescue Exception => exception
    yield(exception, '')
  ensure
    wr.closed? || $stdout.reopen(old_stdout) && wr.close
    rd.closed? || rd.close
  end
end

.sub(text, regexp, with) ⇒ Object

Substitute on current line



326
327
328
329
330
331
332
333
334
# File 'lib/ver/methods/control.rb', line 326

def sub(text, regexp, with)
  linestart = text.index('insert linestart')
  lineend = linestart.lineend
  line = text.get(linestart, lineend)

  if line.sub!(regexp, with)
    text.replace(linestart, lineend, line)
  end
end

.tags_at(index = :insert) ⇒ Object



294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/ver/methods/control.rb', line 294

def tags_at(index = :insert)
  index = index(index)
  tags = tag_names(index)
  VER.message tags.inspect

  require 'ver/tooltip'

  tooltip = Tk::Tooltip.new(tags.inspect)
  tooltip.show_on(self)

  Tk::After.ms(5000){ tooltip.destroy }
end

.toggle_case(text, count = text.prefix_count) ⇒ Object

Toggle case of the character under the cursor up to count characters forward (count is inclusive the first character). This only works for alphabetic ASCII characters, no other encodings.



100
101
102
103
104
105
# File 'lib/ver/methods/control.rb', line 100

def toggle_case(text, count = text.prefix_count)
  from, to = 'insert', "insert + #{count} chars"
  chunk = text.get(from, to)
  chunk.tr!('a-zA-Z', 'A-Za-z')
  text.replace(from, to, chunk)
end

.unindent_line(text, count = text.prefix_count) ⇒ Object



408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'lib/ver/methods/control.rb', line 408

def unindent_line(text, count = text.prefix_count)
  indent = ' ' * text.options[:shiftwidth]
  replace_from = 'insert linestart'
  replace_to = "insert linestart + #{indent.size} chars"

  Undo.record text do |record|
    count.times do
      line = text.get('insert linestart', 'insert lineend')

      return unless line.start_with?(indent)

      record.replace(replace_from, replace_to, '')
    end
  end
end

.wrap_line(text) ⇒ Object



342
343
344
345
346
347
348
349
# File 'lib/ver/methods/control.rb', line 342

def wrap_line(text)
  content = text.get('insert linestart', 'insert lineend')
  textwidth = text.options.textwidth
  lines = wrap_lines_of(content, textwidth).join("\n")
  lines.rstrip!

  text.replace('insert linestart', 'insert lineend', lines)
end

.wrap_lines_of(content, wrap = 80) ⇒ Object



432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
# File 'lib/ver/methods/control.rb', line 432

def wrap_lines_of(content, wrap = 80)
  Kernel.raise ArgumentError, "+wrap+ must be > 1" unless wrap > 1
  wrap -= 1

  indent = content[/^\s+/] || ''
  indent_size = indent.size
  lines = [indent.dup]

  content.scan(/\S+/) do |chunk|
    last = lines.last
    last_size = last.size
    chunk_size = chunk.size

    if last_size + chunk_size > wrap
      lines << indent + chunk
    elsif last_size == indent_size
      last << chunk
    elsif chunk =~ /\.$/
      last << ' ' << chunk
      lines << indent.dup
    else
      last << ' ' << chunk
    end
  end

  lines
end