textbringer 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 88862bef486e7b3ea0b5b2a410eae26b089b3180
4
- data.tar.gz: cfa7d1c4ca4e19a7f7b648d783f0779ea9469678
3
+ metadata.gz: acc4214c3d7c5b5535435505b2504db1f80d46ba
4
+ data.tar.gz: e0ad741989368ad91ce5d2b5100896297d28a059
5
5
  SHA512:
6
- metadata.gz: '0238827e2f2a54593d541dbbc621d135f9279d153e15120742efa6e775df74e8c0c95ed39366ec2e5833c5d8df0a16cc49279e48ed9c53bdff2e8684dd82d2ac'
7
- data.tar.gz: 4d29f982b2c0f761fce5b607fc11a5081ed029e09f81a2ab43c8664f22535ddafa2346406bec655ccd67d32a824ee77f53c375bf026211c804f1b3c130168d17
6
+ metadata.gz: f4adfeefebf234a5329c2bfda93f8d9ffe4a83fc029a57579fa8e72d58802aa92be479949a1243f540047ad495efa6507dbbd1d1f61cd5c27e8e3f17225160f3
7
+ data.tar.gz: 8edab0edf73fbff79c8a16b62a9863a6aa5ee5867abbc494e9bb261c2885fc5e277ac9957731e80adf8806fbcfa15a8e11096094259f0e4ebf7390ba16e3a21e
@@ -0,0 +1,9 @@
1
+ root = true
2
+
3
+ [*]
4
+ end_of_line = lf
5
+
6
+ [*.rb]
7
+ indent_style = space
8
+ indent_size = 2
9
+
@@ -7,6 +7,9 @@ cache: bundler
7
7
  script:
8
8
  - xvfb-run bundle exec rake test
9
9
  - bundle exec bundle-audit check --update
10
+ env:
11
+ global:
12
+ UPLOAD_TO_CODECOV: 1
10
13
  notifications:
11
14
  email:
12
15
  on_success: never
data/CHANGES.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.1.7
2
+
3
+ * Support EditorConfig.
4
+ * Add CONFIG[:ambiguos_east_asian_width].
5
+ * Add C mode.
6
+ * Add the *Completions* buffer.
7
+ * Echo multi-character commands in the echo area.
8
+
1
9
  ## 0.1.6
2
10
 
3
11
  * Fix bugs of clipboard commands.
data/README.md CHANGED
@@ -1,12 +1,13 @@
1
1
  # Textbringer
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/textbringer.svg)](https://badge.fury.io/rb/textbringer)
4
+ [![Dependency Status](https://gemnasium.com/shugo/textbringer.svg)](https://gemnasium.com/shugo/textbringer)
4
5
  [![Build Status](https://travis-ci.org/shugo/textbringer.svg?branch=master)](https://travis-ci.org/shugo/textbringer)
5
6
  [![Build status](https://ci.appveyor.com/api/projects/status/n20vtpfgcgii5jtc?svg=true)](https://ci.appveyor.com/project/shugo31737/textbringer)
6
7
  [![codecov](https://codecov.io/gh/shugo/textbringer/branch/master/graph/badge.svg)](https://codecov.io/gh/shugo/textbringer)
7
8
 
8
- Textbringer is a member of a demon race that takes on the form of a text
9
- editor.
9
+ Textbringer is a member of a demon race that takes on the form of an Emacs-like
10
+ text editor.
10
11
 
11
12
  ## Demo
12
13
 
@@ -30,27 +31,60 @@ minor versions.
30
31
 
31
32
  You can quit the editor by C-x C-c.
32
33
 
33
- ## Configuration of terminal emulators
34
+ ## Configuration
34
35
 
35
- ### xterm
36
+ ### Meta key
37
+
38
+ You need the following configuration of terminal emulators to use meta key.
39
+
40
+ #### xterm
36
41
 
37
42
  Add the following line to ~/.Xresources.
38
43
 
39
44
  XTerm*metaSendsEscape: true
40
45
 
41
- ### mlterm
46
+ #### mlterm
42
47
 
43
48
  Add the following lines to ~/.mlterm/main.
44
49
 
45
50
  mod_meta_key = alt
46
51
  mod_meta_mode = esc
47
- col_size_of_width_a = 1
48
52
 
49
- ### screen
53
+ ### East asian ambiguous width
54
+
55
+ Add the following line to ~/.textbringer.rb to treat
56
+ [ambiguous characters](http://unicode.org/reports/tr11/#Ambiguous)
57
+ as fullwidth.
58
+
59
+ CONFIG[:east_asian_ambiguous_width] = 2
60
+
61
+ You also need a LD_PRELOAD hack or a modified locale charmap because ncursesw
62
+ uses wcwidth(3).
63
+
64
+ * https://github.com/fumiyas/wcwidth-cjk
65
+ * https://github.com/hamano/locale-eaw
66
+
67
+ xterm, mlterm and screen have their own configuration options.
68
+
69
+ #### xterm
70
+
71
+ Add the following lines to ~/.Xresources.
72
+
73
+ xterm*utf8: 1
74
+ xterm*locale: true
75
+ xterm*cjkWidth: true
76
+
77
+ #### mlterm
78
+
79
+ Add the following line to ~/.mlterm/main.
80
+
81
+ col_size_of_width_a = 2
82
+
83
+ #### screen
50
84
 
51
85
  Add the following line to ~/.screenrc.
52
86
 
53
- cjkwidth off
87
+ cjkwidth on
54
88
 
55
89
  ## Development
56
90
 
@@ -4,10 +4,13 @@ install:
4
4
  - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
5
5
  - gem install bundler --no-document
6
6
  - bundle install
7
+ - ps: Invoke-WebRequest -Uri http://curl.haxx.se/ca/cacert.pem -OutFile C:\projects\textbringer\cacert.pem
7
8
  build: off
8
9
  test_script:
9
10
  - rake
10
11
  deploy: off
11
12
  environment:
13
+ UPLOAD_TO_CODECOV: 1
14
+ SSL_CERT_FILE: C:\projects\textbringer\cacert.pem
12
15
  matrix:
13
16
  - ruby_version: "23-x64"
@@ -19,5 +19,7 @@ require_relative "textbringer/mode"
19
19
  require_relative "textbringer/modes/fundamental_mode"
20
20
  require_relative "textbringer/modes/programming_mode"
21
21
  require_relative "textbringer/modes/ruby_mode"
22
+ require_relative "textbringer/modes/c_mode"
22
23
  require_relative "textbringer/modes/backtrace_mode"
24
+ require_relative "textbringer/modes/completion_list_mode"
23
25
  require_relative "textbringer/controller"
@@ -158,8 +158,20 @@ module Textbringer
158
158
  end
159
159
 
160
160
  def self.display_width(s)
161
- # ncurses seems to treat ambiguous east asian characters as narrow.
162
- Unicode::DisplayWidth.of(s, 1)
161
+ Unicode::DisplayWidth.of(s, CONFIG[:east_asian_ambiguous_width])
162
+ end
163
+
164
+ def expand_tab(s)
165
+ # TOOD: Support multibyte characters
166
+ tw = self[:tab_width]
167
+ fmt = "A#{tw}"
168
+ s.b.gsub(/([^\t]{#{tw}})|([^\t]*)\t/n) {
169
+ [$+].pack(fmt)
170
+ }.force_encoding(Encoding::UTF_8)
171
+ end
172
+
173
+ def display_width(s)
174
+ Buffer.display_width(expand_tab(s))
163
175
  end
164
176
 
165
177
  # s might not be copied.
@@ -615,42 +627,22 @@ module Textbringer
615
627
  end
616
628
 
617
629
  def next_line(n = 1)
618
- if @goal_column
619
- column = @goal_column
620
- else
621
- prev_point = @point
622
- beginning_of_line
623
- column = Buffer.display_width(substring(@point, prev_point))
624
- end
630
+ column = get_goal_column
625
631
  n.times do
626
632
  end_of_line
627
633
  forward_char
628
- s = @point
629
- while !end_of_line? &&
630
- Buffer.display_width(substring(s, @point)) < column
631
- forward_char
632
- end
634
+ adjust_column(column)
633
635
  end
634
636
  @goal_column = column
635
637
  end
636
638
 
637
639
  def previous_line(n = 1)
638
- if @goal_column
639
- column = @goal_column
640
- else
641
- prev_point = @point
642
- beginning_of_line
643
- column = Buffer.display_width(substring(@point, prev_point))
644
- end
640
+ column = get_goal_column
645
641
  n.times do
646
642
  beginning_of_line
647
643
  backward_char
648
644
  beginning_of_line
649
- s = @point
650
- while !end_of_line? &&
651
- Buffer.display_width(substring(s, @point)) < column
652
- forward_char
653
- end
645
+ adjust_column(column)
654
646
  end
655
647
  @goal_column = column
656
648
  end
@@ -968,8 +960,12 @@ module Textbringer
968
960
  end
969
961
 
970
962
  def looking_at?(re)
971
- # TODO: optimization
972
- byteindex(true, re, @point) == @point
963
+ if re.is_a?(Regexp)
964
+ r = Regexp.new("\\G(?:#{re.source})", re.options)
965
+ else
966
+ r = "\\G(?:#{re})"
967
+ end
968
+ byteindex(true, r, @point) == @point
973
969
  end
974
970
 
975
971
  def byteindex(forward, re, pos)
@@ -1300,6 +1296,28 @@ module Textbringer
1300
1296
  end
1301
1297
  end
1302
1298
 
1299
+ def get_goal_column
1300
+ if @goal_column
1301
+ @goal_column
1302
+ else
1303
+ prev_point = @point
1304
+ beginning_of_line
1305
+ display_width(substring(@point, prev_point))
1306
+ end
1307
+ end
1308
+
1309
+ def adjust_column(column)
1310
+ s = @point
1311
+ w = 0
1312
+ while !end_of_line? &&
1313
+ (w = display_width(substring(s, @point))) < column
1314
+ forward_char
1315
+ end
1316
+ if w > column
1317
+ backward_char
1318
+ end
1319
+ end
1320
+
1303
1321
  def write_to_file(f)
1304
1322
  [@contents[0...@gap_start], @contents[@gap_end..-1]].each do |s|
1305
1323
  s.force_encoding(Encoding::UTF_8) unless @binary
@@ -55,9 +55,7 @@ module Textbringer
55
55
  define_command(:self_insert) do |n = number_prefix_arg|
56
56
  c = Controller.current.last_key
57
57
  merge_undo = Controller.current.last_command == :self_insert
58
- n.times do
59
- Buffer.current.insert(c, merge_undo)
60
- end
58
+ Buffer.current.insert(c * n, merge_undo)
61
59
  end
62
60
 
63
61
  define_command(:quoted_insert) do |n = number_prefix_arg|
@@ -65,9 +63,7 @@ module Textbringer
65
63
  if !c.is_a?(String)
66
64
  raise EditorError, "Invalid key"
67
65
  end
68
- n.times do
69
- Buffer.current.insert(c)
70
- end
66
+ Buffer.current.insert(c * n)
71
67
  end
72
68
 
73
69
  define_command(:kill_line) do
@@ -90,12 +86,12 @@ module Textbringer
90
86
 
91
87
  define_command(:undo) do
92
88
  Buffer.current.undo
93
- message("Undo!")
89
+ message("Undo!") unless Window.echo_area.current?
94
90
  end
95
91
 
96
92
  define_command(:redo) do
97
93
  Buffer.current.redo
98
- message("Redo!")
94
+ message("Redo!") unless Window.echo_area.current?
99
95
  end
100
96
  end
101
97
  end
@@ -5,7 +5,7 @@ require "clipboard"
5
5
  module Textbringer
6
6
  module Commands
7
7
  CLIPBOARD_AVAILABLE =
8
- Clipboard.implementation.name != :Linux ||
8
+ Clipboard.implementation.name != "Clipboard::Linux" ||
9
9
  (ENV["DISPLAY"] && system("which xclip > /dev/null 2>&1"))
10
10
 
11
11
  if CLIPBOARD_AVAILABLE
@@ -14,6 +14,7 @@ module Textbringer
14
14
  GLOBAL_MAP.define_key(?\C-k, :clipboard_kill_line)
15
15
  GLOBAL_MAP.define_key("\ed", :clipboard_kill_word)
16
16
  GLOBAL_MAP.define_key("\C-y", :clipboard_yank)
17
+ GLOBAL_MAP.define_key("\ey", :clipboard_yank_pop)
17
18
  end
18
19
 
19
20
  define_command(:clipboard_copy_region) do
@@ -37,12 +38,17 @@ module Textbringer
37
38
  end
38
39
 
39
40
  define_command(:clipboard_yank) do
40
- s = Clipboard.paste.encode(Encoding::UTF_8)
41
+ s = Clipboard.paste.encode(Encoding::UTF_8).gsub(/\r\n/, "\n")
41
42
  if !s.empty? && (KILL_RING.empty? || KILL_RING.current != s)
42
43
  KILL_RING.push(s)
43
44
  end
44
45
  yank
45
46
  Controller.current.this_command = :yank
46
47
  end
48
+
49
+ define_command(:clipboard_yank_pop) do
50
+ yank_pop
51
+ Clipboard.copy(KILL_RING.current)
52
+ end
47
53
  end
48
54
  end
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "editorconfig"
4
+
3
5
  module Textbringer
4
6
  module Commands
5
7
  define_command(:find_file) do
6
8
  |file_name = read_file_name("Find file: ")|
9
+ config = EditorConfig.load_file(file_name)
7
10
  buffer = Buffer.find_file(file_name)
8
11
  if buffer.new_file?
9
12
  message("New file")
@@ -20,6 +23,29 @@ module Textbringer
20
23
  m.interpreter_name_pattern =~ shebang)
21
24
  } || FundamentalMode
22
25
  send(mode.command_name)
26
+ if config.key?("charset")
27
+ Buffer.current.file_encoding = config["charset"]
28
+ end
29
+ if config.key?("end_of_line")
30
+ Buffer.current.file_format =
31
+ case config["end_of_line"]
32
+ when "lf"
33
+ :unix
34
+ when "crlf"
35
+ :dos
36
+ when "cr"
37
+ :mac
38
+ end
39
+ end
40
+ if config.key?("indent_style")
41
+ Buffer.current[:indent_tabs_mode] = config["indent_style"] == "tab"
42
+ end
43
+ if config.key?("indent_size")
44
+ Buffer.current[:indent_level] = config["indent_size"].to_i
45
+ end
46
+ if config.key?("tab_width")
47
+ Buffer.current[:tab_width] = config["tab_width"].to_i
48
+ end
23
49
  end
24
50
 
25
51
  define_command(:save_buffer) do
@@ -77,15 +77,66 @@ module Textbringer
77
77
  raise Quit
78
78
  end
79
79
 
80
+ def update_completions(xs)
81
+ if xs.size > 1
82
+ if COMPLETION[:original_buffer].nil?
83
+ COMPLETION[:completions_window] = Window.windows[-2]
84
+ COMPLETION[:original_buffer] =
85
+ COMPLETION[:completions_window].buffer
86
+ end
87
+ completions = Buffer.find_or_new("*Completions*", undo_limit: 0)
88
+ if !completions.mode.is_a?(CompletionListMode)
89
+ completions.apply_mode(CompletionListMode)
90
+ end
91
+ completions.read_only = false
92
+ begin
93
+ completions.clear
94
+ xs.each do |x|
95
+ completions.insert(x + "\n")
96
+ end
97
+ COMPLETION[:completions_window].buffer = completions
98
+ ensure
99
+ completions.read_only = true
100
+ end
101
+ else
102
+ if COMPLETION[:original_buffer]
103
+ COMPLETION[:completions_window].buffer =
104
+ COMPLETION[:original_buffer]
105
+ end
106
+ end
107
+ end
108
+ private :update_completions
109
+
110
+ def complete_minibuffer_with_string(s)
111
+ minibuffer = Buffer.minibuffer
112
+ if s.start_with?(minibuffer.to_s)
113
+ minibuffer.insert(s[minibuffer.to_s.size..-1])
114
+ else
115
+ minibuffer.delete_region(minibuffer.point_min,
116
+ minibuffer.point_max)
117
+ minibuffer.insert(s)
118
+ end
119
+ end
120
+ private :complete_minibuffer_with_string
121
+
80
122
  define_command(:complete_minibuffer) do
81
123
  minibuffer = Buffer.minibuffer
82
124
  completion_proc = minibuffer[:completion_proc]
83
125
  if completion_proc
84
- s = completion_proc.call(minibuffer.to_s)
126
+ xs = completion_proc.call(minibuffer.to_s)
127
+ update_completions(xs)
128
+ if xs.empty?
129
+ message("No match", sit_for: 1)
130
+ return
131
+ end
132
+ y, *ys = xs
133
+ s = y.size.downto(1).lazy.map { |i|
134
+ y[0, i]
135
+ }.find { |i|
136
+ ys.all? { |j| j.start_with?(i) }
137
+ }
85
138
  if s
86
- minibuffer.delete_region(minibuffer.point_min,
87
- minibuffer.point_max)
88
- minibuffer.insert(s)
139
+ complete_minibuffer_with_string(s)
89
140
  end
90
141
  end
91
142
  end
@@ -184,18 +235,11 @@ module Textbringer
184
235
  Window.redisplay
185
236
  signals = [:INT, :TERM, :KILL]
186
237
  begin
187
- if /mswin32|mingw32/ =~ RUBY_PLATFORM
188
- opts = {}
189
- else
190
- opts = {pgroup: true}
191
- end
238
+ opts = /mswin32|mingw32/ =~ RUBY_PLATFORM ? {} : {pgroup: true}
192
239
  Open3.popen2e(cmd, opts) do |input, output, wait_thread|
193
240
  input.close
194
241
  loop do
195
242
  status = output.wait_readable(0.5)
196
- if status == false
197
- break # EOF
198
- end
199
243
  if status
200
244
  begin
201
245
  s = output.read_nonblock(1024).force_encoding("utf-8").
@@ -228,8 +272,6 @@ module Textbringer
228
272
  elsif status.signaled?
229
273
  signame = Signal.signame(status.termsig)
230
274
  message("Process #{pid} was killed by #{signame}")
231
- else
232
- message("Process #{pid} exited")
233
275
  end
234
276
  end
235
277
  ensure