textbringer 0.3.2 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
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