textbringer 0.3.2 → 1.0.4

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +1 -0
  3. data/.github/workflows/macos.yml +15 -0
  4. data/.github/workflows/ubuntu.yml +25 -0
  5. data/.github/workflows/windows.yml +19 -0
  6. data/CHANGES.md +29 -0
  7. data/README.md +4 -11
  8. data/exe/textbringer +5 -0
  9. data/lib/textbringer.rb +0 -2
  10. data/lib/textbringer/buffer.rb +43 -42
  11. data/lib/textbringer/color.rb +0 -2
  12. data/lib/textbringer/commands.rb +0 -2
  13. data/lib/textbringer/commands/buffers.rb +22 -2
  14. data/lib/textbringer/commands/clipboard.rb +3 -5
  15. data/lib/textbringer/commands/ctags.rb +3 -5
  16. data/lib/textbringer/commands/dabbrev.rb +1 -3
  17. data/lib/textbringer/commands/files.rb +10 -5
  18. data/lib/textbringer/commands/fill.rb +2 -2
  19. data/lib/textbringer/commands/help.rb +25 -18
  20. data/lib/textbringer/commands/isearch.rb +11 -4
  21. data/lib/textbringer/commands/keyboard_macro.rb +0 -2
  22. data/lib/textbringer/commands/misc.rb +29 -27
  23. data/lib/textbringer/commands/register.rb +0 -2
  24. data/lib/textbringer/commands/replace.rb +0 -2
  25. data/lib/textbringer/commands/server.rb +0 -2
  26. data/lib/textbringer/commands/windows.rb +0 -2
  27. data/lib/textbringer/config.rb +0 -2
  28. data/lib/textbringer/controller.rb +2 -4
  29. data/lib/textbringer/errors.rb +0 -2
  30. data/lib/textbringer/face.rb +0 -2
  31. data/lib/textbringer/faces/basic.rb +0 -2
  32. data/lib/textbringer/faces/programming.rb +0 -2
  33. data/lib/textbringer/keymap.rb +44 -26
  34. data/lib/textbringer/mode.rb +0 -2
  35. data/lib/textbringer/modes/backtrace_mode.rb +1 -3
  36. data/lib/textbringer/modes/buffer_list_mode.rb +1 -3
  37. data/lib/textbringer/modes/c_mode.rb +4 -2
  38. data/lib/textbringer/modes/completion_list_mode.rb +1 -3
  39. data/lib/textbringer/modes/fundamental_mode.rb +0 -2
  40. data/lib/textbringer/modes/help_mode.rb +1 -3
  41. data/lib/textbringer/modes/programming_mode.rb +25 -5
  42. data/lib/textbringer/modes/ruby_mode.rb +33 -10
  43. data/lib/textbringer/plugin.rb +0 -2
  44. data/lib/textbringer/ring.rb +0 -2
  45. data/lib/textbringer/utils.rb +8 -7
  46. data/lib/textbringer/version.rb +1 -3
  47. data/lib/textbringer/window.rb +5 -3
  48. data/logo/logo.jpg +0 -0
  49. data/logo/logo.png +0 -0
  50. metadata +12 -9
  51. data/.travis.yml +0 -56
  52. data/appveyor.yml +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2244343a4baaddd8efff307da619579a102c66d61c14f5dcebdba589b7f809ba
4
- data.tar.gz: 0e59492b0f35673c3d0658d7c96c55288734017ace2edb1c58fddcdf22ca9976
3
+ metadata.gz: 1cadae924b2e85758480d58a7f4ba6ff48fc6ac1971039159a8b81a1a0bbbd29
4
+ data.tar.gz: cb981c7fb394e1c4683cd1365f5da1ed1f372c4254d3e9d8ca5782cad18cf167
5
5
  SHA512:
6
- metadata.gz: 680ea08b6a0c55e0a514f8da5708cbbcde48efe50747b9f7fdf96ec39264619abfbfbab32a7ca03577885e8691c2d221e563d2fcd98c8bc3dd4e3cd9b647ac10
7
- data.tar.gz: bac76f72017761cb3c46ff83a0d3f0dee86e811940dc97bd79c6665231f621989c262be1c17ca70d75eb5f1885fd55190062240e5b6d886c29894172a2c3c39c
6
+ metadata.gz: a57df2132fc40661649106e25f523e7f866ae469020fb33b687d1bf05921f0b4f17915271df4745035737b3be0c65d34650ae55af3ca10d4f677d7c2ac4d7715
7
+ data.tar.gz: fd5081ffaa6a8f42466fdc9fd82d6acd4a732941c66d5e2d37fd1c2a66cafba947de668a08ea60ac87f171306aadcaeca6e815991666bcac47ac376a8cd16d73
@@ -0,0 +1 @@
1
+ *.rb diff=ruby
@@ -0,0 +1,15 @@
1
+ name: macos
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: macos-latest
8
+ steps:
9
+ - uses: actions/checkout@master
10
+ - name: Install dependencies
11
+ run: |
12
+ gem install bundler --no-document
13
+ bundle install
14
+ - name: Run test
15
+ run: bundle exec rake test
@@ -0,0 +1,25 @@
1
+ name: ubuntu
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ test:
7
+ strategy:
8
+ matrix:
9
+ ruby: [ head, 2.7, 2.6, 2.5, 2.4 ]
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v2
13
+ - uses: ruby/setup-ruby@v1
14
+ with:
15
+ ruby-version: ${{ matrix.ruby }}
16
+ - name: Install dependencies
17
+ run: |
18
+ sudo apt install libncursesw5-dev
19
+ gem install bundler --no-document
20
+ bundle install
21
+ - name: Run test
22
+ run: xvfb-run bundle exec rake test
23
+ env:
24
+ UPLOAD_TO_CODECOV: 1
25
+ CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}}
@@ -0,0 +1,19 @@
1
+ name: windows
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: windows-latest
8
+ strategy:
9
+ matrix:
10
+ ruby: [ 'mingw', 'mswin', '2.7', '2.6', '2.5' ]
11
+ steps:
12
+ - uses: actions/checkout@v2
13
+ - name: Set up Ruby
14
+ uses: ruby/setup-ruby@v1
15
+ with:
16
+ ruby-version: ${{ matrix.ruby }}
17
+ bundler-cache: true
18
+ - name: Run test
19
+ run: bundle exec rake test
data/CHANGES.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## 1.0.4
2
+
3
+ * Support Ruby 3.0.
4
+ * Do not record backtrace of Quit (C-g).
5
+
6
+ ## 1.0.3
7
+
8
+ * Fix indentation bugs.
9
+ * Fix a bug of fourground! when it is called in the main thread.
10
+
11
+ ## 1.0.2
12
+
13
+ * Add isearch_quoted_insert.
14
+ * Use M- notation instead of ESC in define_key and help.
15
+ * Add indent_new_comment_line_command.
16
+ * Add find_alternate_file.
17
+ * Fix indentation bugs in the Ruby mode.
18
+
19
+ ## 1.0.1
20
+
21
+ * Support pattern matching in the Ruby mode.
22
+ * Bug fixes.
23
+
24
+ ## 1.0.0
25
+
26
+ * Add mark_whole_buffer.
27
+ * Add zap_to_char.
28
+ * Exit on SIGTERM, SIGHUP etc.
29
+
1
30
  ## 0.3.2
2
31
 
3
32
  * Drop Ruby 2.3 support.
data/README.md CHANGED
@@ -1,8 +1,9 @@
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
- [![Build Status](https://travis-ci.org/shugo/textbringer.svg?branch=master)](https://travis-ci.org/shugo/textbringer)
5
- [![Build status](https://ci.appveyor.com/api/projects/status/n20vtpfgcgii5jtc?svg=true)](https://ci.appveyor.com/project/shugo31737/textbringer)
4
+ [![ubuntu](https://github.com/shugo/textbringer/workflows/ubuntu/badge.svg)](https://github.com/shugo/textbringer/actions?query=workflow%3Aubuntu)
5
+ [![windows](https://github.com/shugo/textbringer/workflows/windows/badge.svg)](https://github.com/shugo/textbringer/actions?query=workflow%3Awindows)
6
+ [![macos](https://github.com/shugo/textbringer/workflows/macos/badge.svg)](https://github.com/shugo/textbringer/actions?query=workflow%3Amacos)
6
7
  [![codecov](https://codecov.io/gh/shugo/textbringer/branch/master/graph/badge.svg)](https://codecov.io/gh/shugo/textbringer)
7
8
 
8
9
  Textbringer is a member of a demon race that takes on the form of an Emacs-like
@@ -18,14 +19,6 @@ text editor.
18
19
  * Ruby Programming: https://asciinema.org/a/100156
19
20
  * Japanese Text Editing: https://asciinema.org/a/100166
20
21
 
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
22
  ## Installation
30
23
 
31
24
  $ gem install textbringer
@@ -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
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require_relative "textbringer/version"
4
2
  require_relative "textbringer/config"
5
3
  require_relative "textbringer/errors"
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require "nkf"
4
2
  require "unicode/display_width"
5
3
  require "json"
@@ -205,7 +203,7 @@ def display_width(s)
205
203
  end
206
204
 
207
205
  # s might not be copied.
208
- def initialize(s = String.new, name: nil,
206
+ def initialize(s = +"", name: nil,
209
207
  file_name: nil,
210
208
  file_encoding: CONFIG[:default_file_encoding],
211
209
  file_mtime: nil, new_file: true, undo_limit: UNDO_LIMIT,
@@ -524,7 +522,7 @@ def goto_char(pos)
524
522
  if pos < 0 || pos > size
525
523
  raise RangeError, "Out of buffer"
526
524
  end
527
- if !@binary && /[\x80-\xbf]/n.match?(byte_after(pos))
525
+ if !@binary && byte_after(pos)&.match?(/[\x80-\xbf]/n)
528
526
  raise ArgumentError, "Position is in the middle of a character"
529
527
  end
530
528
  @goal_column = nil
@@ -578,12 +576,12 @@ def insert(x, merge_undo = false)
578
576
 
579
577
  def newline
580
578
  indentation = save_point { |saved|
581
- if /[ \t]/.match?(char_after)
579
+ if char_after&.match?(/[ \t]/)
582
580
  next ""
583
581
  end
584
582
  beginning_of_line
585
583
  s = @point
586
- while /[ \t]/.match?(char_after)
584
+ while char_after&.match?(/[ \t]/)
587
585
  forward_char
588
586
  end
589
587
  str = substring(s, @point)
@@ -964,7 +962,7 @@ def replace(str, start: point_min, end: point_max)
964
962
 
965
963
  def clear
966
964
  check_read_only_flag
967
- @contents = String.new
965
+ @contents = +""
968
966
  @point = @gap_start = @gap_end = 0
969
967
  @marks.each do |m|
970
968
  m.location = 0
@@ -1065,40 +1063,54 @@ def redo
1065
1063
  end
1066
1064
  end
1067
1065
 
1068
- def re_search_forward(s, raise_error: true)
1066
+ def re_search_forward(s, raise_error: true, count: 1)
1067
+ if count < 0
1068
+ return re_search_backward(s, raise_error: raise_error, count: -count)
1069
+ end
1069
1070
  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
1071
+ pos = @point
1072
+ count.times do
1073
+ i = byteindex(true, re, pos)
1074
+ if i.nil?
1075
+ if raise_error
1076
+ raise SearchError, "Search failed"
1077
+ else
1078
+ return nil
1079
+ end
1076
1080
  end
1081
+ pos = match_end(0)
1077
1082
  end
1078
- goto_char(match_end(0))
1083
+ goto_char(pos)
1079
1084
  end
1080
1085
 
1081
- def re_search_backward(s, raise_error: true)
1086
+ def re_search_backward(s, raise_error: true, count: 1)
1087
+ if count < 0
1088
+ return re_search_forward(s, raise_error: raise_error, count: -count)
1089
+ end
1082
1090
  re = new_regexp(s)
1083
1091
  pos = @point
1084
- begin
1085
- i = byteindex(false, re, pos)
1086
- if i.nil?
1092
+ count.times do
1093
+ p = pos
1094
+ begin
1095
+ i = byteindex(false, re, p)
1096
+ if i.nil?
1097
+ if raise_error
1098
+ raise SearchError, "Search failed"
1099
+ else
1100
+ return nil
1101
+ end
1102
+ end
1103
+ p = get_pos(p, -1)
1104
+ rescue RangeError
1087
1105
  if raise_error
1088
1106
  raise SearchError, "Search failed"
1089
1107
  else
1090
1108
  return nil
1091
1109
  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))
1110
+ end while match_end(0) > pos
1111
+ pos = match_beginning(0)
1112
+ end
1113
+ goto_char(pos)
1102
1114
  end
1103
1115
 
1104
1116
  def looking_at?(re)
@@ -1233,7 +1245,7 @@ def transpose_chars
1233
1245
  end
1234
1246
 
1235
1247
  def gap_filled_with_nul?
1236
- /\A\0*\z/ =~ @contents[@gap_start...@gap_end] ? true : false
1248
+ @contents[@gap_start...@gap_end]&.match?(/\A\0*\z/)
1237
1249
  end
1238
1250
 
1239
1251
  def composite_edit
@@ -1338,7 +1350,7 @@ def skip_re_backward(re)
1338
1350
  def gsub(*args, &block)
1339
1351
  if block
1340
1352
  s = to_s.gsub(*args) { |*params|
1341
- set_block_backref(block, $~)
1353
+ block.binding.eval('->(backref) { $~ = backref }').call($~)
1342
1354
  block.call(*params)
1343
1355
  }
1344
1356
  else
@@ -1576,17 +1588,6 @@ def fire_callbacks(name)
1576
1588
  callback.call(self)
1577
1589
  end
1578
1590
  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
1591
  end
1591
1592
 
1592
1593
  class Mark
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require "curses"
4
2
 
5
3
  module Textbringer
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require "open3"
4
2
  require "io/wait"
5
3
 
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Textbringer
4
2
  module Commands
5
3
  define_command(:forward_char,
@@ -244,5 +242,27 @@ module Commands
244
242
  buffer.insert(" ")
245
243
  buffer.backward_char
246
244
  end
245
+
246
+ define_command(:mark_whole_buffer,
247
+ doc: <<~EOD) do
248
+ Put point at beginning and mark at end of buffer.
249
+ EOD
250
+ buffer = Buffer.current
251
+ buffer.push_mark
252
+ buffer.push_mark(buffer.point_max)
253
+ buffer.beginning_of_buffer
254
+ end
255
+
256
+ define_command(:zap_to_char,
257
+ doc: <<~EOD) do
258
+ Kill up to and including count-th occurrence of char.
259
+ EOD
260
+ |char = read_char, count: number_prefix_arg|
261
+
262
+ buffer = Buffer.current
263
+ s = buffer.point
264
+ e = buffer.re_search_forward(Regexp.quote(char), count: count)
265
+ buffer.kill_region(s, e)
266
+ end
247
267
  end
248
268
  end
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Clipboard
4
2
  @implementation = nil
5
3
  end
@@ -13,12 +11,12 @@ module Commands
13
11
  (ENV["DISPLAY"] && system("which xclip > /dev/null 2>&1"))
14
12
 
15
13
  if CLIPBOARD_AVAILABLE
16
- GLOBAL_MAP.define_key("\ew", :clipboard_copy_region)
14
+ GLOBAL_MAP.define_key("\M-w", :clipboard_copy_region)
17
15
  GLOBAL_MAP.define_key("\C-w", :clipboard_kill_region)
18
16
  GLOBAL_MAP.define_key(?\C-k, :clipboard_kill_line)
19
- GLOBAL_MAP.define_key("\ed", :clipboard_kill_word)
17
+ GLOBAL_MAP.define_key("\M-d", :clipboard_kill_word)
20
18
  GLOBAL_MAP.define_key("\C-y", :clipboard_yank)
21
- GLOBAL_MAP.define_key("\ey", :clipboard_yank_pop)
19
+ GLOBAL_MAP.define_key("\M-y", :clipboard_yank_pop)
22
20
  end
23
21
 
24
22
  define_command(:clipboard_copy_region, doc: <<~EOD) do
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Textbringer
4
2
  module Commands
5
3
  CTAGS = {
@@ -51,12 +49,12 @@ module Commands
51
49
  when /\A\d+\z/
52
50
  push_tag_mark_and_find_file(file)
53
51
  goto_line(addr.to_i)
54
- when %r'\A/\^(.*)\$/\z'
52
+ when %r'\A/\^(.*?)(\$)?/\z'
53
+ re = "^" + Regexp.quote($1.gsub(/\\([\\\/])/, "\\1")) + $2.to_s
55
54
  push_tag_mark_and_find_file(file)
56
55
  beginning_of_buffer
57
56
  n.times do
58
- s = Regexp.quote($1.gsub(/\\([\\\/])/, "\\1"))
59
- re_search_forward("^" + s + "$")
57
+ re_search_forward(re)
60
58
  end
61
59
  beginning_of_line
62
60
  when %r'\A\?\^(.*)\$\?\z'
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Textbringer
4
2
  module DabbrevExtension
5
3
  refine Buffer do
@@ -93,7 +91,7 @@ def dabbrev_regexp(stem, candidates)
93
91
  using DabbrevExtension
94
92
 
95
93
  module Commands
96
- GLOBAL_MAP.define_key("\e/", :dabbrev_expand_command)
94
+ GLOBAL_MAP.define_key("\M-/", :dabbrev_expand_command)
97
95
 
98
96
  define_command(:dabbrev_expand_command) do
99
97
  contd = Controller.current.last_command == :dabbrev_expand_command
@@ -1,11 +1,9 @@
1
- # frozen_string_literal: true
2
-
3
1
  require "editorconfig"
4
2
 
5
3
  module Textbringer
6
4
  module Commands
7
5
  define_command(:find_file, doc: "Open or create a file.") do
8
- |file_name = read_file_name("Find file: ")|
6
+ |file_name = read_file_name("Find file: ", default: (Buffer.current.file_name ? File.dirname(Buffer.current.file_name) : Dir.pwd) + "/")|
9
7
  config = EditorConfig.load_file(file_name)
10
8
  buffer = Buffer.find_file(file_name)
11
9
  if buffer.new_file?
@@ -88,12 +86,13 @@ module Commands
88
86
 
89
87
  define_command(:write_file,
90
88
  doc: "Save the current buffer as the specified file.") do
91
- |file_name = read_file_name("Write file: ")|
89
+ |file_name = read_file_name("Write file: ",
90
+ default: Buffer.current.file_name)|
92
91
  if File.directory?(file_name)
93
92
  file_name = File.expand_path(Buffer.current.name, file_name)
94
93
  end
95
94
  if File.exist?(file_name)
96
- unless y_or_n?("File `#{file_name}' exists; overwrite?")
95
+ unless y_or_n?("File exists; overwrite?")
97
96
  message("Cancelled")
98
97
  next
99
98
  end
@@ -126,5 +125,11 @@ module Commands
126
125
  File.dirname(Buffer.current.file_name))|
127
126
  Dir.chdir(dir_name)
128
127
  end
128
+
129
+ define_command(:find_alternate_file, doc: "Find an alternate file.") do
130
+ |file_name = read_file_name("Find alternate file: ",
131
+ default: Buffer.current.file_name)|
132
+ find_file(file_name)
133
+ end
129
134
  end
130
135
  end