textbringer 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +22 -8
- data/CHANGES.md +11 -0
- data/Guardfile +1 -1
- data/exe/tbtags +26 -0
- data/exe/textbringer +1 -0
- data/lib/textbringer.rb +6 -0
- data/lib/textbringer/buffer.rb +158 -83
- data/lib/textbringer/commands.rb +18 -6
- data/lib/textbringer/commands/buffers.rb +187 -43
- data/lib/textbringer/commands/clipboard.rb +23 -6
- data/lib/textbringer/commands/ctags.rb +3 -23
- data/lib/textbringer/commands/files.rb +10 -7
- data/lib/textbringer/commands/help.rb +114 -0
- data/lib/textbringer/commands/isearch.rb +13 -7
- data/lib/textbringer/commands/keyboard_macro.rb +86 -0
- data/lib/textbringer/commands/misc.rb +43 -2
- data/lib/textbringer/commands/register.rb +128 -0
- data/lib/textbringer/commands/replace.rb +4 -3
- data/lib/textbringer/commands/windows.rb +49 -22
- data/lib/textbringer/config.rb +2 -1
- data/lib/textbringer/controller.rb +89 -23
- data/lib/textbringer/keymap.rb +60 -2
- data/lib/textbringer/modes/help_mode.rb +42 -0
- data/lib/textbringer/modes/programming_mode.rb +35 -28
- data/lib/textbringer/modes/ruby_mode.rb +28 -10
- data/lib/textbringer/plugin.rb +21 -0
- data/lib/textbringer/ring.rb +84 -0
- data/lib/textbringer/utils.rb +28 -0
- data/lib/textbringer/version.rb +1 -1
- data/lib/textbringer/window.rb +59 -5
- data/textbringer.gemspec +1 -1
- metadata +12 -4
data/lib/textbringer/commands.rb
CHANGED
@@ -4,26 +4,38 @@ require "open3"
|
|
4
4
|
require "io/wait"
|
5
5
|
|
6
6
|
module Textbringer
|
7
|
+
Command = Struct.new(:name, :block, :doc)
|
8
|
+
|
7
9
|
module Commands
|
8
10
|
include Utils
|
9
11
|
|
10
|
-
|
12
|
+
@command_table = {}
|
11
13
|
|
12
14
|
def self.list
|
13
|
-
|
15
|
+
@command_table.keys
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.command_table
|
19
|
+
@command_table
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.[](name)
|
23
|
+
@command_table[name.intern]
|
14
24
|
end
|
15
25
|
|
16
|
-
def define_command(name, &block)
|
26
|
+
def define_command(name, doc: "No documentation", &block)
|
27
|
+
name = name.intern
|
17
28
|
Commands.send(:define_method, name, &block)
|
18
|
-
|
29
|
+
Commands.command_table[name] = Command.new(name, block, doc)
|
19
30
|
name
|
20
31
|
end
|
21
32
|
module_function :define_command
|
22
33
|
|
23
34
|
def undefine_command(name)
|
24
|
-
|
35
|
+
name = name.intern
|
36
|
+
if Commands.command_table.key?(name)
|
25
37
|
Commands.send(:undef_method, name)
|
26
|
-
|
38
|
+
Commands.command_table.delete(name)
|
27
39
|
end
|
28
40
|
end
|
29
41
|
module_function :undefine_command
|
@@ -2,63 +2,175 @@
|
|
2
2
|
|
3
3
|
module Textbringer
|
4
4
|
module Commands
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
define_command(name) do |n = number_prefix_arg|
|
16
|
-
Buffer.current.send(name, n)
|
17
|
-
end
|
5
|
+
define_command(:forward_char,
|
6
|
+
doc: "Move point n characters forward.") do
|
7
|
+
|n = number_prefix_arg|
|
8
|
+
Buffer.current.forward_char(n)
|
9
|
+
end
|
10
|
+
|
11
|
+
define_command(:backward_char,
|
12
|
+
doc: "Move point n characters backward.") do
|
13
|
+
|n = number_prefix_arg|
|
14
|
+
Buffer.current.backward_char(n)
|
18
15
|
end
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
17
|
+
define_command(:forward_word,
|
18
|
+
doc: "Move point n words forward.") do
|
19
|
+
|n = number_prefix_arg|
|
20
|
+
Buffer.current.forward_word(n)
|
21
|
+
end
|
22
|
+
|
23
|
+
define_command(:backward_word,
|
24
|
+
doc: "Move point n words backward.") do
|
25
|
+
|n = number_prefix_arg|
|
26
|
+
Buffer.current.backward_word(n)
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
define_command(:next_line,
|
31
|
+
doc: "Move point n lines forward.") do
|
32
|
+
|n = number_prefix_arg|
|
33
|
+
Buffer.current.next_line(n)
|
34
|
+
end
|
35
|
+
|
36
|
+
define_command(:previous_line,
|
37
|
+
doc: "Move point n lines backward.") do
|
38
|
+
|n = number_prefix_arg|
|
39
|
+
Buffer.current.previous_line(n)
|
40
|
+
end
|
41
|
+
|
42
|
+
define_command(:delete_char,
|
43
|
+
doc: "Delete n characters forward.") do
|
44
|
+
|n = number_prefix_arg|
|
45
|
+
Buffer.current.delete_char(n)
|
46
|
+
end
|
47
|
+
|
48
|
+
define_command(:backward_delete_char,
|
49
|
+
doc: "Delete n characters backward.") do
|
50
|
+
|n = number_prefix_arg|
|
51
|
+
Buffer.current.backward_delete_char(n)
|
52
|
+
end
|
53
|
+
|
54
|
+
define_command(:beginning_of_line,
|
55
|
+
doc: "Move point to the beginning of the current line.") do
|
56
|
+
Buffer.current.beginning_of_line
|
36
57
|
end
|
37
58
|
|
38
|
-
define_command(:
|
39
|
-
|
40
|
-
|
59
|
+
define_command(:end_of_line,
|
60
|
+
doc: "Move point to the end of the current line.") do
|
61
|
+
Buffer.current.end_of_line
|
41
62
|
end
|
42
63
|
|
43
|
-
define_command(:
|
44
|
-
|
45
|
-
Buffer.current.
|
64
|
+
define_command(:beginning_of_buffer,
|
65
|
+
doc: "Move point to the beginning of the buffer.") do
|
66
|
+
Buffer.current.beginning_of_buffer
|
67
|
+
end
|
68
|
+
|
69
|
+
define_command(:end_of_buffer,
|
70
|
+
doc: "Move point to the end of the buffer.") do
|
71
|
+
Buffer.current.end_of_buffer
|
72
|
+
end
|
73
|
+
|
74
|
+
define_command(:push_mark,
|
75
|
+
doc: <<~EOD) do
|
76
|
+
Set mark at pos, and push the mark on the mark ring.
|
77
|
+
Unlike Emacs, the new mark is pushed on the mark ring instead of
|
78
|
+
the old one.
|
79
|
+
EOD
|
80
|
+
|pos = Buffer.current.point|
|
81
|
+
Buffer.current.push_mark(pos)
|
82
|
+
end
|
83
|
+
|
84
|
+
define_command(:pop_mark,
|
85
|
+
doc: "Pop the mark from the mark ring.") do
|
86
|
+
Buffer.current.pop_mark
|
87
|
+
end
|
88
|
+
|
89
|
+
define_command(:pop_to_mark,
|
90
|
+
doc: <<~EOD) do
|
91
|
+
Move point to where the mark is, and pop the mark from
|
92
|
+
the mark ring.
|
93
|
+
EOD
|
94
|
+
Buffer.current.pop_to_mark
|
95
|
+
end
|
96
|
+
|
97
|
+
define_command(:exchange_point_and_mark,
|
98
|
+
doc: "Exchange the positions of point and mark.") do
|
99
|
+
Buffer.current.exchange_point_and_mark
|
100
|
+
end
|
101
|
+
|
102
|
+
define_command(:copy_region,
|
103
|
+
doc: "Copy the region to the kill ring.") do
|
104
|
+
Buffer.current.copy_region
|
105
|
+
end
|
106
|
+
|
107
|
+
define_command(:kill_region,
|
108
|
+
doc: "Copy and delete the region.") do
|
109
|
+
Buffer.current.kill_region
|
110
|
+
end
|
111
|
+
|
112
|
+
define_command(:yank,
|
113
|
+
doc: "Insert the last text copied in the kill ring.") do
|
114
|
+
Buffer.current.yank
|
115
|
+
end
|
116
|
+
|
117
|
+
define_command(:newline,
|
118
|
+
doc: "Insert a newline.") do
|
119
|
+
Buffer.current.newline
|
120
|
+
end
|
121
|
+
|
122
|
+
define_command(:delete_region,
|
123
|
+
doc: "Delete the region without copying.") do
|
124
|
+
Buffer.current.delete_region
|
125
|
+
end
|
126
|
+
|
127
|
+
define_command(:transpose_chars,
|
128
|
+
doc: "Transpose characters.") do
|
129
|
+
Buffer.current.transpose_chars
|
130
|
+
end
|
131
|
+
|
132
|
+
define_command(:set_mark_command,
|
133
|
+
doc: <<~EOD) do
|
134
|
+
Set the mark at point.
|
135
|
+
|
136
|
+
With C-u, move point to where the mark is, and pop the mark from
|
137
|
+
the mark ring.
|
138
|
+
EOD
|
139
|
+
|arg = current_prefix_arg|
|
140
|
+
buffer = Buffer.current
|
141
|
+
if arg
|
142
|
+
buffer.pop_to_mark
|
143
|
+
else
|
144
|
+
buffer.push_mark
|
145
|
+
message("Mark set")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
define_command(:goto_char,
|
150
|
+
doc: "Move point to pos.") do
|
151
|
+
|pos = read_from_minibuffer("Go to char: ")|
|
152
|
+
Buffer.current.goto_char(pos.to_i)
|
46
153
|
Window.current.recenter_if_needed
|
47
154
|
end
|
48
155
|
|
49
|
-
define_command(:goto_line
|
156
|
+
define_command(:goto_line,
|
157
|
+
doc: "Move point to line n.") do
|
50
158
|
|n = read_from_minibuffer("Go to line: ")|
|
51
159
|
Buffer.current.goto_line(n.to_i)
|
52
160
|
Window.current.recenter_if_needed
|
53
161
|
end
|
54
162
|
|
55
|
-
define_command(:self_insert
|
163
|
+
define_command(:self_insert,
|
164
|
+
doc: "Insert the character typed.") do
|
165
|
+
|n = number_prefix_arg|
|
56
166
|
c = Controller.current.last_key
|
57
167
|
merge_undo = Controller.current.last_command == :self_insert
|
58
168
|
Buffer.current.insert(c * n, merge_undo)
|
59
169
|
end
|
60
170
|
|
61
|
-
define_command(:quoted_insert
|
171
|
+
define_command(:quoted_insert,
|
172
|
+
doc: "Read a character, and insert it.") do
|
173
|
+
|n = number_prefix_arg|
|
62
174
|
c = Controller.current.read_char
|
63
175
|
if !c.is_a?(String)
|
64
176
|
raise EditorError, "Invalid key"
|
@@ -66,17 +178,22 @@ module Textbringer
|
|
66
178
|
Buffer.current.insert(c * n)
|
67
179
|
end
|
68
180
|
|
69
|
-
define_command(:kill_line
|
181
|
+
define_command(:kill_line,
|
182
|
+
doc: "Kill the rest of the current line.") do
|
70
183
|
Buffer.current.kill_line(Controller.current.last_command == :kill_region)
|
71
184
|
Controller.current.this_command = :kill_region
|
72
185
|
end
|
73
186
|
|
74
|
-
define_command(:kill_word
|
187
|
+
define_command(:kill_word,
|
188
|
+
doc: "Kill a word.") do
|
75
189
|
Buffer.current.kill_word(Controller.current.last_command == :kill_region)
|
76
190
|
Controller.current.this_command = :kill_region
|
77
191
|
end
|
78
192
|
|
79
|
-
define_command(:yank_pop
|
193
|
+
define_command(:yank_pop,
|
194
|
+
doc: <<~EOD) do
|
195
|
+
Rotate the kill ring, and replace the yanked text.
|
196
|
+
EOD
|
80
197
|
if Controller.current.last_command != :yank
|
81
198
|
raise EditorError, "Previous command was not a yank"
|
82
199
|
end
|
@@ -84,14 +201,41 @@ module Textbringer
|
|
84
201
|
Controller.current.this_command = :yank
|
85
202
|
end
|
86
203
|
|
87
|
-
define_command(:undo
|
204
|
+
define_command(:undo,
|
205
|
+
doc: "Undo changes.") do
|
88
206
|
Buffer.current.undo
|
89
207
|
message("Undo!") unless Window.echo_area.current?
|
90
208
|
end
|
91
209
|
|
92
|
-
define_command(:
|
210
|
+
define_command(:redo_command,
|
211
|
+
doc: "Redo changes reverted by undo.") do
|
93
212
|
Buffer.current.redo
|
94
213
|
message("Redo!") unless Window.echo_area.current?
|
95
214
|
end
|
215
|
+
|
216
|
+
define_command(:back_to_indentation,
|
217
|
+
doc: "Move point to the first non-space character.") do
|
218
|
+
buffer = Buffer.current
|
219
|
+
buffer.beginning_of_line
|
220
|
+
while /[ \t]/ =~ buffer.char_after
|
221
|
+
buffer.forward_char
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
define_command(:delete_indentation,
|
226
|
+
doc: <<~EOD) do
|
227
|
+
Delete indentation and join the current line to the previous line.
|
228
|
+
EOD
|
229
|
+
buffer = Buffer.current
|
230
|
+
back_to_indentation
|
231
|
+
pos = buffer.point
|
232
|
+
buffer.skip_re_backward(/[^\n]/)
|
233
|
+
return if buffer.beginning_of_buffer?
|
234
|
+
buffer.backward_char
|
235
|
+
buffer.skip_re_backward(/[ \t]/)
|
236
|
+
buffer.delete_region(buffer.point, pos)
|
237
|
+
buffer.insert(" ")
|
238
|
+
buffer.backward_char
|
239
|
+
end
|
96
240
|
end
|
97
241
|
end
|
@@ -21,27 +21,41 @@ module Textbringer
|
|
21
21
|
GLOBAL_MAP.define_key("\ey", :clipboard_yank_pop)
|
22
22
|
end
|
23
23
|
|
24
|
-
define_command(:clipboard_copy_region) do
|
24
|
+
define_command(:clipboard_copy_region, doc: <<~EOD) do
|
25
|
+
Copy the region to the kill ring and the clipboard.
|
26
|
+
EOD
|
25
27
|
copy_region
|
26
28
|
Clipboard.copy(KILL_RING.current)
|
27
29
|
end
|
28
30
|
|
29
|
-
define_command(:clipboard_kill_region) do
|
31
|
+
define_command(:clipboard_kill_region, doc: <<~EOD) do
|
32
|
+
Copy the region to the kill ring and the clipboard, and delete
|
33
|
+
the region.
|
34
|
+
EOD
|
30
35
|
kill_region
|
31
36
|
Clipboard.copy(KILL_RING.current)
|
32
37
|
end
|
33
38
|
|
34
|
-
define_command(:clipboard_kill_line) do
|
39
|
+
define_command(:clipboard_kill_line, doc: <<~EOD) do
|
40
|
+
Kill the rest of the current line, and copy the killed text to
|
41
|
+
the clipboard.
|
42
|
+
EOD
|
35
43
|
kill_line
|
36
44
|
Clipboard.copy(KILL_RING.current)
|
37
45
|
end
|
38
46
|
|
39
|
-
define_command(:clipboard_kill_word) do
|
47
|
+
define_command(:clipboard_kill_word, doc: <<~EOD) do
|
48
|
+
Kill a word, and copy the word to the clipboard.
|
49
|
+
EOD
|
40
50
|
kill_word
|
41
51
|
Clipboard.copy(KILL_RING.current)
|
42
52
|
end
|
43
53
|
|
44
|
-
define_command(:clipboard_yank) do
|
54
|
+
define_command(:clipboard_yank, doc: <<~EOD) do
|
55
|
+
If the clipboard contents are different from the last killed text,
|
56
|
+
push the contents to the kill ring, and insert it.
|
57
|
+
Otherwise, just insert the last text copied in the kill ring.
|
58
|
+
EOD
|
45
59
|
s = Clipboard.paste.encode(Encoding::UTF_8).gsub(/\r\n/, "\n")
|
46
60
|
if !s.empty? && (KILL_RING.empty? || KILL_RING.current != s)
|
47
61
|
KILL_RING.push(s)
|
@@ -50,7 +64,10 @@ module Textbringer
|
|
50
64
|
Controller.current.this_command = :yank
|
51
65
|
end
|
52
66
|
|
53
|
-
define_command(:clipboard_yank_pop) do
|
67
|
+
define_command(:clipboard_yank_pop, doc: <<~EOD) do
|
68
|
+
Rotate the kill ring, and replace the yanked text, and copy
|
69
|
+
the text to the clipboard.
|
70
|
+
EOD
|
54
71
|
yank_pop
|
55
72
|
Clipboard.copy(KILL_RING.current)
|
56
73
|
end
|
@@ -2,9 +2,6 @@
|
|
2
2
|
|
3
3
|
module Textbringer
|
4
4
|
module Commands
|
5
|
-
GLOBAL_MAP.define_key("\e.", :find_tag)
|
6
|
-
GLOBAL_MAP.define_key("\e*", :pop_tag_mark)
|
7
|
-
|
8
5
|
CTAGS = {
|
9
6
|
path: nil,
|
10
7
|
tags: nil,
|
@@ -58,7 +55,8 @@ module Textbringer
|
|
58
55
|
push_tag_mark_and_find_file(file)
|
59
56
|
beginning_of_buffer
|
60
57
|
n.times do
|
61
|
-
|
58
|
+
s = Regexp.quote($1.gsub(/\\([\\\/])/, "\\1"))
|
59
|
+
re_search_forward("^" + s + "$")
|
62
60
|
end
|
63
61
|
beginning_of_line
|
64
62
|
when %r'\A\?\^(.*)\$\?\z'
|
@@ -92,28 +90,10 @@ module Textbringer
|
|
92
90
|
CTAGS[:tags]
|
93
91
|
end
|
94
92
|
|
95
|
-
define_command(:pop_tag_mark) do
|
96
|
-
tag_mark_stack = CTAGS[:tag_mark_stack]
|
97
|
-
if tag_mark_stack.empty?
|
98
|
-
raise EditorError, "No previous locations"
|
99
|
-
end
|
100
|
-
mark = tag_mark_stack.pop
|
101
|
-
begin
|
102
|
-
switch_to_buffer(mark.buffer)
|
103
|
-
mark.buffer.point_to_mark(mark)
|
104
|
-
ensure
|
105
|
-
mark.delete
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
93
|
private
|
110
94
|
|
111
95
|
def push_tag_mark_and_find_file(file)
|
112
|
-
|
113
|
-
if tag_mark_stack.size == CONFIG[:tag_mark_limit]
|
114
|
-
tag_mark_stack.shift.delete
|
115
|
-
end
|
116
|
-
tag_mark_stack.push(Buffer.current.new_mark)
|
96
|
+
Buffer.current.push_global_mark(force: true)
|
117
97
|
find_file(file)
|
118
98
|
end
|
119
99
|
end
|
@@ -4,7 +4,7 @@ require "editorconfig"
|
|
4
4
|
|
5
5
|
module Textbringer
|
6
6
|
module Commands
|
7
|
-
define_command(:find_file) do
|
7
|
+
define_command(:find_file, doc: "Open or create a file.") do
|
8
8
|
|file_name = read_file_name("Find file: ")|
|
9
9
|
config = EditorConfig.load_file(file_name)
|
10
10
|
buffer = Buffer.find_file(file_name)
|
@@ -48,7 +48,7 @@ module Textbringer
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
define_command(:save_buffer) do
|
51
|
+
define_command(:save_buffer, doc: "Save the current buffer to a file.") do
|
52
52
|
if Buffer.current.file_name.nil?
|
53
53
|
Buffer.current.file_name = read_file_name("File to save in: ")
|
54
54
|
next if Buffer.current.file_name.nil?
|
@@ -63,7 +63,8 @@ module Textbringer
|
|
63
63
|
message("Wrote #{Buffer.current.file_name}")
|
64
64
|
end
|
65
65
|
|
66
|
-
define_command(:write_file
|
66
|
+
define_command(:write_file,
|
67
|
+
doc: "Save the current buffer as the specified file.") do
|
67
68
|
|file_name = read_file_name("Write file: ")|
|
68
69
|
if File.directory?(file_name)
|
69
70
|
file_name = File.expand_path(Buffer.current.name, file_name)
|
@@ -78,23 +79,25 @@ module Textbringer
|
|
78
79
|
message("Wrote #{Buffer.current.file_name}")
|
79
80
|
end
|
80
81
|
|
81
|
-
define_command(:set_buffer_file_encoding
|
82
|
+
define_command(:set_buffer_file_encoding,
|
83
|
+
doc: "Set the file encoding of the current buffer.") do
|
82
84
|
|enc = read_from_minibuffer("File encoding: ",
|
83
85
|
default: Buffer.current.file_encoding.name)|
|
84
86
|
Buffer.current.file_encoding = enc
|
85
87
|
end
|
86
88
|
|
87
|
-
define_command(:set_buffer_file_format
|
89
|
+
define_command(:set_buffer_file_format,
|
90
|
+
doc: "Set the file format of the current buffer.") do
|
88
91
|
|format = read_from_minibuffer("File format: ",
|
89
92
|
default: Buffer.current.file_format.to_s)|
|
90
93
|
Buffer.current.file_format = format
|
91
94
|
end
|
92
95
|
|
93
|
-
define_command(:pwd) do
|
96
|
+
define_command(:pwd, doc: "Show the current working directory.") do
|
94
97
|
message(Dir.pwd)
|
95
98
|
end
|
96
99
|
|
97
|
-
define_command(:chdir) do
|
100
|
+
define_command(:chdir, doc: "Change the current working directory.") do
|
98
101
|
|dir_name = read_file_name("Change directory: ")|
|
99
102
|
Dir.chdir(dir_name)
|
100
103
|
end
|