textbringer 0.1.8 → 0.1.9
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.
- 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
@@ -55,9 +55,10 @@ module Textbringer
|
|
55
55
|
when ?n
|
56
56
|
# do nothing
|
57
57
|
when ?!
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
Buffer.current.composite_edit do
|
59
|
+
replace_match(to_str)
|
60
|
+
n += 1 + Buffer.current.replace_regexp_forward(regexp, to_str)
|
61
|
+
end
|
61
62
|
break
|
62
63
|
when ?q
|
63
64
|
break
|
@@ -2,63 +2,90 @@
|
|
2
2
|
|
3
3
|
module Textbringer
|
4
4
|
module Commands
|
5
|
-
define_command(:resize_window
|
5
|
+
define_command(:resize_window,
|
6
|
+
doc: "Resize windows to fit the terminal size.") do
|
6
7
|
Window.resize
|
7
8
|
end
|
8
9
|
|
9
|
-
define_command(:recenter
|
10
|
+
define_command(:recenter,
|
11
|
+
doc: "Center point in the current window.") do
|
10
12
|
Window.current.recenter
|
11
13
|
Window.redraw
|
12
14
|
end
|
13
15
|
|
14
|
-
define_command(:scroll_up
|
16
|
+
define_command(:scroll_up,
|
17
|
+
doc: "Scroll text of the current window upward.") do
|
15
18
|
Window.current.scroll_up
|
16
19
|
end
|
17
20
|
|
18
|
-
define_command(:scroll_down
|
21
|
+
define_command(:scroll_down,
|
22
|
+
doc: "Scroll text of the current window downward.") do
|
19
23
|
Window.current.scroll_down
|
20
24
|
end
|
21
25
|
|
22
|
-
define_command(:delete_window
|
26
|
+
define_command(:delete_window,
|
27
|
+
doc: "Delete the current window.") do
|
23
28
|
Window.delete_window
|
24
29
|
end
|
25
30
|
|
26
|
-
define_command(:delete_other_windows
|
31
|
+
define_command(:delete_other_windows,
|
32
|
+
doc: "Delete windows other than the current one.") do
|
27
33
|
Window.delete_other_windows
|
28
34
|
end
|
29
35
|
|
30
|
-
define_command(:split_window
|
36
|
+
define_command(:split_window,
|
37
|
+
doc: "Split the current window vertically.") do
|
31
38
|
Window.current.split
|
32
39
|
end
|
33
40
|
|
34
|
-
define_command(:other_window
|
41
|
+
define_command(:other_window,
|
42
|
+
doc: "Switch to another window.") do
|
35
43
|
Window.other_window
|
36
44
|
end
|
37
45
|
|
38
|
-
define_command(:enlarge_window) do
|
46
|
+
define_command(:enlarge_window, doc: <<~EOD) do
|
47
|
+
Make the current window n lines taller.
|
48
|
+
|
49
|
+
If n is negative, shrink the window -n lines.
|
50
|
+
See [shrink_window] for details.
|
51
|
+
EOD
|
52
|
+
|n = number_prefix_arg|
|
39
53
|
Window.current.enlarge(n)
|
40
54
|
end
|
41
55
|
|
42
|
-
define_command(:
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
56
|
+
define_command(:shrink_window, doc: <<~EOD) do |n = number_prefix_arg|
|
57
|
+
Make the current window n lines smaller.
|
58
|
+
|
59
|
+
If n is negative, enlarge the window -n lines.
|
60
|
+
See [enlarge_window] for details.
|
61
|
+
EOD
|
62
|
+
Window.current.shrink(n)
|
63
|
+
end
|
64
|
+
|
65
|
+
define_command(:shrink_window_if_larger_than_buffer, doc: <<~EOD) do
|
66
|
+
Shrink the current window if it's larger than the buffer.
|
67
|
+
EOD
|
68
|
+
Window.current.shrink_if_larger_than_buffer
|
69
|
+
end
|
70
|
+
|
71
|
+
define_command(:switch_to_buffer, doc: <<~EOD) do
|
72
|
+
Display buffer in the current window.
|
73
|
+
EOD
|
74
|
+
|buffer = read_buffer("Switch to buffer: ")|
|
75
|
+
if buffer.is_a?(String)
|
76
|
+
buffer = Buffer[buffer]
|
48
77
|
end
|
49
78
|
if buffer
|
50
79
|
Window.current.buffer = Buffer.current = buffer
|
51
80
|
else
|
52
|
-
raise EditorError, "No such buffer: #{
|
81
|
+
raise EditorError, "No such buffer: #{buffer}"
|
53
82
|
end
|
54
83
|
end
|
55
84
|
|
56
|
-
define_command(:kill_buffer) do
|
57
|
-
|
|
58
|
-
if
|
59
|
-
buffer =
|
60
|
-
else
|
61
|
-
buffer = Buffer[name]
|
85
|
+
define_command(:kill_buffer, doc: "Kill buffer.") do
|
86
|
+
|buffer = read_buffer("Kill buffer: ", default: Buffer.current.name)|
|
87
|
+
if buffer.is_a?(String)
|
88
|
+
buffer = Buffer[buffer]
|
62
89
|
end
|
63
90
|
if buffer.modified?
|
64
91
|
next unless yes_or_no?("The last change is not saved; kill anyway?")
|
data/lib/textbringer/config.rb
CHANGED
@@ -9,7 +9,8 @@ module Textbringer
|
|
9
9
|
indent_tabs_mode: false,
|
10
10
|
case_fold_search: true,
|
11
11
|
buffer_dump_dir: File.expand_path("~/.textbringer/buffer_dump"),
|
12
|
-
|
12
|
+
mark_ring_max: 16,
|
13
|
+
global_mark_ring_max: 16,
|
13
14
|
window_min_height: 4,
|
14
15
|
syntax_highlight: true,
|
15
16
|
highlight_buffer_size_limit: 102400,
|
@@ -5,9 +5,11 @@ module Textbringer
|
|
5
5
|
RECURSIVE_EDIT_TAG = Object.new
|
6
6
|
|
7
7
|
class Controller
|
8
|
+
attr_reader :this_command_keys
|
8
9
|
attr_accessor :this_command, :last_command, :overriding_map
|
9
10
|
attr_accessor :prefix_arg, :current_prefix_arg
|
10
11
|
attr_reader :key_sequence, :last_key, :recursive_edit_level
|
12
|
+
attr_reader :last_keyboard_macro
|
11
13
|
|
12
14
|
@@current = nil
|
13
15
|
|
@@ -20,15 +22,20 @@ module Textbringer
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def initialize
|
25
|
+
@top_self = eval("self", TOPLEVEL_BINDING)
|
23
26
|
@key_sequence = []
|
24
27
|
@last_key = nil
|
25
28
|
@recursive_edit_level = 0
|
29
|
+
@this_command_keys = nil
|
26
30
|
@this_command = nil
|
27
31
|
@last_command = nil
|
28
32
|
@overriding_map = nil
|
29
33
|
@prefix_arg = nil
|
30
34
|
@current_prefix_arg = nil
|
31
35
|
@echo_immediately = false
|
36
|
+
@recording_keyboard_macro = nil
|
37
|
+
@last_keyboard_macro = nil
|
38
|
+
@executing_keyboard_macro = nil
|
32
39
|
end
|
33
40
|
|
34
41
|
def command_loop(tag)
|
@@ -43,14 +50,15 @@ module Textbringer
|
|
43
50
|
@key_sequence << @last_key
|
44
51
|
cmd = key_binding(@key_sequence)
|
45
52
|
if cmd.is_a?(Symbol) || cmd.respond_to?(:call)
|
46
|
-
@key_sequence
|
53
|
+
@this_command_keys = @key_sequence
|
54
|
+
@key_sequence = []
|
47
55
|
@this_command = cmd
|
48
56
|
@current_prefix_arg = @prefix_arg
|
49
57
|
@prefix_arg = nil
|
50
58
|
begin
|
51
59
|
run_hooks(:pre_command_hook, remove_on_error: true)
|
52
60
|
if cmd.is_a?(Symbol)
|
53
|
-
send(cmd)
|
61
|
+
@top_self.send(cmd)
|
54
62
|
else
|
55
63
|
cmd.call
|
56
64
|
end
|
@@ -61,31 +69,41 @@ module Textbringer
|
|
61
69
|
end
|
62
70
|
else
|
63
71
|
if cmd.nil?
|
64
|
-
keys = @key_sequence
|
72
|
+
keys = Keymap.key_sequence_string(@key_sequence)
|
65
73
|
@key_sequence.clear
|
66
74
|
@prefix_arg = nil
|
67
75
|
message("#{keys} is undefined")
|
68
76
|
end
|
69
77
|
end
|
78
|
+
Window.redisplay
|
70
79
|
rescue Exception => e
|
71
80
|
show_exception(e)
|
72
81
|
@prefix_arg = nil
|
82
|
+
@recording_keyboard_macro = nil
|
83
|
+
Window.redisplay
|
84
|
+
if Window.echo_area.active?
|
85
|
+
wait_input(2000)
|
86
|
+
Window.echo_area.clear_message
|
87
|
+
Window.redisplay
|
88
|
+
end
|
73
89
|
end
|
74
|
-
Window.redisplay
|
75
90
|
end
|
76
91
|
end
|
77
92
|
end
|
78
93
|
|
79
94
|
def wait_input(msecs)
|
95
|
+
if executing_keyboard_macro?
|
96
|
+
return @executing_keyboard_macro.first
|
97
|
+
end
|
80
98
|
Window.current.wait_input(msecs)
|
81
99
|
end
|
82
100
|
|
83
101
|
def read_char
|
84
|
-
|
102
|
+
read_char_with_keyboard_macro(:read_char)
|
85
103
|
end
|
86
104
|
|
87
105
|
def read_char_nonblock
|
88
|
-
|
106
|
+
read_char_with_keyboard_macro(:read_char_nonblock)
|
89
107
|
end
|
90
108
|
|
91
109
|
def received_keyboard_quit?
|
@@ -108,22 +126,8 @@ module Textbringer
|
|
108
126
|
end
|
109
127
|
end
|
110
128
|
|
111
|
-
def key_name(key)
|
112
|
-
case key
|
113
|
-
when Symbol
|
114
|
-
"<#{key}>"
|
115
|
-
when "\e"
|
116
|
-
"ESC"
|
117
|
-
when "\C-m"
|
118
|
-
"RET"
|
119
|
-
when /\A[\0-\b\v-\x1f\x7f]\z/
|
120
|
-
"C-" + (key.ord ^ 0x40).chr.downcase
|
121
|
-
else
|
122
|
-
key.to_s
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
129
|
def echo_input
|
130
|
+
return if executing_keyboard_macro?
|
127
131
|
if @prefix_arg || !@key_sequence.empty?
|
128
132
|
if !@echo_immediately
|
129
133
|
return if wait_input(1000)
|
@@ -138,7 +142,7 @@ module Textbringer
|
|
138
142
|
end
|
139
143
|
if !@key_sequence.empty?
|
140
144
|
s << " " if !s.empty?
|
141
|
-
s << @key_sequence
|
145
|
+
s << Keymap.key_sequence_string(@key_sequence)
|
142
146
|
end
|
143
147
|
s << "-"
|
144
148
|
Window.echo_area.show(s)
|
@@ -150,12 +154,74 @@ module Textbringer
|
|
150
154
|
end
|
151
155
|
end
|
152
156
|
|
153
|
-
|
157
|
+
def start_keyboard_macro
|
158
|
+
if @recording_keyboard_macro
|
159
|
+
@recording_keyboard_macro = nil
|
160
|
+
raise EditorError, "Already recording keyboard macro"
|
161
|
+
end
|
162
|
+
@recording_keyboard_macro = []
|
163
|
+
end
|
164
|
+
|
165
|
+
def end_keyboard_macro
|
166
|
+
if @recording_keyboard_macro.nil?
|
167
|
+
raise EditorError, "Not recording keyboard macro"
|
168
|
+
end
|
169
|
+
if @recording_keyboard_macro.empty?
|
170
|
+
raise EditorError, "Empty keyboard macro"
|
171
|
+
end
|
172
|
+
@recording_keyboard_macro.pop(@this_command_keys.size)
|
173
|
+
@last_keyboard_macro = @recording_keyboard_macro
|
174
|
+
@recording_keyboard_macro = nil
|
175
|
+
end
|
176
|
+
|
177
|
+
def execute_keyboard_macro(macro, n = 1)
|
178
|
+
n.times do
|
179
|
+
@executing_keyboard_macro = macro.dup
|
180
|
+
begin
|
181
|
+
recursive_edit
|
182
|
+
ensure
|
183
|
+
@executing_keyboard_macro = nil
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def call_last_keyboard_macro(n)
|
189
|
+
if @last_keyboard_macro.nil?
|
190
|
+
raise EditorError, "Keyboard macro not defined"
|
191
|
+
end
|
192
|
+
execute_keyboard_macro(@last_keyboard_macro, n)
|
193
|
+
end
|
194
|
+
|
195
|
+
def recording_keyboard_macro?
|
196
|
+
!@recording_keyboard_macro.nil?
|
197
|
+
end
|
198
|
+
|
199
|
+
def executing_keyboard_macro?
|
200
|
+
!@executing_keyboard_macro.nil?
|
201
|
+
end
|
154
202
|
|
155
203
|
def key_binding(key_sequence)
|
156
204
|
@overriding_map&.lookup(key_sequence) ||
|
157
205
|
Buffer.current&.keymap&.lookup(key_sequence) ||
|
158
206
|
GLOBAL_MAP.lookup(key_sequence)
|
159
207
|
end
|
208
|
+
|
209
|
+
private
|
210
|
+
|
211
|
+
def read_char_with_keyboard_macro(read_char_method)
|
212
|
+
if !executing_keyboard_macro?
|
213
|
+
c = call_read_char_method(read_char_method)
|
214
|
+
if @recording_keyboard_macro
|
215
|
+
@recording_keyboard_macro.push(c)
|
216
|
+
end
|
217
|
+
c
|
218
|
+
else
|
219
|
+
@executing_keyboard_macro.shift
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def call_read_char_method(read_char_method)
|
224
|
+
Window.current.send(read_char_method)
|
225
|
+
end
|
160
226
|
end
|
161
227
|
end
|
data/lib/textbringer/keymap.rb
CHANGED
@@ -4,6 +4,8 @@ require "curses"
|
|
4
4
|
|
5
5
|
module Textbringer
|
6
6
|
class Keymap
|
7
|
+
include Enumerable
|
8
|
+
|
7
9
|
def initialize
|
8
10
|
@map = {}
|
9
11
|
end
|
@@ -35,10 +37,43 @@ module Textbringer
|
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
40
|
+
def each(prefixes = [], &block)
|
41
|
+
@map.each do |key, val|
|
42
|
+
if val.is_a?(Keymap)
|
43
|
+
val.each([*prefixes, key], &block)
|
44
|
+
else
|
45
|
+
yield([*prefixes, key], val)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
38
50
|
def handle_undefined_key
|
39
51
|
@map.default_proc = Proc.new { |h, k| yield(k) }
|
40
52
|
end
|
41
53
|
|
54
|
+
def self.key_name(key)
|
55
|
+
case key
|
56
|
+
when Symbol
|
57
|
+
"<#{key}>"
|
58
|
+
when " "
|
59
|
+
"SPC"
|
60
|
+
when "\t"
|
61
|
+
"TAB"
|
62
|
+
when "\e"
|
63
|
+
"ESC"
|
64
|
+
when "\C-m"
|
65
|
+
"RET"
|
66
|
+
when /\A[\0-\x1f\x7f]\z/
|
67
|
+
"C-" + (key.ord ^ 0x40).chr.downcase
|
68
|
+
else
|
69
|
+
key.to_s
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.key_sequence_string(key_sequence)
|
74
|
+
key_sequence.map { |key| key_name(key) }.join(" ")
|
75
|
+
end
|
76
|
+
|
42
77
|
private
|
43
78
|
|
44
79
|
def kbd(key)
|
@@ -85,7 +120,10 @@ module Textbringer
|
|
85
120
|
end
|
86
121
|
GLOBAL_MAP.define_key(?\t, :self_insert)
|
87
122
|
GLOBAL_MAP.define_key(?\C-q, :quoted_insert)
|
88
|
-
GLOBAL_MAP.define_key("\C
|
123
|
+
GLOBAL_MAP.define_key("\C-@", :set_mark_command)
|
124
|
+
GLOBAL_MAP.define_key("\C-x\C-@", :pop_global_mark)
|
125
|
+
GLOBAL_MAP.define_key("\e*", :next_global_mark)
|
126
|
+
GLOBAL_MAP.define_key("\e?", :previous_global_mark)
|
89
127
|
GLOBAL_MAP.define_key("\C-x\C-x", :exchange_point_and_mark)
|
90
128
|
GLOBAL_MAP.define_key("\ew", :copy_region)
|
91
129
|
GLOBAL_MAP.define_key(?\C-w, :kill_region)
|
@@ -94,10 +132,12 @@ module Textbringer
|
|
94
132
|
GLOBAL_MAP.define_key(?\C-y, :yank)
|
95
133
|
GLOBAL_MAP.define_key("\ey", :yank_pop)
|
96
134
|
GLOBAL_MAP.define_key(?\C-_, :undo)
|
97
|
-
GLOBAL_MAP.define_key("\C-x\C-_", :
|
135
|
+
GLOBAL_MAP.define_key("\C-x\C-_", :redo_command)
|
98
136
|
GLOBAL_MAP.define_key("\C-t", :transpose_chars)
|
99
137
|
GLOBAL_MAP.define_key("\C-j", :newline)
|
100
138
|
GLOBAL_MAP.define_key("\C-m", :newline)
|
139
|
+
GLOBAL_MAP.define_key("\em", :back_to_indentation)
|
140
|
+
GLOBAL_MAP.define_key("\e^", :delete_indentation)
|
101
141
|
GLOBAL_MAP.define_key("\C-l", :recenter)
|
102
142
|
GLOBAL_MAP.define_key("\C-v", :scroll_up)
|
103
143
|
GLOBAL_MAP.define_key(:npage, :scroll_up)
|
@@ -108,6 +148,7 @@ module Textbringer
|
|
108
148
|
GLOBAL_MAP.define_key("\C-x2", :split_window)
|
109
149
|
GLOBAL_MAP.define_key("\C-xo", :other_window)
|
110
150
|
GLOBAL_MAP.define_key("\C-x^", :enlarge_window)
|
151
|
+
GLOBAL_MAP.define_key("\C-x-", :shrink_window_if_larger_than_buffer)
|
111
152
|
GLOBAL_MAP.define_key("\C-x\C-c", :exit_textbringer)
|
112
153
|
GLOBAL_MAP.define_key("\C-z", :suspend_textbringer)
|
113
154
|
GLOBAL_MAP.define_key("\C-x\C-f", :find_file)
|
@@ -117,6 +158,7 @@ module Textbringer
|
|
117
158
|
GLOBAL_MAP.define_key("\C-xk", :kill_buffer)
|
118
159
|
GLOBAL_MAP.define_key("\C-x\C-mf", :set_buffer_file_encoding)
|
119
160
|
GLOBAL_MAP.define_key("\C-x\C-mn", :set_buffer_file_format)
|
161
|
+
GLOBAL_MAP.define_key("\e.", :find_tag)
|
120
162
|
GLOBAL_MAP.define_key("\ex", :execute_command)
|
121
163
|
GLOBAL_MAP.define_key("\e:", :eval_expression)
|
122
164
|
GLOBAL_MAP.define_key(?\C-u, :universal_argument)
|
@@ -125,6 +167,22 @@ module Textbringer
|
|
125
167
|
GLOBAL_MAP.define_key(?\C-r, :isearch_backward)
|
126
168
|
GLOBAL_MAP.define_key("\e%", :query_replace_regexp)
|
127
169
|
GLOBAL_MAP.define_key("\e!", :shell_execute)
|
170
|
+
GLOBAL_MAP.define_key("\C-xr ", :point_to_register)
|
171
|
+
GLOBAL_MAP.define_key("\C-xrj", :jump_to_register)
|
172
|
+
GLOBAL_MAP.define_key("\C-xrx", :copy_to_register)
|
173
|
+
GLOBAL_MAP.define_key("\C-xrs", :copy_to_register)
|
174
|
+
GLOBAL_MAP.define_key("\C-xrg", :insert_register)
|
175
|
+
GLOBAL_MAP.define_key("\C-xri", :insert_register)
|
176
|
+
GLOBAL_MAP.define_key("\C-xrn", :number_to_register)
|
177
|
+
GLOBAL_MAP.define_key("\C-xr+", :increment_register)
|
178
|
+
GLOBAL_MAP.define_key("\C-x(", :start_keyboard_macro)
|
179
|
+
GLOBAL_MAP.define_key(:f3, :start_keyboard_macro)
|
180
|
+
GLOBAL_MAP.define_key("\C-x)", :end_keyboard_macro)
|
181
|
+
GLOBAL_MAP.define_key("\C-xe", :end_and_call_keyboard_macro)
|
182
|
+
GLOBAL_MAP.define_key(:f4, :end_or_call_keyboard_macro)
|
183
|
+
GLOBAL_MAP.define_key([:f1, "b"], :describe_bindings)
|
184
|
+
GLOBAL_MAP.define_key([:f1, "f"], :describe_command)
|
185
|
+
GLOBAL_MAP.define_key([:f1, "k"], :describe_key)
|
128
186
|
GLOBAL_MAP.handle_undefined_key do |key|
|
129
187
|
if key.is_a?(String) && /[\0-\x7f]/ !~ key
|
130
188
|
:self_insert
|