textbringer 0.1.4 → 0.1.5

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: c4c0499915d9509f0f2ef8d8b30b8a3c87955c9c
4
- data.tar.gz: 017b6339f497de93887ee252df2b1da9b3c20bae
3
+ metadata.gz: cc327e0ef70cebb198dee6defdcf209902b5af3d
4
+ data.tar.gz: fb3012f45cd4396e2d5fa0538ee62de453bd1faa
5
5
  SHA512:
6
- metadata.gz: 813608d1b0cd0f5a120256a49f5509a75f0d4c8a05c1f803e3b6625f8161f3a249a944fc447e16dc50eb9fb9754f2e8b6ab2d55bca0df4ef9a45887151d04637
7
- data.tar.gz: a3b1267f21be52ef1e9136cc530cf7b0f0cd158d636940d0143980b79a54ef96cefbb354aae2e9eb877942097ee90044e2e8d4991cbfb55671c5f049fc8bb365
6
+ metadata.gz: cbf9922744735e4b1e8f8c1c5e4d00c40f12e5c50b295bfecd95fa8e66ffb8c0de455ff47aa148414f7e99acb599a27ac84fb52c29e0062e9075d39af54cbc15
7
+ data.tar.gz: dd2f32a52ede7bbc6df718689bebbfe403305b9e46b29d46128d7b0ae5bced73830e1ba6a34b66473b19b6cf6d9d95e2eff3292aefe21bb43464bb5cc8ce54ad
data/.gitignore CHANGED
@@ -7,4 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
- tags
10
+ /tags
@@ -5,7 +5,7 @@ rvm:
5
5
  - 2.4.0
6
6
  cache: bundler
7
7
  script:
8
- - bundle exec rake test
8
+ - xvfb-run bundle exec rake test
9
9
  - bundle exec bundle-audit check --update
10
10
  notifications:
11
11
  email:
data/CHANGES.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.1.5
2
+
3
+ * Support clipboard.
4
+ * Added tests.
5
+ * Bug fixes.
6
+
1
7
  ## 0.1.4
2
8
 
3
9
  * Add dabbrev_expand (M-/).
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/textbringer.svg)](https://badge.fury.io/rb/textbringer)
4
4
  [![Build Status](https://travis-ci.org/shugo/textbringer.svg?branch=master)](https://travis-ci.org/shugo/textbringer)
5
5
  [![Build status](https://ci.appveyor.com/api/projects/status/n20vtpfgcgii5jtc?svg=true)](https://ci.appveyor.com/project/shugo31737/textbringer)
6
+ [![codecov](https://codecov.io/gh/shugo/textbringer/branch/master/graph/badge.svg)](https://codecov.io/gh/shugo/textbringer)
6
7
 
7
8
  Textbringer is a member of a demon race that takes on the form of a text
8
9
  editor.
@@ -65,4 +66,3 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/shugo/
65
66
  ## License
66
67
 
67
68
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
68
-
@@ -6,7 +6,18 @@ require_relative "textbringer/window"
6
6
  require_relative "textbringer/keymap"
7
7
  require_relative "textbringer/utils"
8
8
  require_relative "textbringer/commands"
9
+ require_relative "textbringer/commands/buffers"
10
+ require_relative "textbringer/commands/windows"
11
+ require_relative "textbringer/commands/files"
12
+ require_relative "textbringer/commands/misc"
13
+ require_relative "textbringer/commands/isearch"
14
+ require_relative "textbringer/commands/replace"
9
15
  require_relative "textbringer/commands/dabbrev"
10
16
  require_relative "textbringer/commands/ctags"
11
- require_relative "textbringer/modes"
17
+ require_relative "textbringer/commands/clipboard"
18
+ require_relative "textbringer/mode"
19
+ require_relative "textbringer/modes/fundamental_mode"
20
+ require_relative "textbringer/modes/programming_mode"
21
+ require_relative "textbringer/modes/ruby_mode"
22
+ require_relative "textbringer/modes/backtrace_mode"
12
23
  require_relative "textbringer/controller"
@@ -239,7 +239,7 @@ module Textbringer
239
239
  end
240
240
 
241
241
  def file_encoding=(enc)
242
- @file_encoding = enc
242
+ @file_encoding = Encoding.find(enc)
243
243
  @binary = enc == Encoding::ASCII_8BIT
244
244
  end
245
245
 
@@ -1111,8 +1111,9 @@ module Textbringer
1111
1111
  end
1112
1112
 
1113
1113
  def apply_mode(mode_class)
1114
+ @keymap = nil
1114
1115
  @mode = mode_class.new(self)
1115
- run_hooks(mode_class.hook_name)
1116
+ Utils.run_hooks(mode_class.hook_name)
1116
1117
  end
1117
1118
 
1118
1119
  def indent_to(column)
@@ -1397,6 +1398,10 @@ module Textbringer
1397
1398
  def empty?
1398
1399
  @ring.empty?
1399
1400
  end
1401
+
1402
+ def size
1403
+ @ring.size
1404
+ end
1400
1405
  end
1401
1406
 
1402
1407
  KILL_RING = KillRing.new
@@ -26,682 +26,5 @@ module Textbringer
26
26
  end
27
27
  end
28
28
  module_function :undefine_command
29
-
30
- define_command(:version) do
31
- message("Textbringer #{Textbringer::VERSION} "\
32
- "(ruby #{RUBY_VERSION} [#{RUBY_PLATFORM}])")
33
- end
34
-
35
- [
36
- :forward_char,
37
- :backward_char,
38
- :forward_word,
39
- :backward_word,
40
- :next_line,
41
- :previous_line,
42
- :delete_char,
43
- :backward_delete_char,
44
- ].each do |name|
45
- define_command(name) do |n = number_prefix_arg|
46
- Buffer.current.send(name, n)
47
- end
48
- end
49
-
50
- [
51
- :beginning_of_line,
52
- :end_of_line,
53
- :beginning_of_buffer,
54
- :end_of_buffer,
55
- :exchange_point_and_mark,
56
- :copy_region,
57
- :kill_region,
58
- :yank,
59
- :newline,
60
- :delete_region,
61
- :transpose_chars
62
- ].each do |name|
63
- define_command(name) do
64
- Buffer.current.send(name)
65
- end
66
- end
67
-
68
- define_command(:set_mark_command) do
69
- Buffer.current.set_mark
70
- message("Mark set")
71
- end
72
-
73
- define_command(:goto_char) do
74
- |n = read_from_minibuffer("Go to char: ")|
75
- Buffer.current.goto_char(n.to_i)
76
- Window.current.recenter_if_needed
77
- end
78
-
79
- define_command(:goto_line) do
80
- |n = read_from_minibuffer("Go to line: ")|
81
- Buffer.current.goto_line(n.to_i)
82
- Window.current.recenter_if_needed
83
- end
84
-
85
- define_command(:self_insert) do |n = number_prefix_arg|
86
- c = Controller.current.last_key
87
- merge_undo = Controller.current.last_command == :self_insert
88
- n.times do
89
- Buffer.current.insert(c, merge_undo)
90
- end
91
- end
92
-
93
- define_command(:quoted_insert) do |n = number_prefix_arg|
94
- c = Controller.current.read_char
95
- if !c.is_a?(String)
96
- raise "Invalid key"
97
- end
98
- n.times do
99
- Buffer.current.insert(c)
100
- end
101
- end
102
-
103
- define_command(:kill_line) do
104
- Buffer.current.kill_line(Controller.current.last_command == :kill_region)
105
- Controller.current.this_command = :kill_region
106
- end
107
-
108
- define_command(:kill_word) do
109
- Buffer.current.kill_word(Controller.current.last_command == :kill_region)
110
- Controller.current.this_command = :kill_region
111
- end
112
-
113
- define_command(:yank_pop) do
114
- if Controller.current.last_command != :yank
115
- raise EditorError, "Previous command was not a yank"
116
- end
117
- Buffer.current.yank_pop
118
- Controller.current.this_command = :yank
119
- end
120
-
121
- RE_SEARCH_STATUS = {
122
- last_regexp: nil
123
- }
124
-
125
- define_command(:re_search_forward) do
126
- |s = read_from_minibuffer("RE search: ",
127
- default: RE_SEARCH_STATUS[:last_regexp])|
128
- RE_SEARCH_STATUS[:last_regexp] = s
129
- Buffer.current.re_search_forward(s)
130
- end
131
-
132
- define_command(:re_search_backward) do
133
- |s = read_from_minibuffer("RE search backward: ",
134
- default: RE_SEARCH_STATUS[:last_regexp])|
135
- RE_SEARCH_STATUS[:last_regexp] = s
136
- Buffer.current.re_search_backward(s)
137
- end
138
-
139
- def match_beginning(n)
140
- Buffer.current.match_beginning(n)
141
- end
142
-
143
- def match_end(n)
144
- Buffer.current.match_end(n)
145
- end
146
-
147
- def match_string(n)
148
- Buffer.current.match_string(n)
149
- end
150
-
151
- def replace_match(s)
152
- Buffer.current.replace_match(s)
153
- end
154
-
155
- define_command(:query_replace_regexp) do
156
- |regexp = read_from_minibuffer("Query replace regexp: "),
157
- to_str = read_from_minibuffer("with: ")|
158
- n = 0
159
- begin
160
- loop do
161
- re_search_forward(regexp)
162
- Window.current.recenter_if_needed
163
- Buffer.current.set_visible_mark(match_beginning(0))
164
- begin
165
- Window.redisplay
166
- c = read_single_char("Replace?", [?y, ?n, ?!, ?q, ?.])
167
- case c
168
- when ?y
169
- replace_match(to_str)
170
- n += 1
171
- when ?n
172
- # do nothing
173
- when ?!
174
- replace_match(to_str)
175
- n += 1 + Buffer.current.replace_regexp_forward(regexp, to_str)
176
- Buffer.current.merge_undo(2)
177
- break
178
- when ?q
179
- break
180
- when ?.
181
- replace_match(to_str)
182
- n += 1
183
- break
184
- end
185
- ensure
186
- Buffer.current.delete_visible_mark
187
- end
188
- end
189
- rescue SearchError
190
- end
191
- if n == 1
192
- message("Replaced 1 occurrence")
193
- else
194
- message("Replaced #{n} occurrences")
195
- end
196
- end
197
-
198
- define_command(:undo) do
199
- Buffer.current.undo
200
- message("Undo!")
201
- end
202
-
203
- define_command(:redo) do
204
- Buffer.current.redo
205
- message("Redo!")
206
- end
207
-
208
- define_command(:resize_window) do
209
- Window.resize
210
- end
211
-
212
- define_command(:recenter) do
213
- Window.current.recenter
214
- Window.redraw
215
- end
216
-
217
- define_command(:scroll_up) do
218
- Window.current.scroll_up
219
- end
220
-
221
- define_command(:scroll_down) do
222
- Window.current.scroll_down
223
- end
224
-
225
- define_command(:delete_window) do
226
- Window.delete_window
227
- end
228
-
229
- define_command(:delete_other_windows) do
230
- Window.delete_other_windows
231
- end
232
-
233
- define_command(:split_window) do
234
- Window.current.split
235
- end
236
-
237
- define_command(:other_window) do
238
- Window.other_window
239
- end
240
-
241
- define_command(:exit_textbringer) do |status = 0|
242
- if Buffer.any? { |buffer| /\A\*/ !~ buffer.name && buffer.modified? }
243
- return unless yes_or_no?("Unsaved buffers exist; exit anyway?")
244
- end
245
- exit(status)
246
- end
247
-
248
- define_command(:suspend_textbringer) do
249
- Curses.close_screen
250
- Process.kill(:STOP, $$)
251
- end
252
-
253
- define_command(:pwd) do
254
- message(Dir.pwd)
255
- end
256
-
257
- define_command(:chdir) do
258
- |dir_name = read_file_name("Change directory: ")|
259
- Dir.chdir(dir_name)
260
- end
261
-
262
- define_command(:find_file) do
263
- |file_name = read_file_name("Find file: ")|
264
- buffer = Buffer.find_file(file_name)
265
- if buffer.new_file?
266
- message("New file")
267
- end
268
- switch_to_buffer(buffer)
269
- shebang = buffer.save_excursion {
270
- buffer.beginning_of_buffer
271
- buffer.looking_at?(/#!.*$/) ? buffer.match_string(0) : nil
272
- }
273
- mode = Mode.list.find { |m|
274
- (m.file_name_pattern &&
275
- m.file_name_pattern =~ File.basename(buffer.file_name)) ||
276
- (m.interpreter_name_pattern &&
277
- m.interpreter_name_pattern =~ shebang)
278
- } || FundamentalMode
279
- send(mode.command_name)
280
- end
281
-
282
- define_command(:switch_to_buffer) do
283
- |buffer_name = read_buffer("Switch to buffer: ")|
284
- if buffer_name.is_a?(Buffer)
285
- buffer = buffer_name
286
- else
287
- buffer = Buffer[buffer_name]
288
- end
289
- if buffer
290
- Window.current.buffer = Buffer.current = buffer
291
- else
292
- message("No such buffer: #{buffer_name}")
293
- end
294
- end
295
-
296
- define_command(:save_buffer) do
297
- if Buffer.current.file_name.nil?
298
- Buffer.current.file_name = read_file_name("File to save in: ")
299
- next if Buffer.current.file_name.nil?
300
- end
301
- if Buffer.current.file_modified?
302
- unless yes_or_no?("File changed on disk. Save anyway?")
303
- message("Cancelled")
304
- next
305
- end
306
- end
307
- Buffer.current.save
308
- message("Wrote #{Buffer.current.file_name}")
309
- end
310
-
311
- define_command(:write_file) do
312
- |file_name = read_file_name("Write file: ")|
313
- if File.directory?(file_name)
314
- file_name = File.expand_path(Buffer.current.name, file_name)
315
- end
316
- if File.exist?(file_name)
317
- unless y_or_n?("File `#{file_name}' exists; overwrite?")
318
- message("Cancelled")
319
- next
320
- end
321
- end
322
- Buffer.current.save(file_name)
323
- message("Wrote #{Buffer.current.file_name}")
324
- end
325
-
326
- define_command(:kill_buffer) do
327
- |name = read_buffer("Kill buffer: ", default: Buffer.current.name)|
328
- if name.is_a?(Buffer)
329
- buffer = name
330
- else
331
- buffer = Buffer[name]
332
- end
333
- if buffer.modified?
334
- next unless yes_or_no?("The last change is not saved; kill anyway?")
335
- message("Arioch! Arioch! Blood and souls for my Lord Arioch!")
336
- end
337
- buffer.kill
338
- if Buffer.count == 0
339
- buffer = Buffer.new_buffer("*scratch*")
340
- switch_to_buffer(buffer)
341
- elsif Buffer.current.nil?
342
- switch_to_buffer(Buffer.last)
343
- end
344
- end
345
-
346
- define_command(:set_buffer_file_encoding) do
347
- |enc = read_from_minibuffer("File encoding: ",
348
- default: Buffer.current.file_encoding.name)|
349
- Buffer.current.file_encoding = Encoding.find(enc)
350
- end
351
-
352
- define_command(:set_buffer_file_format) do
353
- |format = read_from_minibuffer("File format: ",
354
- default: Buffer.current.file_format.to_s)|
355
- Buffer.current.file_format = format
356
- end
357
-
358
- define_command(:execute_command) do
359
- |cmd = read_command_name("M-x ").strip.intern|
360
- unless Commands.list.include?(cmd)
361
- raise EditorError, "Undefined command: #{cmd}"
362
- end
363
- Controller.current.this_command = cmd
364
- send(cmd)
365
- end
366
-
367
- define_command(:eval_expression) do
368
- |s = read_from_minibuffer("Eval: ")|
369
- message(eval(s, TOPLEVEL_BINDING, "(eval_expression)", 1).inspect)
370
- end
371
-
372
- define_command(:eval_buffer) do
373
- buffer = Buffer.current
374
- result = eval(buffer.to_s, TOPLEVEL_BINDING,
375
- buffer.file_name || buffer.name, 1)
376
- message(result.inspect)
377
- end
378
-
379
- define_command(:eval_region) do
380
- buffer = Buffer.current
381
- b, e = buffer.point, buffer.mark
382
- if e < b
383
- b, e = e, b
384
- end
385
- result = eval(buffer.substring(b, e), TOPLEVEL_BINDING,
386
- "(eval_region)", 1)
387
- message(result.inspect)
388
- end
389
-
390
- define_command(:exit_recursive_edit) do
391
- if @recursive_edit_level == 0
392
- raise EditorError, "No recursive edit is in progress"
393
- end
394
- throw RECURSIVE_EDIT_TAG, false
395
- end
396
-
397
- define_command(:abort_recursive_edit) do
398
- if @recursive_edit_level == 0
399
- raise EditorError, "No recursive edit is in progress"
400
- end
401
- throw RECURSIVE_EDIT_TAG, true
402
- end
403
-
404
- define_command(:top_level) do
405
- throw TOP_LEVEL_TAG
406
- end
407
-
408
- define_command(:complete_minibuffer) do
409
- minibuffer = Buffer.minibuffer
410
- completion_proc = minibuffer[:completion_proc]
411
- if completion_proc
412
- s = completion_proc.call(minibuffer.to_s)
413
- if s
414
- minibuffer.delete_region(minibuffer.point_min,
415
- minibuffer.point_max)
416
- minibuffer.insert(s)
417
- end
418
- end
419
- end
420
-
421
- UNIVERSAL_ARGUMENT_MAP = Keymap.new
422
- (?0..?9).each do |c|
423
- UNIVERSAL_ARGUMENT_MAP.define_key(c, :digit_argument)
424
- GLOBAL_MAP.define_key("\e#{c}", :digit_argument)
425
- end
426
- UNIVERSAL_ARGUMENT_MAP.define_key(?-, :negative_argument)
427
- UNIVERSAL_ARGUMENT_MAP.define_key(?\C-u, :universal_argument_more)
428
-
429
- def universal_argument_mode
430
- set_transient_map(UNIVERSAL_ARGUMENT_MAP)
431
- end
432
-
433
- define_command(:universal_argument) do
434
- Controller.current.prefix_arg = [4]
435
- universal_argument_mode
436
- end
437
-
438
- def current_prefix_arg
439
- Controller.current.current_prefix_arg
440
- end
441
-
442
- def number_prefix_arg
443
- arg = current_prefix_arg
444
- case arg
445
- when Integer
446
- arg
447
- when Array
448
- arg.first
449
- when :-
450
- -1
451
- else
452
- 1
453
- end
454
- end
455
-
456
- define_command(:digit_argument) do
457
- |arg = current_prefix_arg|
458
- n = last_key.to_i
459
- Controller.current.prefix_arg =
460
- case arg
461
- when Integer
462
- arg * 10 + (arg < 0 ? -n : n)
463
- when :-
464
- -n
465
- else
466
- n
467
- end
468
- universal_argument_mode
469
- end
470
-
471
- define_command(:negative_argument) do
472
- |arg = current_prefix_arg|
473
- Controller.current.prefix_arg =
474
- case arg
475
- when Integer
476
- -arg
477
- when :-
478
- nil
479
- else
480
- :-
481
- end
482
- universal_argument_mode
483
- end
484
-
485
- define_command(:universal_argument_more) do
486
- |arg = current_prefix_arg|
487
- Controller.current.prefix_arg =
488
- case arg
489
- when Array
490
- [4 * arg.first]
491
- when :-
492
- [-4]
493
- else
494
- nil
495
- end
496
- if Controller.current.prefix_arg
497
- universal_argument_mode
498
- end
499
- end
500
-
501
- define_command(:keyboard_quit) do
502
- raise Quit
503
- end
504
-
505
- define_command(:recursive_edit) do
506
- Controller.current.recursive_edit
507
- end
508
-
509
- ISEARCH_MODE_MAP = Keymap.new
510
- (?\x20..?\x7e).each do |c|
511
- ISEARCH_MODE_MAP.define_key(c, :isearch_printing_char)
512
- end
513
- ISEARCH_MODE_MAP.define_key(?\t, :isearch_printing_char)
514
- ISEARCH_MODE_MAP.handle_undefined_key do |key|
515
- if key.is_a?(String) && /[\0-\x7f]/ !~ key
516
- :isearch_printing_char
517
- else
518
- nil
519
- end
520
- end
521
- ISEARCH_MODE_MAP.define_key(:backspace, :isearch_delete_char)
522
- ISEARCH_MODE_MAP.define_key(?\C-h, :isearch_delete_char)
523
- ISEARCH_MODE_MAP.define_key(?\C-s, :isearch_repeat_forward)
524
- ISEARCH_MODE_MAP.define_key(?\C-r, :isearch_repeat_backward)
525
- ISEARCH_MODE_MAP.define_key(?\n, :isearch_exit)
526
- ISEARCH_MODE_MAP.define_key(?\C-g, :isearch_abort)
527
-
528
- ISEARCH_STATUS = {
529
- forward: true,
530
- string: "",
531
- last_string: "",
532
- start: 0,
533
- last_pos: 0
534
- }
535
-
536
- define_command(:isearch_forward) do
537
- isearch_mode(true)
538
- end
539
-
540
- define_command(:isearch_backward) do
541
- isearch_mode(false)
542
- end
543
-
544
- def isearch_mode(forward)
545
- ISEARCH_STATUS[:forward] = forward
546
- ISEARCH_STATUS[:string] = String.new
547
- Controller.current.overriding_map = ISEARCH_MODE_MAP
548
- run_hooks(:isearch_mode_hook)
549
- add_hook(:pre_command_hook, :isearch_pre_command_hook)
550
- ISEARCH_STATUS[:start] = ISEARCH_STATUS[:last_pos] = Buffer.current.point
551
- if Buffer.current != Buffer.minibuffer
552
- message(isearch_prompt, log: false)
553
- end
554
- end
555
-
556
- def isearch_prompt
557
- if ISEARCH_STATUS[:forward]
558
- "I-search: "
559
- else
560
- "I-search backward: "
561
- end
562
- end
563
-
564
- def isearch_pre_command_hook
565
- if /\Aisearch_/ !~ Controller.current.this_command
566
- isearch_done
567
- end
568
- end
569
-
570
- def isearch_done
571
- Buffer.current.delete_visible_mark
572
- Controller.current.overriding_map = nil
573
- remove_hook(:pre_command_hook, :isearch_pre_command_hook)
574
- ISEARCH_STATUS[:last_string] = ISEARCH_STATUS[:string]
575
- end
576
-
577
- define_command(:isearch_exit) do
578
- isearch_done
579
- end
580
-
581
- define_command(:isearch_abort) do
582
- goto_char(Buffer.current[:isearch_start])
583
- isearch_done
584
- raise Quit
585
- end
586
-
587
- define_command(:isearch_printing_char) do
588
- c = Controller.current.last_key
589
- ISEARCH_STATUS[:string].concat(c)
590
- isearch_search
591
- end
592
-
593
- define_command(:isearch_delete_char) do
594
- ISEARCH_STATUS[:string].chop!
595
- isearch_search
596
- end
597
-
598
- def isearch_search
599
- forward = ISEARCH_STATUS[:forward]
600
- options = if /\A[A-Z]/ =~ ISEARCH_STATUS[:string]
601
- nil
602
- else
603
- Regexp::IGNORECASE
604
- end
605
- re = Regexp.new(Regexp.quote(ISEARCH_STATUS[:string]), options)
606
- last_pos = ISEARCH_STATUS[:last_pos]
607
- offset = forward ? last_pos : last_pos - ISEARCH_STATUS[:string].bytesize
608
- if Buffer.current.byteindex(forward, re, offset)
609
- if Buffer.current != Buffer.minibuffer
610
- message(isearch_prompt + ISEARCH_STATUS[:string], log: false)
611
- end
612
- Buffer.current.set_visible_mark(forward ? match_beginning(0) :
613
- match_end(0))
614
- goto_char(forward ? match_end(0) : match_beginning(0))
615
- else
616
- if Buffer.current != Buffer.minibuffer
617
- message("Falling " + isearch_prompt + ISEARCH_STATUS[:string],
618
- log: false)
619
- end
620
- end
621
- end
622
-
623
- def isearch_repeat_forward
624
- isearch_repeat(true)
625
- end
626
-
627
- def isearch_repeat_backward
628
- isearch_repeat(false)
629
- end
630
-
631
- def isearch_repeat(forward)
632
- ISEARCH_STATUS[:forward] = forward
633
- ISEARCH_STATUS[:last_pos] = Buffer.current.point
634
- if ISEARCH_STATUS[:string].empty?
635
- ISEARCH_STATUS[:string] = ISEARCH_STATUS[:last_string]
636
- end
637
- isearch_search
638
- end
639
-
640
- define_command(:shell_execute) do
641
- |cmd = read_from_minibuffer("Shell execute: "),
642
- buffer_name = "*Shell output*"|
643
- buffer = Buffer.find_or_new(buffer_name)
644
- switch_to_buffer(buffer)
645
- buffer.read_only = false
646
- buffer.clear
647
- Window.redisplay
648
- signals = [:INT, :TERM, :KILL]
649
- begin
650
- if /mswin32|mingw32/ =~ RUBY_PLATFORM
651
- opts = {}
652
- else
653
- opts = {pgroup: true}
654
- end
655
- Open3.popen2e(cmd, opts) do |input, output, wait_thread|
656
- input.close
657
- loop do
658
- status = output.wait_readable(0.5)
659
- if status == false
660
- break # EOF
661
- end
662
- if status
663
- begin
664
- s = output.read_nonblock(1024).force_encoding("utf-8").
665
- scrub("\u{3013}").gsub(/\r\n/, "\n")
666
- buffer.insert(s)
667
- Window.redisplay
668
- rescue EOFError
669
- break
670
- rescue Errno::EAGAIN, Errno::EWOULDBLOCK
671
- next
672
- end
673
- end
674
- if received_keyboard_quit?
675
- if signals.empty?
676
- keyboard_quit
677
- else
678
- sig = signals.shift
679
- message("Send #{sig} to #{wait_thread.pid}")
680
- Process.kill(sig, -wait_thread.pid)
681
- end
682
- end
683
- end
684
- status = wait_thread.value
685
- pid = status.pid
686
- if status.exited?
687
- code = status.exitstatus
688
- message("Process #{pid} exited with status code #{code}")
689
- elsif status.signaled?
690
- signame = Signal.signame(status.termsig)
691
- message("Process #{pid} was killed by #{signame}")
692
- else
693
- message("Process #{pid} exited")
694
- end
695
- end
696
- ensure
697
- buffer.read_only = true
698
- end
699
- end
700
- end
701
-
702
- class Quit < StandardError
703
- def initialize
704
- super("Quit")
705
- end
706
29
  end
707
30
  end