textbringer 0.3.2 → 1.0.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
  SHA256:
3
- metadata.gz: 2244343a4baaddd8efff307da619579a102c66d61c14f5dcebdba589b7f809ba
4
- data.tar.gz: 0e59492b0f35673c3d0658d7c96c55288734017ace2edb1c58fddcdf22ca9976
3
+ metadata.gz: 670221472ba70164a2f44759e11011d8e70a5f467e067e4e400d732fe4082323
4
+ data.tar.gz: 26d15a0030cc1217f131ba761309b3d9bb17078fa5cfd1db24c651bdd5384fb1
5
5
  SHA512:
6
- metadata.gz: 680ea08b6a0c55e0a514f8da5708cbbcde48efe50747b9f7fdf96ec39264619abfbfbab32a7ca03577885e8691c2d221e563d2fcd98c8bc3dd4e3cd9b647ac10
7
- data.tar.gz: bac76f72017761cb3c46ff83a0d3f0dee86e811940dc97bd79c6665231f621989c262be1c17ca70d75eb5f1885fd55190062240e5b6d886c29894172a2c3c39c
6
+ metadata.gz: 000e800e06a430312b133dce7017c560723a473866cbb2c82754ac6af1da6f398be2cdf17b9708f20109784b698b70bb073c744afa4d7f7cc0e086b51db17ffc
7
+ data.tar.gz: ccb23431483eabe736e285d9ee72a17f7cb4f72be07fd049ec091f727a5671cd396e30504cd725d0938614a0fd58a56b8c5547a9e4d1275fd8faf8b654c6b25d
data/CHANGES.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 1.0.0
2
+
3
+ * Add mark_whole_buffer.
4
+ * Add zap_to_char.
5
+ * Exit on SIGTERM, SIGHUP etc.
6
+
1
7
  ## 0.3.2
2
8
 
3
9
  * Drop Ruby 2.3 support.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Textbringer
1
+ # ![Textbringer](logo/logo.png)
2
2
 
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)
@@ -18,14 +18,6 @@ text editor.
18
18
  * Ruby Programming: https://asciinema.org/a/100156
19
19
  * Japanese Text Editing: https://asciinema.org/a/100166
20
20
 
21
- ## WARNING
22
-
23
- Textbringer is beta software, and you may lose your text. Unsaved buffers will
24
- be dumped in ~/.textbringer/buffer_dump on crash.
25
-
26
- APIs are undocumented and unstable. There is no compatibility even in the same
27
- minor versions.
28
-
29
21
  ## Installation
30
22
 
31
23
  $ gem install textbringer
@@ -115,3 +107,8 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/shugo/
115
107
  ## License
116
108
 
117
109
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
110
+
111
+
112
+ ## Credit
113
+
114
+ Logo made with [DesignEvo](https://www.designevo.com/en/).
@@ -15,6 +15,11 @@ end
15
15
 
16
16
  $VERBOSE = nil
17
17
 
18
+ unless STDIN.tty?
19
+ STDERR.puts("textbringer: standard input is not a tty")
20
+ exit 1
21
+ end
22
+
18
23
  Controller.current = Controller.new
19
24
  begin
20
25
  Window.start do
@@ -205,7 +205,7 @@ module Textbringer
205
205
  end
206
206
 
207
207
  # s might not be copied.
208
- def initialize(s = String.new, name: nil,
208
+ def initialize(s = +"", name: nil,
209
209
  file_name: nil,
210
210
  file_encoding: CONFIG[:default_file_encoding],
211
211
  file_mtime: nil, new_file: true, undo_limit: UNDO_LIMIT,
@@ -964,7 +964,7 @@ module Textbringer
964
964
 
965
965
  def clear
966
966
  check_read_only_flag
967
- @contents = String.new
967
+ @contents = +""
968
968
  @point = @gap_start = @gap_end = 0
969
969
  @marks.each do |m|
970
970
  m.location = 0
@@ -1065,40 +1065,54 @@ module Textbringer
1065
1065
  end
1066
1066
  end
1067
1067
 
1068
- def re_search_forward(s, raise_error: true)
1068
+ def re_search_forward(s, raise_error: true, count: 1)
1069
+ if count < 0
1070
+ return re_search_backward(s, raise_error: raise_error, count: -count)
1071
+ end
1069
1072
  re = new_regexp(s)
1070
- i = byteindex(true, re, @point)
1071
- if i.nil?
1072
- if raise_error
1073
- raise SearchError, "Search failed"
1074
- else
1075
- return nil
1073
+ pos = @point
1074
+ count.times do
1075
+ i = byteindex(true, re, pos)
1076
+ if i.nil?
1077
+ if raise_error
1078
+ raise SearchError, "Search failed"
1079
+ else
1080
+ return nil
1081
+ end
1076
1082
  end
1083
+ pos = match_end(0)
1077
1084
  end
1078
- goto_char(match_end(0))
1085
+ goto_char(pos)
1079
1086
  end
1080
1087
 
1081
- def re_search_backward(s, raise_error: true)
1088
+ def re_search_backward(s, raise_error: true, count: 1)
1089
+ if count < 0
1090
+ return re_search_forward(s, raise_error: raise_error, count: -count)
1091
+ end
1082
1092
  re = new_regexp(s)
1083
1093
  pos = @point
1084
- begin
1085
- i = byteindex(false, re, pos)
1086
- if i.nil?
1094
+ count.times do
1095
+ p = pos
1096
+ begin
1097
+ i = byteindex(false, re, p)
1098
+ if i.nil?
1099
+ if raise_error
1100
+ raise SearchError, "Search failed"
1101
+ else
1102
+ return nil
1103
+ end
1104
+ end
1105
+ p = get_pos(p, -1)
1106
+ rescue RangeError
1087
1107
  if raise_error
1088
1108
  raise SearchError, "Search failed"
1089
1109
  else
1090
1110
  return nil
1091
1111
  end
1092
- end
1093
- pos = get_pos(pos, -1)
1094
- rescue RangeError
1095
- if raise_error
1096
- raise SearchError, "Search failed"
1097
- else
1098
- return nil
1099
- end
1100
- end while match_end(0) > @point
1101
- goto_char(match_beginning(0))
1112
+ end while match_end(0) > pos
1113
+ pos = match_beginning(0)
1114
+ end
1115
+ goto_char(pos)
1102
1116
  end
1103
1117
 
1104
1118
  def looking_at?(re)
@@ -1233,7 +1247,7 @@ module Textbringer
1233
1247
  end
1234
1248
 
1235
1249
  def gap_filled_with_nul?
1236
- /\A\0*\z/ =~ @contents[@gap_start...@gap_end] ? true : false
1250
+ /\A\0*\z/.match?(@contents[@gap_start...@gap_end])
1237
1251
  end
1238
1252
 
1239
1253
  def composite_edit
@@ -1338,7 +1352,7 @@ module Textbringer
1338
1352
  def gsub(*args, &block)
1339
1353
  if block
1340
1354
  s = to_s.gsub(*args) { |*params|
1341
- set_block_backref(block, $~)
1355
+ block.binding.eval('->(backref) { $~ = backref }').call($~)
1342
1356
  block.call(*params)
1343
1357
  }
1344
1358
  else
@@ -1576,17 +1590,6 @@ module Textbringer
1576
1590
  callback.call(self)
1577
1591
  end
1578
1592
  end
1579
-
1580
- def set_block_backref(block, backref)
1581
- Thread.current[:__textbringer_backref] = backref
1582
- begin
1583
- block.binding.eval(<<-EOC)
1584
- $~ = Thread.current[:__textbringer_backref]
1585
- EOC
1586
- ensure
1587
- Thread.current[:__textbringer_backref] = nil
1588
- end
1589
- end
1590
1593
  end
1591
1594
 
1592
1595
  class Mark
@@ -244,5 +244,27 @@ module Textbringer
244
244
  buffer.insert(" ")
245
245
  buffer.backward_char
246
246
  end
247
+
248
+ define_command(:mark_whole_buffer,
249
+ doc: <<~EOD) do
250
+ Put point at beginning and mark at end of buffer.
251
+ EOD
252
+ buffer = Buffer.current
253
+ buffer.push_mark
254
+ buffer.push_mark(buffer.point_max)
255
+ buffer.beginning_of_buffer
256
+ end
257
+
258
+ define_command(:zap_to_char,
259
+ doc: <<~EOD) do
260
+ Kill up to and including count-th occurrence of char.
261
+ EOD
262
+ |char = read_char, count: number_prefix_arg|
263
+
264
+ buffer = Buffer.current
265
+ s = buffer.point
266
+ e = buffer.re_search_forward(Regexp.quote(char), count: count)
267
+ buffer.kill_region(s, e)
268
+ end
247
269
  end
248
270
  end
@@ -38,7 +38,7 @@ module Textbringer
38
38
 
39
39
  def fill_string(str, column)
40
40
  input = StringIO.new(str)
41
- output = String.new
41
+ output = +""
42
42
  fill_column = CONFIG[:fill_column]
43
43
  prev_c = nil
44
44
  while c = input.getc
@@ -43,7 +43,7 @@ module Textbringer
43
43
 
44
44
  def isearch_mode(forward, recursive_edit: false)
45
45
  ISEARCH_STATUS[:forward] = forward
46
- ISEARCH_STATUS[:string] = String.new
46
+ ISEARCH_STATUS[:string] = +""
47
47
  ISEARCH_STATUS[:recursive_edit] = recursive_edit
48
48
  Controller.current.overriding_map = ISEARCH_MODE_MAP
49
49
  run_hooks(:isearch_mode_hook)
@@ -282,31 +282,35 @@ module Textbringer
282
282
  if CONFIG[:shell_file_name]
283
283
  cmd = [CONFIG[:shell_file_name], CONFIG[:shell_command_switch], cmd]
284
284
  end
285
- Open3.popen2e(*cmd, opts) do |input, output, wait_thread|
285
+ Open3.popen3(*cmd, opts) do |input, output, error, wait_thread|
286
286
  input.close
287
- loop do
288
- status = output.wait_readable(0.5)
289
- if status
290
- begin
291
- s = output.read_nonblock(1024).force_encoding("utf-8").
292
- scrub("\u{3013}").gsub(/\r\n/, "\n")
293
- buffer.insert(s)
294
- Window.redisplay
295
- rescue EOFError
296
- break
297
- rescue Errno::EAGAIN, Errno::EWOULDBLOCK
298
- next
287
+ catch(:finish) do
288
+ loop do
289
+ rs, = IO.select([output, error], nil, nil, 0.5)
290
+ Window.redisplay
291
+ rs&.each do |r|
292
+ begin
293
+ s = r.read_nonblock(1024).force_encoding("utf-8").
294
+ scrub("\u{3013}").gsub(/\r\n/, "\n")
295
+ buffer.insert(s)
296
+ Window.redisplay
297
+ rescue EOFError
298
+ throw(:finish)
299
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK
300
+ Window.redisplay
301
+ next
302
+ end
299
303
  end
300
- end
301
- if received_keyboard_quit?
302
- if signals.empty?
303
- keyboard_quit
304
- else
305
- sig = signals.shift
306
- pid = wait_thread.pid
307
- pid = -pid if /mswin32|mingw32/ !~ RUBY_PLATFORM
308
- message("Send #{sig} to #{pid}")
309
- Process.kill(sig, pid)
304
+ if received_keyboard_quit?
305
+ if signals.empty?
306
+ keyboard_quit
307
+ else
308
+ sig = signals.shift
309
+ pid = wait_thread.pid
310
+ pid = -pid if /mswin32|mingw32/ !~ RUBY_PLATFORM
311
+ message("Send #{sig} to #{pid}")
312
+ Process.kill(sig, pid)
313
+ end
310
314
  end
311
315
  end
312
316
  end
@@ -128,7 +128,7 @@ module Textbringer
128
128
  else
129
129
  wait_files = [STDIN, @next_tick_input]
130
130
  end
131
- files, = IO.select(wait_files, [], [], 1)
131
+ files, = IO.select(wait_files, nil, nil, 1)
132
132
  # KEY_RESIZE may be returned even if STDIN is not included in files.
133
133
  event = read_event_nonblock
134
134
  if event
@@ -178,7 +178,7 @@ module Textbringer
178
178
  return if wait_input(1000)
179
179
  end
180
180
  @echo_immediately = true
181
- s = String.new
181
+ s = +""
182
182
  if @prefix_arg
183
183
  s << "C-u"
184
184
  if @prefix_arg != [4]
@@ -144,6 +144,8 @@ module Textbringer
144
144
  GLOBAL_MAP.define_key("\C-o", :open_line)
145
145
  GLOBAL_MAP.define_key("\em", :back_to_indentation)
146
146
  GLOBAL_MAP.define_key("\e^", :delete_indentation)
147
+ GLOBAL_MAP.define_key("\C-xh", :mark_whole_buffer)
148
+ GLOBAL_MAP.define_key("\ez", :zap_to_char)
147
149
  GLOBAL_MAP.define_key("\C-l", :recenter)
148
150
  GLOBAL_MAP.define_key("\C-v", :scroll_up)
149
151
  GLOBAL_MAP.define_key(:npage, :scroll_up)
@@ -104,7 +104,7 @@ module Textbringer
104
104
  end
105
105
 
106
106
  def show_exception(e)
107
- if e.is_a?(SystemExit)
107
+ if e.is_a?(SystemExit) || e.is_a?(SignalException)
108
108
  raise
109
109
  end
110
110
  if Buffer.current&.name != "*Backtrace*"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Textbringer
4
- VERSION = "0.3.2"
4
+ VERSION = "1.0.0"
5
5
  end
Binary file
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: textbringer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shugo Maeda
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-02-08 00:00:00.000000000 Z
11
+ date: 2019-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: curses
@@ -227,6 +227,8 @@ files:
227
227
  - lib/textbringer/utils.rb
228
228
  - lib/textbringer/version.rb
229
229
  - lib/textbringer/window.rb
230
+ - logo/logo.jpg
231
+ - logo/logo.png
230
232
  - screenshot.png
231
233
  - textbringer.gemspec
232
234
  homepage: https://github.com/shugo/textbringer
@@ -248,8 +250,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
248
250
  - !ruby/object:Gem::Version
249
251
  version: '0'
250
252
  requirements: []
251
- rubyforge_project:
252
- rubygems_version: 3.0.0.beta3
253
+ rubygems_version: 3.1.0.pre1
253
254
  signing_key:
254
255
  specification_version: 4
255
256
  summary: An Emacs-like text editor