textbringer 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +1 -1
- data/CHANGES.md +6 -0
- data/README.md +1 -1
- data/lib/textbringer.rb +12 -1
- data/lib/textbringer/buffer.rb +7 -2
- data/lib/textbringer/commands.rb +0 -677
- data/lib/textbringer/commands/buffers.rb +101 -0
- data/lib/textbringer/commands/clipboard.rb +35 -0
- data/lib/textbringer/commands/ctags.rb +14 -7
- data/lib/textbringer/commands/dabbrev.rb +39 -32
- data/lib/textbringer/commands/files.rb +76 -0
- data/lib/textbringer/commands/isearch.rb +144 -0
- data/lib/textbringer/commands/misc.rb +240 -0
- data/lib/textbringer/commands/replace.rb +82 -0
- data/lib/textbringer/commands/windows.rb +72 -0
- data/lib/textbringer/controller.rb +17 -19
- data/lib/textbringer/errors.rb +6 -0
- data/lib/textbringer/modes/ruby_mode.rb +73 -53
- data/lib/textbringer/utils.rb +21 -7
- data/lib/textbringer/version.rb +1 -1
- data/lib/textbringer/window.rb +27 -9
- data/textbringer.gemspec +6 -3
- metadata +57 -8
- data/lib/textbringer/modes.rb +0 -7
data/lib/textbringer/errors.rb
CHANGED
@@ -20,6 +20,7 @@ module Textbringer
|
|
20
20
|
def indent_line
|
21
21
|
result = false
|
22
22
|
level = calculate_indentation
|
23
|
+
return result if level.nil?
|
23
24
|
@buffer.save_excursion do
|
24
25
|
@buffer.beginning_of_line
|
25
26
|
has_space = @buffer.looking_at?(/[ \t]+/)
|
@@ -88,8 +89,8 @@ module Textbringer
|
|
88
89
|
end
|
89
90
|
end
|
90
91
|
|
91
|
-
def compile
|
92
|
-
|
92
|
+
def compile(cmd = read_from_minibuffer("Compile: ",
|
93
|
+
default: default_compile_command))
|
93
94
|
shell_execute(cmd, "*Ruby compile result*")
|
94
95
|
backtrace_mode
|
95
96
|
end
|
@@ -98,6 +99,59 @@ module Textbringer
|
|
98
99
|
/[\p{Letter}\p{Number}_$@!?]/
|
99
100
|
end
|
100
101
|
|
102
|
+
def default_compile_command
|
103
|
+
@buffer[:ruby_compile_command] ||
|
104
|
+
if File.exist?("Rakefile")
|
105
|
+
prefix = File.exist?("Gemfile") ? "bundle exec " : ""
|
106
|
+
prefix + "rake"
|
107
|
+
elsif @buffer.file_name
|
108
|
+
"ruby " + @buffer.file_name
|
109
|
+
else
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def toggle_test
|
115
|
+
case @buffer.file_name
|
116
|
+
when %r'(.*)/test/(.*/)?test_(.*?)\.rb\z'
|
117
|
+
base = $1
|
118
|
+
namespace = $2
|
119
|
+
name = $3
|
120
|
+
if namespace
|
121
|
+
paths = Dir.glob("#{base}/{lib,app}/**/#{namespace}#{name}.rb")
|
122
|
+
if !paths.empty?
|
123
|
+
find_file(paths.first)
|
124
|
+
return
|
125
|
+
end
|
126
|
+
end
|
127
|
+
paths = Dir.glob("#{base}/{lib,app}/**/#{name}.rb")
|
128
|
+
if !paths.empty?
|
129
|
+
find_file(paths.first)
|
130
|
+
return
|
131
|
+
end
|
132
|
+
raise EditorError, "Test subject not found"
|
133
|
+
when %r'(.*)/(?:lib|app)/(.*/)?(.*?)\.rb\z'
|
134
|
+
base = $1
|
135
|
+
namespace = $2
|
136
|
+
name = $3
|
137
|
+
if namespace
|
138
|
+
paths = Dir.glob("#{base}/test/**/#{namespace}test_#{name}.rb")
|
139
|
+
if !paths.empty?
|
140
|
+
find_file(paths.first)
|
141
|
+
return
|
142
|
+
end
|
143
|
+
end
|
144
|
+
paths = Dir.glob("#{base}/test/**/test_#{name}.rb")
|
145
|
+
if !paths.empty?
|
146
|
+
find_file(paths.first)
|
147
|
+
return
|
148
|
+
end
|
149
|
+
raise EditorError, "Test not found"
|
150
|
+
else
|
151
|
+
raise EditorError, "Unknown file type"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
101
155
|
private
|
102
156
|
|
103
157
|
def calculate_indentation
|
@@ -109,12 +163,29 @@ module Textbringer
|
|
109
163
|
bol_pos = @buffer.point
|
110
164
|
tokens = Ripper.lex(@buffer.substring(@buffer.point_min,
|
111
165
|
@buffer.point))
|
166
|
+
_, event, = tokens.last
|
167
|
+
if event == :on_tstring_beg ||
|
168
|
+
event == :on_heredoc_beg ||
|
169
|
+
event == :on_tstring_content
|
170
|
+
return nil
|
171
|
+
end
|
112
172
|
line, column, event, = find_nearest_beginning_token(tokens)
|
113
173
|
if event == :on_lparen
|
114
174
|
return column + 1
|
115
175
|
end
|
116
176
|
if line
|
117
177
|
@buffer.goto_line(line)
|
178
|
+
while !@buffer.beginning_of_buffer?
|
179
|
+
if @buffer.save_excursion {
|
180
|
+
@buffer.backward_char
|
181
|
+
@buffer.skip_re_backward(/\s/)
|
182
|
+
@buffer.char_before == ?,
|
183
|
+
}
|
184
|
+
@buffer.backward_line
|
185
|
+
else
|
186
|
+
break
|
187
|
+
end
|
188
|
+
end
|
118
189
|
else
|
119
190
|
@buffer.backward_line
|
120
191
|
end
|
@@ -183,56 +254,5 @@ module Textbringer
|
|
183
254
|
end
|
184
255
|
return nil
|
185
256
|
end
|
186
|
-
|
187
|
-
def default_compile_command
|
188
|
-
@buffer[:ruby_compile_command] ||
|
189
|
-
if File.exist?("Rakefile")
|
190
|
-
prefix = File.exist?("Gemfile") ? "bundle exec " : ""
|
191
|
-
prefix + "rake"
|
192
|
-
else
|
193
|
-
"ruby " + @buffer.file_name
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
def toggle_test
|
198
|
-
case @buffer.file_name
|
199
|
-
when %r'(.*)/test/(.*/)?test_(.*?)\.rb\z'
|
200
|
-
base = $1
|
201
|
-
namespace = $2
|
202
|
-
name = $3
|
203
|
-
if namespace
|
204
|
-
paths = Dir.glob("#{base}/{lib,app}/**/#{namespace}#{name}.rb")
|
205
|
-
if !paths.empty?
|
206
|
-
find_file(paths.first)
|
207
|
-
return
|
208
|
-
end
|
209
|
-
end
|
210
|
-
paths = Dir.glob("#{base}/{lib,app}/**/#{name}.rb")
|
211
|
-
if !paths.empty?
|
212
|
-
find_file(paths.first)
|
213
|
-
return
|
214
|
-
end
|
215
|
-
raise EditorError, "Test subject not found"
|
216
|
-
when %r'(.*)/(?:lib|app)/(.*/)?(.*?)\.rb\z'
|
217
|
-
base = $1
|
218
|
-
namespace = $2
|
219
|
-
name = $3
|
220
|
-
if namespace
|
221
|
-
paths = Dir.glob("#{base}/test/**/#{namespace}test_#{name}.rb")
|
222
|
-
if !paths.empty?
|
223
|
-
find_file(paths.first)
|
224
|
-
return
|
225
|
-
end
|
226
|
-
end
|
227
|
-
paths = Dir.glob("#{base}/test/**/#{name}.rb")
|
228
|
-
if !paths.empty?
|
229
|
-
find_file(paths.first)
|
230
|
-
return
|
231
|
-
end
|
232
|
-
raise EditorError, "Test not found"
|
233
|
-
else
|
234
|
-
raise EditorError, "Unknown file type"
|
235
|
-
end
|
236
|
-
end
|
237
257
|
end
|
238
258
|
end
|
data/lib/textbringer/utils.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rbconfig"
|
4
|
+
|
3
5
|
module Textbringer
|
4
6
|
module Utils
|
7
|
+
module_function
|
8
|
+
|
5
9
|
def message(msg, log: true, sit_for: nil, sleep_for: nil)
|
6
10
|
if log && Buffer.current.name != "*Messages*"
|
7
11
|
buffer = Buffer["*Messages*"] ||
|
@@ -15,7 +19,7 @@ module Textbringer
|
|
15
19
|
if buffer.current_line > 1000
|
16
20
|
buffer.beginning_of_buffer
|
17
21
|
10.times do
|
18
|
-
buffer.
|
22
|
+
buffer.forward_line
|
19
23
|
end
|
20
24
|
buffer.delete_region(buffer.point_min, buffer.point)
|
21
25
|
buffer.end_of_buffer
|
@@ -52,7 +56,7 @@ module Textbringer
|
|
52
56
|
Controller.current.received_keyboard_quit?
|
53
57
|
end
|
54
58
|
|
55
|
-
def
|
59
|
+
def show_exception(e)
|
56
60
|
if e.is_a?(SystemExit)
|
57
61
|
raise
|
58
62
|
end
|
@@ -65,8 +69,10 @@ module Textbringer
|
|
65
69
|
begin
|
66
70
|
buffer.delete_region(buffer.point_min, buffer.point_max)
|
67
71
|
buffer.insert("#{e.class}: #{e}\n")
|
68
|
-
e.backtrace
|
69
|
-
|
72
|
+
if e.backtrace
|
73
|
+
e.backtrace.each do |line|
|
74
|
+
buffer.insert(line + "\n")
|
75
|
+
end
|
70
76
|
end
|
71
77
|
buffer.beginning_of_buffer
|
72
78
|
ensure
|
@@ -148,7 +154,7 @@ module Textbringer
|
|
148
154
|
File.expand_path(file)
|
149
155
|
end
|
150
156
|
|
151
|
-
def
|
157
|
+
def complete_for_minibuffer(s, candidates)
|
152
158
|
xs = candidates.select { |i| i.start_with?(s) }
|
153
159
|
if xs.size > 0
|
154
160
|
y, *ys = xs
|
@@ -163,13 +169,13 @@ module Textbringer
|
|
163
169
|
end
|
164
170
|
|
165
171
|
def read_buffer(prompt, default: (Buffer.last || Buffer.current)&.name)
|
166
|
-
f = ->(s) {
|
172
|
+
f = ->(s) { complete_for_minibuffer(s, Buffer.names) }
|
167
173
|
read_from_minibuffer(prompt, completion_proc: f, default: default)
|
168
174
|
end
|
169
175
|
|
170
176
|
def read_command_name(prompt)
|
171
177
|
f = ->(s) {
|
172
|
-
|
178
|
+
complete_for_minibuffer(s.tr("-", "_"), Commands.list.map(&:to_s))
|
173
179
|
}
|
174
180
|
read_from_minibuffer(prompt, completion_proc: f)
|
175
181
|
end
|
@@ -273,5 +279,13 @@ module Textbringer
|
|
273
279
|
add_hook(:pre_command_hook, hook)
|
274
280
|
Controller.current.overriding_map = map
|
275
281
|
end
|
282
|
+
|
283
|
+
def ruby_install_name
|
284
|
+
RbConfig::CONFIG["ruby_install_name"]
|
285
|
+
end
|
286
|
+
|
287
|
+
def insert(s)
|
288
|
+
Buffer.current.insert(s)
|
289
|
+
end
|
276
290
|
end
|
277
291
|
end
|
data/lib/textbringer/version.rb
CHANGED
data/lib/textbringer/window.rb
CHANGED
@@ -191,7 +191,8 @@ module Textbringer
|
|
191
191
|
Curses.beep
|
192
192
|
end
|
193
193
|
|
194
|
-
attr_reader :buffer, :lines, :columns, :y, :x
|
194
|
+
attr_reader :buffer, :lines, :columns, :y, :x, :window, :mode_line
|
195
|
+
attr_reader :top_of_window, :bottom_of_window
|
195
196
|
|
196
197
|
def initialize(lines, columns, y, x)
|
197
198
|
@lines = lines
|
@@ -336,8 +337,9 @@ module Textbringer
|
|
336
337
|
@window.attron(Curses::A_REVERSE)
|
337
338
|
end
|
338
339
|
while !@buffer.end_of_buffer?
|
340
|
+
cury, curx = @window.cury, @window.curx
|
339
341
|
if @buffer.point_at_mark?(point)
|
340
|
-
y, x =
|
342
|
+
y, x = cury, curx
|
341
343
|
if current? && @buffer.visible_mark
|
342
344
|
if @buffer.point_after_mark?(@buffer.visible_mark)
|
343
345
|
@window.attroff(Curses::A_REVERSE)
|
@@ -357,16 +359,31 @@ module Textbringer
|
|
357
359
|
c = @buffer.char_after
|
358
360
|
if c == "\n"
|
359
361
|
@window.clrtoeol
|
360
|
-
break if
|
362
|
+
break if cury == lines - 2 # lines include mode line
|
363
|
+
@window.setpos(cury + 1, 0)
|
364
|
+
@buffer.forward_char
|
365
|
+
next
|
361
366
|
elsif c == "\t"
|
362
|
-
n = calc_tab_width(
|
367
|
+
n = calc_tab_width(curx)
|
363
368
|
c = " " * n
|
364
369
|
else
|
365
370
|
c = escape(c)
|
366
371
|
end
|
372
|
+
if curx < columns - 4
|
373
|
+
newx = nil
|
374
|
+
else
|
375
|
+
newx = curx + Buffer.display_width(c)
|
376
|
+
if newx > columns
|
377
|
+
if cury == lines - 2
|
378
|
+
break
|
379
|
+
else
|
380
|
+
@window.clrtoeol
|
381
|
+
@window.setpos(cury + 1, 0)
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
367
385
|
@window.addstr(c)
|
368
|
-
break if
|
369
|
-
@window.curx == columns
|
386
|
+
break if newx == columns && cury == lines - 2
|
370
387
|
@buffer.forward_char
|
371
388
|
end
|
372
389
|
if current? && @buffer.visible_mark
|
@@ -504,7 +521,7 @@ module Textbringer
|
|
504
521
|
@mode_line.addstr(unicode_codepoint(c))
|
505
522
|
@mode_line.addstr(" #{line},#{column}")
|
506
523
|
@mode_line.addstr(" (#{@buffer.mode&.name || 'None'})")
|
507
|
-
@mode_line.addstr(" " * (
|
524
|
+
@mode_line.addstr(" " * (columns - @mode_line.curx))
|
508
525
|
@mode_line.attroff(Curses::A_REVERSE)
|
509
526
|
@mode_line.noutrefresh
|
510
527
|
end
|
@@ -519,13 +536,13 @@ module Textbringer
|
|
519
536
|
|
520
537
|
def escape(s)
|
521
538
|
if @buffer.binary?
|
522
|
-
s.gsub(/[\0-\b\v-\x1f]/) { |c|
|
539
|
+
s.gsub(/[\0-\b\v-\x1f\x7f]/) { |c|
|
523
540
|
"^" + (c.ord ^ 0x40).chr
|
524
541
|
}.gsub(/[\x80-\xff]/n) { |c|
|
525
542
|
"<%02X>" % c.ord
|
526
543
|
}
|
527
544
|
else
|
528
|
-
s.gsub(/[\0-\b\v-\x1f]/) { |c|
|
545
|
+
s.gsub(/[\0-\b\v-\x1f\x7f]/) { |c|
|
529
546
|
"^" + (c.ord ^ 0x40).chr
|
530
547
|
}
|
531
548
|
end
|
@@ -620,6 +637,7 @@ module Textbringer
|
|
620
637
|
end
|
621
638
|
|
622
639
|
class EchoArea < Window
|
640
|
+
attr_reader :message
|
623
641
|
attr_accessor :prompt
|
624
642
|
attr_writer :active
|
625
643
|
|
data/textbringer.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Shugo Maeda"]
|
10
10
|
spec.email = ["shugo@ruby-lang.org"]
|
11
11
|
|
12
|
-
spec.summary = "
|
13
|
-
spec.description = "Textbringer is a member of a demon race that takes on the form of
|
12
|
+
spec.summary = "An Emacs-like text editor"
|
13
|
+
spec.description = "Textbringer is a member of a demon race that takes on the form of an Emacs-like text editor."
|
14
14
|
spec.homepage = "https://github.com/shugo/textbringer"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
@@ -23,11 +23,14 @@ Gem::Specification.new do |spec|
|
|
23
23
|
|
24
24
|
spec.add_runtime_dependency "curses", "~> 1.1"
|
25
25
|
spec.add_runtime_dependency "unicode-display_width", "~> 1.1"
|
26
|
+
spec.add_runtime_dependency "clipboard", "~> 1.1"
|
27
|
+
spec.add_runtime_dependency "ffi"
|
26
28
|
|
27
29
|
spec.add_development_dependency "bundler", "~> 1.11"
|
28
30
|
spec.add_development_dependency "rake", "~> 10.0"
|
29
|
-
spec.add_development_dependency "simplecov"
|
30
31
|
spec.add_development_dependency "test-unit"
|
32
|
+
spec.add_development_dependency "simplecov"
|
33
|
+
spec.add_development_dependency "codecov"
|
31
34
|
spec.add_development_dependency "bundler-audit"
|
32
35
|
spec.add_development_dependency "guard"
|
33
36
|
spec.add_development_dependency "guard-shell"
|
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.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curses
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: clipboard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: ffi
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: bundler
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +94,20 @@ dependencies:
|
|
66
94
|
- - "~>"
|
67
95
|
- !ruby/object:Gem::Version
|
68
96
|
version: '10.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: test-unit
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
69
111
|
- !ruby/object:Gem::Dependency
|
70
112
|
name: simplecov
|
71
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,7 +123,7 @@ dependencies:
|
|
81
123
|
- !ruby/object:Gem::Version
|
82
124
|
version: '0'
|
83
125
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
126
|
+
name: codecov
|
85
127
|
requirement: !ruby/object:Gem::Requirement
|
86
128
|
requirements:
|
87
129
|
- - ">="
|
@@ -150,8 +192,8 @@ dependencies:
|
|
150
192
|
- - ">="
|
151
193
|
- !ruby/object:Gem::Version
|
152
194
|
version: '0'
|
153
|
-
description: Textbringer is a member of a demon race that takes on the form of
|
154
|
-
editor.
|
195
|
+
description: Textbringer is a member of a demon race that takes on the form of an
|
196
|
+
Emacs-like text editor.
|
155
197
|
email:
|
156
198
|
- shugo@ruby-lang.org
|
157
199
|
executables:
|
@@ -173,14 +215,20 @@ files:
|
|
173
215
|
- lib/textbringer.rb
|
174
216
|
- lib/textbringer/buffer.rb
|
175
217
|
- lib/textbringer/commands.rb
|
218
|
+
- lib/textbringer/commands/buffers.rb
|
219
|
+
- lib/textbringer/commands/clipboard.rb
|
176
220
|
- lib/textbringer/commands/ctags.rb
|
177
221
|
- lib/textbringer/commands/dabbrev.rb
|
222
|
+
- lib/textbringer/commands/files.rb
|
223
|
+
- lib/textbringer/commands/isearch.rb
|
224
|
+
- lib/textbringer/commands/misc.rb
|
225
|
+
- lib/textbringer/commands/replace.rb
|
226
|
+
- lib/textbringer/commands/windows.rb
|
178
227
|
- lib/textbringer/config.rb
|
179
228
|
- lib/textbringer/controller.rb
|
180
229
|
- lib/textbringer/errors.rb
|
181
230
|
- lib/textbringer/keymap.rb
|
182
231
|
- lib/textbringer/mode.rb
|
183
|
-
- lib/textbringer/modes.rb
|
184
232
|
- lib/textbringer/modes/backtrace_mode.rb
|
185
233
|
- lib/textbringer/modes/fundamental_mode.rb
|
186
234
|
- lib/textbringer/modes/programming_mode.rb
|
@@ -209,8 +257,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
257
|
version: '0'
|
210
258
|
requirements: []
|
211
259
|
rubyforge_project:
|
212
|
-
rubygems_version: 2.6.
|
260
|
+
rubygems_version: 2.6.10
|
213
261
|
signing_key:
|
214
262
|
specification_version: 4
|
215
|
-
summary:
|
263
|
+
summary: An Emacs-like text editor
|
216
264
|
test_files: []
|
265
|
+
has_rdoc:
|