ver 2009.11.29 → 2009.12.14
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +6 -0
- data/CHANGELOG +353 -1
- data/LICENSE +18 -0
- data/MANIFEST +11 -1
- data/Rakefile +2 -1
- data/bin/ver +3 -12
- data/config/detect.rb +1 -1
- data/config/keymap/diakonos.rb +181 -0
- data/config/keymap/emacs.rb +24 -24
- data/config/keymap/vim.rb +162 -127
- data/config/rc.rb +29 -14
- data/config/syntax/Nemerle.json +3 -3
- data/lib/ver.rb +88 -134
- data/lib/ver/entry.rb +5 -0
- data/lib/ver/exception_view.rb +97 -0
- data/lib/ver/hover_completion.rb +14 -7
- data/lib/ver/keymap.rb +30 -1
- data/lib/ver/layout.rb +20 -14
- data/lib/ver/methods.rb +6 -15
- data/lib/ver/methods/bookmark.rb +189 -0
- data/lib/ver/methods/completion.rb +2 -2
- data/lib/ver/methods/control.rb +109 -26
- data/lib/ver/methods/ctags.rb +28 -4
- data/lib/ver/methods/delete.rb +85 -4
- data/lib/ver/methods/insert.rb +73 -52
- data/lib/ver/methods/move.rb +122 -35
- data/lib/ver/methods/open.rb +4 -43
- data/lib/ver/methods/search.rb +46 -17
- data/lib/ver/methods/select.rb +121 -24
- data/lib/ver/methods/undo.rb +23 -0
- data/lib/ver/methods/views.rb +5 -0
- data/lib/ver/mode.rb +18 -17
- data/lib/ver/status.rb +2 -2
- data/lib/ver/status/context.rb +166 -0
- data/lib/ver/text.rb +43 -81
- data/lib/ver/text/index.rb +24 -7
- data/lib/ver/undo.rb +289 -0
- data/lib/ver/vendor/sized_array.rb +70 -0
- data/lib/ver/vendor/textpow.rb +6 -1
- data/lib/ver/version.rb +3 -0
- data/lib/ver/view.rb +11 -8
- data/lib/ver/view/list/grep.rb +15 -4
- data/lib/ver/view/term.rb +9 -3
- data/spec/helper.rb +94 -0
- data/ver.gemspec +9 -6
- metadata +25 -5
- data/spec/keymap.rb +0 -224
data/lib/ver/status.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module VER
|
2
2
|
# The status bar
|
3
3
|
class Status < VER::Entry
|
4
|
+
autoload :Context, 'ver/status/context'
|
5
|
+
|
4
6
|
attr_accessor :keymap, :view
|
5
7
|
attr_reader :mode
|
6
8
|
|
@@ -112,7 +114,6 @@ module VER
|
|
112
114
|
@history_idx = history.size - 1
|
113
115
|
end
|
114
116
|
|
115
|
-
p prev: [history, @history_idx]
|
116
117
|
answer = history[@history_idx]
|
117
118
|
return unless answer
|
118
119
|
self.value = answer
|
@@ -126,7 +127,6 @@ module VER
|
|
126
127
|
@history_idx = 0
|
127
128
|
end
|
128
129
|
|
129
|
-
p next: [history, @history_idx]
|
130
130
|
answer = history[@history_idx]
|
131
131
|
return unless answer
|
132
132
|
self.value = answer
|
@@ -0,0 +1,166 @@
|
|
1
|
+
module VER
|
2
|
+
class Status
|
3
|
+
class Context < Struct.new(:text)
|
4
|
+
def filename(width = 0)
|
5
|
+
"%#{width}s" % text.filename
|
6
|
+
end
|
7
|
+
alias F filename
|
8
|
+
|
9
|
+
def basename(width = 0)
|
10
|
+
"%#{width}s" % text.filename.basename
|
11
|
+
end
|
12
|
+
alias f basename
|
13
|
+
|
14
|
+
def relative(width = 0)
|
15
|
+
"%#{width}s" % text.short_filename
|
16
|
+
end
|
17
|
+
alias r relative
|
18
|
+
|
19
|
+
def dir(width = 0)
|
20
|
+
"%#{width}s" % text.filename.directory
|
21
|
+
end
|
22
|
+
alias d dir
|
23
|
+
|
24
|
+
def line(width = 0)
|
25
|
+
"%#{width}s" % (text.count(1.0, :insert, :lines) + 1)
|
26
|
+
end
|
27
|
+
alias l line
|
28
|
+
|
29
|
+
def lines(width = 0)
|
30
|
+
"%#{width}s" % text.count(1.0, :end, :lines)
|
31
|
+
end
|
32
|
+
alias L lines
|
33
|
+
|
34
|
+
def column(width = 0)
|
35
|
+
"%#{width}s" % text.count('insert linestart', :insert, :displaychars)
|
36
|
+
end
|
37
|
+
alias c column
|
38
|
+
|
39
|
+
def percent
|
40
|
+
here = text.count(1.0, :insert, :lines)
|
41
|
+
total = text.count(1.0, :end, :lines)
|
42
|
+
percent = ((100.0 / total) * here).round
|
43
|
+
|
44
|
+
case percent
|
45
|
+
when 100; 'Bot'
|
46
|
+
when 0 ; 'Top'
|
47
|
+
else ; '%2d%%' % percent
|
48
|
+
end
|
49
|
+
end
|
50
|
+
alias P percent
|
51
|
+
|
52
|
+
def buffer(width = 0)
|
53
|
+
"%#{width}s" % text.layout.views.index(text.view)
|
54
|
+
end
|
55
|
+
alias b buffer
|
56
|
+
|
57
|
+
def buffers(width = 0)
|
58
|
+
"%#{width}s" % text.layout.views.size
|
59
|
+
end
|
60
|
+
alias B buffers
|
61
|
+
|
62
|
+
def encoding(width = 0)
|
63
|
+
"%#{width}s" % text.encoding
|
64
|
+
end
|
65
|
+
alias e encoding
|
66
|
+
|
67
|
+
def syntax(width = 0)
|
68
|
+
"%#{width}s" % text.syntax.name if text.syntax
|
69
|
+
end
|
70
|
+
alias s syntax
|
71
|
+
|
72
|
+
def mode(width = 0)
|
73
|
+
"%#{width}s" % text.keymap.mode
|
74
|
+
end
|
75
|
+
alias m mode
|
76
|
+
|
77
|
+
# format sequences:
|
78
|
+
#
|
79
|
+
# %c Current capacity (mAh)
|
80
|
+
# %r Current rate
|
81
|
+
# %b short battery status, '+', '-', '!'
|
82
|
+
# %p battery load percentage
|
83
|
+
# %m remaining time in minutes
|
84
|
+
# %h remaining time in hours
|
85
|
+
# %t remaining time in as 'H:M'
|
86
|
+
def battery(format = '[%b] %p% %t')
|
87
|
+
now = Time.now
|
88
|
+
|
89
|
+
if @battery_last
|
90
|
+
if @battery_last < (now - 60)
|
91
|
+
@battery_last = now
|
92
|
+
@battery_value = battery_build(format)
|
93
|
+
else
|
94
|
+
@battery_value
|
95
|
+
end
|
96
|
+
else
|
97
|
+
@battery_last = now
|
98
|
+
@battery_value = battery_build(format)
|
99
|
+
end
|
100
|
+
rescue => ex
|
101
|
+
puts ex, *ex.backtrace
|
102
|
+
ex.message
|
103
|
+
end
|
104
|
+
|
105
|
+
def battery_build(format)
|
106
|
+
total = {}
|
107
|
+
|
108
|
+
Dir.glob('/proc/acpi/battery/*/{state,info}') do |file|
|
109
|
+
parsed = battery_parse(file)
|
110
|
+
next unless parsed[:present] == 'yes'
|
111
|
+
# FIXME: doesn't take care of multiple batteries
|
112
|
+
total.merge!(parsed)
|
113
|
+
end
|
114
|
+
|
115
|
+
# rate might be 0
|
116
|
+
rate = total[:present_rate].to_i
|
117
|
+
capacity = total[:remaining_capacity].to_i
|
118
|
+
|
119
|
+
if rate == 0
|
120
|
+
hours, percent = 2, 100
|
121
|
+
time = hours_left = minutes_left = 'N/A'
|
122
|
+
else
|
123
|
+
hours, minutes = ((capacity * 60.0) / rate).divmod(60)
|
124
|
+
minutes = minutes.round
|
125
|
+
percent = ((100 / total[:last_full_capacity].to_f) * capacity).round
|
126
|
+
hours_left = (hours + (minutes / 60.0)).round
|
127
|
+
minutes_left = (hours / 60.0) + minutes
|
128
|
+
time = "#{hours}:#{minutes}"
|
129
|
+
end
|
130
|
+
|
131
|
+
case total[:charging_state]
|
132
|
+
when 'discharging'
|
133
|
+
b = hours < 1 ? '!' : '-'
|
134
|
+
when 'charging'
|
135
|
+
b = '+'
|
136
|
+
end
|
137
|
+
|
138
|
+
final = {
|
139
|
+
'%c' => capacity,
|
140
|
+
'%r' => rate,
|
141
|
+
'%b' => b,
|
142
|
+
'%p' => percent,
|
143
|
+
'%m' => minutes_left,
|
144
|
+
'%h' => hours_left,
|
145
|
+
'%t' => time,
|
146
|
+
}
|
147
|
+
|
148
|
+
@last = Time.now
|
149
|
+
format.gsub(/%\w/, final)
|
150
|
+
end
|
151
|
+
|
152
|
+
def battery_parse(file)
|
153
|
+
data = {}
|
154
|
+
|
155
|
+
File.open(file) do |io|
|
156
|
+
io.each_line do |line|
|
157
|
+
next unless line =~ /^([^:]+):\s*(.+)$/
|
158
|
+
data[$1.downcase.tr(' ', '_').to_sym] = $2
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
data
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
data/lib/ver/text.rb
CHANGED
@@ -42,7 +42,7 @@ module VER
|
|
42
42
|
MATCH_WORD_LEFT = /(^|\b)\S+(\b|$)/
|
43
43
|
|
44
44
|
attr_accessor :keymap, :view, :status
|
45
|
-
attr_reader :filename, :encoding, :pristine, :syntax
|
45
|
+
attr_reader :filename, :encoding, :pristine, :syntax, :undoer
|
46
46
|
|
47
47
|
# attributes for diverse functionality
|
48
48
|
attr_accessor :selection_mode, :selection_start
|
@@ -50,17 +50,19 @@ module VER
|
|
50
50
|
def initialize(view, options = {})
|
51
51
|
super
|
52
52
|
self.view = view
|
53
|
+
@options = Options.new(:text, VER.options)
|
53
54
|
|
54
|
-
keymap_name =
|
55
|
+
keymap_name = @options.keymap
|
55
56
|
self.keymap = Keymap.get(name: keymap_name, receiver: self)
|
56
57
|
|
57
58
|
apply_mode_style(keymap.mode) # for startup
|
58
59
|
setup_tags
|
59
60
|
|
61
|
+
@undoer = VER::Undo::Tree.new(self)
|
62
|
+
|
60
63
|
self.selection_start = nil
|
61
64
|
@pristine = true
|
62
65
|
@syntax = nil
|
63
|
-
@options = Options.new(:text, VER.options)
|
64
66
|
@encoding = Encoding.default_internal
|
65
67
|
@dirty_indices = []
|
66
68
|
|
@@ -91,34 +93,20 @@ module VER
|
|
91
93
|
view.layout
|
92
94
|
end
|
93
95
|
|
94
|
-
# lines start from 1
|
95
|
-
# end is maximum lines + 1
|
96
96
|
def status_projection(into)
|
97
|
-
format =
|
98
|
-
|
99
|
-
top, bot = yview
|
100
|
-
|
101
|
-
if top < 0.5
|
102
|
-
percent = '[top]'
|
103
|
-
elsif bot > 99.5
|
104
|
-
percent = '[bot]'
|
105
|
-
else
|
106
|
-
percent = "#{bot.to_i}%"
|
107
|
-
end
|
97
|
+
format = options.statusline.dup
|
108
98
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
99
|
+
format.gsub!(/%([[:alpha:]]+)/, '#{\1()}')
|
100
|
+
format.gsub!(/%_([[:alpha:]]+)/, '#{(_ = \1()) ? " #{_}" : ""}')
|
101
|
+
format.gsub!(/%([+-]?\d+)([[:alpha:]]+)/, '#{\2(\1)}')
|
102
|
+
format = "%{#{format}}"
|
113
103
|
|
114
|
-
|
115
|
-
|
116
|
-
index(:insert).idx,
|
117
|
-
percent,
|
118
|
-
additional.join(' | '),
|
119
|
-
]
|
104
|
+
context = Status::Context.new(self)
|
105
|
+
line = context.instance_eval(format)
|
120
106
|
|
121
|
-
into.value =
|
107
|
+
into.value = line
|
108
|
+
rescue => ex
|
109
|
+
puts ex, ex.backtrace
|
122
110
|
end
|
123
111
|
|
124
112
|
TAG_ALL_MATCHING_OPTIONS = { from: '1.0', to: 'end - 1 chars' }
|
@@ -183,49 +171,12 @@ module VER
|
|
183
171
|
Tk::Event.generate(self, '<<Movement>>')
|
184
172
|
end
|
185
173
|
|
186
|
-
def
|
187
|
-
|
188
|
-
|
189
|
-
now = index(:insert)
|
190
|
-
left, right = [start, now].sort
|
191
|
-
tag_remove :sel, '1.0', 'end'
|
192
|
-
|
193
|
-
case selection_mode
|
194
|
-
when :select_char
|
195
|
-
tag_add :sel, left, "#{right} + 1 chars"
|
196
|
-
when :select_line
|
197
|
-
tag_add :sel, "#{left} linestart", "#{right} lineend"
|
198
|
-
when :select_block
|
199
|
-
ly, lx = left.split
|
200
|
-
ry, rx = right.split
|
201
|
-
|
202
|
-
from_y, to_y = [ly, ry].sort
|
203
|
-
from_x, to_x = [lx, rx].sort
|
174
|
+
def insert(index, string)
|
175
|
+
index = index(index) unless index.respond_to?(:to_index)
|
204
176
|
|
205
|
-
|
206
|
-
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
# fix the ruby definition of delete, Tk allows more than 2 indices
|
212
|
-
def delete(*args)
|
213
|
-
if args.size > 2
|
214
|
-
deleted = args.each_slice(2).map{|left, right| get(left, right) }
|
215
|
-
else
|
216
|
-
deleted = get(*args)
|
177
|
+
undo_record do |record|
|
178
|
+
record.insert(index, string)
|
217
179
|
end
|
218
|
-
|
219
|
-
copy(deleted)
|
220
|
-
|
221
|
-
execute('delete', *args)
|
222
|
-
|
223
|
-
touch!(*args)
|
224
|
-
end
|
225
|
-
|
226
|
-
def insert(*args)
|
227
|
-
super
|
228
|
-
touch!(args.first)
|
229
180
|
end
|
230
181
|
|
231
182
|
# Replaces the range of characters between index1 and index2 with the given
|
@@ -241,9 +192,14 @@ module VER
|
|
241
192
|
# are active in the text widget.
|
242
193
|
#
|
243
194
|
# replace index1 index2 chars ?tagList chars tagList ...?
|
244
|
-
def replace(index1, index2,
|
245
|
-
|
246
|
-
|
195
|
+
def replace(index1, index2, string)
|
196
|
+
index1 = index(index1) unless index1.respond_to?(:to_index)
|
197
|
+
index2 = index(index2) unless index2.respond_to?(:to_index)
|
198
|
+
return if index1 == index2
|
199
|
+
|
200
|
+
undo_record do |record|
|
201
|
+
record.replace(index1, index2, string)
|
202
|
+
end
|
247
203
|
end
|
248
204
|
|
249
205
|
def focus
|
@@ -282,6 +238,7 @@ module VER
|
|
282
238
|
|
283
239
|
if @syntax = Syntax.from_filename(filename)
|
284
240
|
defer{ syntax.highlight(self, value) }
|
241
|
+
status_projection(status) if status
|
285
242
|
end
|
286
243
|
end
|
287
244
|
|
@@ -296,6 +253,13 @@ module VER
|
|
296
253
|
schedule_highlight!
|
297
254
|
end
|
298
255
|
|
256
|
+
# TODO: maybe we can make this one faster when many lines are going to be
|
257
|
+
# highlighted at once by bundling them.
|
258
|
+
def touch!(*args)
|
259
|
+
args.each{|arg| schedule_line_highlight(arg) } if @syntax
|
260
|
+
Tk::Event.generate(self, '<<Modified>>')
|
261
|
+
end
|
262
|
+
|
299
263
|
private
|
300
264
|
|
301
265
|
def schedule_highlight!(*args)
|
@@ -315,22 +279,16 @@ module VER
|
|
315
279
|
end
|
316
280
|
end
|
317
281
|
|
318
|
-
# TODO: maybe we can make this one faster when many lines are going to be
|
319
|
-
# highlighted at once by bundling them.
|
320
|
-
def touch!(*args)
|
321
|
-
args.each{|arg| schedule_line_highlight(arg) } if @syntax
|
322
|
-
Tk::Event.generate(self, '<<Modified>>')
|
323
|
-
end
|
324
|
-
|
325
282
|
def mode=(name)
|
326
283
|
keymap.mode = mode = name.to_sym
|
327
|
-
|
284
|
+
undo_separator
|
328
285
|
apply_mode_style(mode)
|
329
286
|
status_projection(status) if status
|
330
287
|
end
|
331
288
|
|
332
289
|
def apply_mode_style(mode)
|
333
290
|
cursor = MODE_CURSOR[mode]
|
291
|
+
return unless cursor
|
334
292
|
configure cursor
|
335
293
|
|
336
294
|
return unless status && color = cursor[:insertbackground]
|
@@ -426,8 +384,12 @@ module VER
|
|
426
384
|
end
|
427
385
|
end
|
428
386
|
|
429
|
-
def font(
|
430
|
-
|
387
|
+
def font(given_options = nil)
|
388
|
+
if given_options
|
389
|
+
options.font.configure(given_options)
|
390
|
+
else
|
391
|
+
options.font
|
392
|
+
end
|
431
393
|
end
|
432
394
|
end
|
433
395
|
end
|
data/lib/ver/text/index.rb
CHANGED
@@ -19,6 +19,11 @@ module VER
|
|
19
19
|
return 0 if widget.compare(self_idx, '==', other_idx)
|
20
20
|
end
|
21
21
|
|
22
|
+
def ==(other)
|
23
|
+
self_idx, other_idx = idx, other.to_index.idx
|
24
|
+
widget.compare(self_idx, '==', other_idx)
|
25
|
+
end
|
26
|
+
|
22
27
|
def delta(other)
|
23
28
|
y_diff = other.y - y
|
24
29
|
|
@@ -38,27 +43,39 @@ module VER
|
|
38
43
|
end
|
39
44
|
|
40
45
|
def linestart
|
41
|
-
"#{idx} linestart"
|
46
|
+
widget.index "#{idx} linestart"
|
42
47
|
end
|
43
48
|
|
44
49
|
def lineend
|
45
|
-
"#{idx} lineend"
|
50
|
+
widget.index "#{idx} lineend"
|
46
51
|
end
|
47
52
|
|
48
53
|
def wordstart
|
49
|
-
"#{idx} wordstart"
|
54
|
+
widget.index "#{idx} wordstart"
|
50
55
|
end
|
51
56
|
|
52
57
|
def wordend
|
53
|
-
"#{idx} wordend"
|
58
|
+
widget.index "#{idx} wordend"
|
54
59
|
end
|
55
60
|
|
56
61
|
def next
|
57
|
-
|
62
|
+
widget.index "#{y + 1}.#{x}"
|
58
63
|
end
|
59
64
|
|
60
65
|
def prev
|
61
|
-
|
66
|
+
widget.index "#{y - 1}.#{x}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def +(chars)
|
70
|
+
widget.index "#{idx} + #{chars} chars"
|
71
|
+
end
|
72
|
+
|
73
|
+
def -(other)
|
74
|
+
if other.is_a?(self.class)
|
75
|
+
widget.count(other, self, :displaychars)
|
76
|
+
else
|
77
|
+
widget.index "#{idx} - #{other.to_int} chars"
|
78
|
+
end
|
62
79
|
end
|
63
80
|
|
64
81
|
def split
|
@@ -66,7 +83,7 @@ module VER
|
|
66
83
|
end
|
67
84
|
|
68
85
|
def inspect
|
69
|
-
"#<Text::Index #{self}>"
|
86
|
+
to_s # "#<Text::Index #{self}>"
|
70
87
|
end
|
71
88
|
|
72
89
|
def to_str
|