ver 2009.11.29 → 2009.12.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/AUTHORS +6 -0
  2. data/CHANGELOG +353 -1
  3. data/LICENSE +18 -0
  4. data/MANIFEST +11 -1
  5. data/Rakefile +2 -1
  6. data/bin/ver +3 -12
  7. data/config/detect.rb +1 -1
  8. data/config/keymap/diakonos.rb +181 -0
  9. data/config/keymap/emacs.rb +24 -24
  10. data/config/keymap/vim.rb +162 -127
  11. data/config/rc.rb +29 -14
  12. data/config/syntax/Nemerle.json +3 -3
  13. data/lib/ver.rb +88 -134
  14. data/lib/ver/entry.rb +5 -0
  15. data/lib/ver/exception_view.rb +97 -0
  16. data/lib/ver/hover_completion.rb +14 -7
  17. data/lib/ver/keymap.rb +30 -1
  18. data/lib/ver/layout.rb +20 -14
  19. data/lib/ver/methods.rb +6 -15
  20. data/lib/ver/methods/bookmark.rb +189 -0
  21. data/lib/ver/methods/completion.rb +2 -2
  22. data/lib/ver/methods/control.rb +109 -26
  23. data/lib/ver/methods/ctags.rb +28 -4
  24. data/lib/ver/methods/delete.rb +85 -4
  25. data/lib/ver/methods/insert.rb +73 -52
  26. data/lib/ver/methods/move.rb +122 -35
  27. data/lib/ver/methods/open.rb +4 -43
  28. data/lib/ver/methods/search.rb +46 -17
  29. data/lib/ver/methods/select.rb +121 -24
  30. data/lib/ver/methods/undo.rb +23 -0
  31. data/lib/ver/methods/views.rb +5 -0
  32. data/lib/ver/mode.rb +18 -17
  33. data/lib/ver/status.rb +2 -2
  34. data/lib/ver/status/context.rb +166 -0
  35. data/lib/ver/text.rb +43 -81
  36. data/lib/ver/text/index.rb +24 -7
  37. data/lib/ver/undo.rb +289 -0
  38. data/lib/ver/vendor/sized_array.rb +70 -0
  39. data/lib/ver/vendor/textpow.rb +6 -1
  40. data/lib/ver/version.rb +3 -0
  41. data/lib/ver/view.rb +11 -8
  42. data/lib/ver/view/list/grep.rb +15 -4
  43. data/lib/ver/view/term.rb +9 -3
  44. data/spec/helper.rb +94 -0
  45. data/ver.gemspec +9 -6
  46. metadata +25 -5
  47. data/spec/keymap.rb +0 -224
@@ -0,0 +1,289 @@
1
+ module VER
2
+ module Undo
3
+ # The Tree keeps track of the current Record and creates new records.
4
+ #
5
+ # It maintains a pointer to the widget and the current record in the tree.
6
+ # The current record is the record that was last applied.
7
+ #
8
+ # When a record is undone:
9
+ # If there is a parent, it becomes the new current record.
10
+ # If there is no parent, it stays the current record, only flagged as
11
+ # unapplied.
12
+ # it's parent (if there is one), becomes the new
13
+ # current record.
14
+ #
15
+ # When a record is redone, it's current child (if there is one), becomes the
16
+ # new current record.
17
+ #
18
+ # The Tree doesn't have a maximum depth at the moment, but this will be
19
+ # added, when old records are pruned, only the record at depth+1 that is
20
+ # current stays.
21
+ #
22
+ # Eventually we have to separate records and undo/redo stepping.
23
+ # Some operations involve more than one record, but should be undone/redone
24
+ # together.
25
+ # It would also be handy if these operations could be identified
26
+ # automagically (like multiple operations within one record block).
27
+ class Tree < Struct.new(:widget, :applied, :pending)
28
+ def record_multi
29
+ AutoSeparator.new self do |auto_separator|
30
+ yield auto_separator
31
+ end
32
+
33
+ compact!
34
+ end
35
+
36
+ def record
37
+ current = Record.new(widget, applied)
38
+
39
+ yield current
40
+
41
+ applied.next = current if applied = self.applied
42
+
43
+ self.applied = current
44
+ self.applied = current
45
+ self.pending = nil
46
+ end
47
+
48
+ # Undo last applied change so it becomes the next pending change.
49
+ # Parent of the applied change becomes the next applied change.
50
+ def undo
51
+ while applied = self.applied
52
+ applied.undo
53
+
54
+ self.pending = applied
55
+ self.applied = applied = applied.parent
56
+
57
+ break if applied && applied.separator
58
+ end
59
+ end
60
+
61
+ # Redo pending change so it becomes the new applied change.
62
+ # If the pending change has a next child, it becomes the new pending one.
63
+ def redo
64
+ while pending = self.pending
65
+ pending.redo
66
+
67
+ self.applied = pending
68
+ self.pending = pending.next
69
+
70
+ break if pending && pending.separator
71
+ end
72
+ end
73
+
74
+ # Join previous applied changes that have only one child and that modify
75
+ # data consecutive.
76
+ # This rewrites already applied history only.
77
+ def compact!
78
+ return unless applied
79
+ applied.compact!
80
+ self.pending = applied.next
81
+ end
82
+
83
+ def separate!
84
+ applied.separator = true if applied
85
+ end
86
+ end
87
+
88
+ class AutoSeparator < Struct.new(:tree, :records)
89
+ def initialize(tree)
90
+ self.tree = tree
91
+ self.records = []
92
+
93
+ yield(self) if block_given?
94
+
95
+ records.last.separator = true if records.any?
96
+ end
97
+
98
+ def insert(*args)
99
+ tree.record do |record|
100
+ record.insert(*args)
101
+ records << record
102
+ end
103
+ end
104
+
105
+ def replace(*args)
106
+ tree.record do |record|
107
+ record.replace(*args)
108
+ records << record
109
+ end
110
+ end
111
+
112
+ def delete(*args)
113
+ tree.record do |record|
114
+ record.delete(*args)
115
+ records << record
116
+ end
117
+ end
118
+ end
119
+
120
+ # Every Record is responsible for one change that it can apply or undo.
121
+ # There is only a very limited set of methods for modifications, as some of
122
+ # the destructive String methods in Ruby can have unpredictable results.
123
+ # In order to undo a change, we have to predict what the change will do
124
+ # before it happens to avoid expensive diff algorithms.
125
+ #
126
+ # A Record has one parent and a number of childs.
127
+ # If there are any childs, one of them is called current, and is the child
128
+ # that was last active, this way we can provide an intuitive way of choosing
129
+ # a child record to apply when a user wants to redo an undone change.
130
+ #
131
+ # Record has a direct pointer to the data in the tree, since it has to know
132
+ # about nothing else.
133
+ #
134
+ # Apart from that, Record also knows the time when it was created, this way
135
+ # you can move forward and backward in time.
136
+ #
137
+ # Revisions only keep the data necessary to undo/redo a change, not the whole
138
+ # data that was modified, that way it can keep overall memory-usage to a
139
+ # minimum.
140
+ #
141
+ # The applied property indicates whether or not this change has been applied
142
+ # already.
143
+ class Record < Struct.new(:widget, :parent, :ctime, :childs, :applied,
144
+ :undo_info, :redo_info, :separator)
145
+
146
+ def initialize(widget, parent = nil)
147
+ self.widget, self.parent = widget, parent
148
+ self.ctime = Time.now
149
+ self.childs = []
150
+ self.applied = false
151
+ self.separator = false
152
+ end
153
+
154
+ def insert(pos, string)
155
+ pos = widget.index(pos) unless pos.respond_to?(:to_index)
156
+
157
+ widget.execute_only(:insert, pos, string)
158
+ widget.touch!(pos)
159
+
160
+ self.redo_info = [:insert, pos, string]
161
+ self.undo_info = [pos, pos + string.size, '']
162
+ self.applied = true
163
+ end
164
+
165
+ def replace(from, to, string)
166
+ from = widget.index(from) unless from.respond_to?(:to_index)
167
+ to = widget.index(to) unless to.respond_to?(:to_index)
168
+
169
+ data = widget.get(from, to)
170
+ widget.execute_only(:replace, from, to, string)
171
+ widget.touch!(*from.upto(to))
172
+
173
+ self.redo_info = [:replace, from, to, string]
174
+ self.undo_info = [from, from + string.size, data]
175
+ self.applied = true
176
+ end
177
+
178
+ def delete(from, to)
179
+ from = widget.index(from) unless from.respond_to?(:to_index)
180
+ to = widget.index(to) unless to.respond_to?(:to_index)
181
+
182
+ data = widget.get(from, to)
183
+ widget.execute_only(:delete, from, to)
184
+ widget.touch!(*from.upto(to))
185
+
186
+ self.redo_info = [:delete, from, to]
187
+ self.undo_info = [from, from, data]
188
+ self.applied = true
189
+ end
190
+
191
+ def undo
192
+ return unless undo_info && applied
193
+
194
+ from, to, string = undo_info
195
+ widget.execute_only(:replace, from, to, string)
196
+
197
+ self.applied = false
198
+ end
199
+
200
+ def redo
201
+ return unless redo_info && !applied
202
+ send(*redo_info)
203
+ end
204
+
205
+ def compact!
206
+ return if separator
207
+ return unless parent = self.parent
208
+
209
+ pundo_from, pundo_to, pundo_string = parent.undo_info
210
+ sundo_from, sundo_to, sundo_string = undo_info
211
+
212
+ predo_name, *predo_args = parent.redo_info
213
+ sredo_name, *sredo_args = redo_info
214
+
215
+ # only compact identical methods
216
+ return unless predo_name == sredo_name
217
+
218
+ case predo_name
219
+ when :insert
220
+ predo_pos, predo_string = predo_args
221
+ sredo_pos, sredo_string = sredo_args
222
+
223
+ # the records have to be consecutive so they can still be applied by a
224
+ # single undo/redo
225
+ consecutive = (predo_pos + predo_string.size) == sredo_pos
226
+ return parent.compact! unless consecutive
227
+
228
+ redo_string = "#{predo_string}#{sredo_string}"
229
+ self.redo_info = [:insert, predo_pos, redo_string]
230
+
231
+ undo_string = "#{pundo_string}#{sundo_string}"
232
+ self.undo_info = [pundo_from, sundo_to, undo_string]
233
+ when :replace
234
+ predo_from, predo_to, predo_string = predo_args
235
+ sredo_from, sredo_to, sredo_string = sredo_args
236
+
237
+ # the records have to be consecutive so they can still be applied by a
238
+ # single undo/redo
239
+ consecutive = predo_to == sredo_from
240
+ return parent.compact! unless consecutive
241
+
242
+ redo_string = "#{predo_string}#{sredo_string}"
243
+ self.redo_info = [:replace, predo_from, sredo_to, undo_string]
244
+
245
+ undo_string = "#{pundo_string}#{sundo_string}"
246
+ self.undo_info = [pundo_from, sundo_to, undo_string]
247
+ when :delete
248
+ predo_from, predo_to = predo_args
249
+ sredo_from, sredo_to = sredo_args
250
+
251
+ consecutive = predo_to == sredo_from
252
+ return parent.compact! unless consecutive
253
+
254
+ self.redo_info = [:delete, predo_from, sredo_to]
255
+
256
+ undo_string = "#{sundo_string}#{pundo_string}"
257
+ self.undo_info = [pundo_from, sundo_to, undo_string]
258
+ else
259
+ return
260
+ end
261
+
262
+ # the parent of our parent (grandparent) becomes our parent
263
+ self.parent = grandparent = parent.parent
264
+
265
+ # recurse into a new compact cycle if we have a grandparent
266
+ if grandparent
267
+ grandparent.next = self
268
+ compact!
269
+ end
270
+ end
271
+
272
+ def next=(child)
273
+ childs.unshift(childs.delete(child) || child)
274
+ end
275
+
276
+ def next
277
+ childs.first
278
+ end
279
+
280
+ def applied?
281
+ applied
282
+ end
283
+
284
+ def inspect
285
+ "#<Undo::Record sep=%p undo=%p redo=%p>" % [separator, undo_info, redo_info]
286
+ end
287
+ end
288
+ end
289
+ end
@@ -0,0 +1,70 @@
1
+ # The MIT Licence
2
+ #
3
+ # Copyright (c) 2004-2009 Pistos
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ class SizedArray < Array
24
+ attr_reader :capacity
25
+
26
+ def initialize( capacity = 10, *args )
27
+ @capacity = capacity
28
+ super( *args )
29
+ end
30
+
31
+ def resize
32
+ if size > @capacity
33
+ slice!( (0...-@capacity) )
34
+ end
35
+ end
36
+ private :resize
37
+
38
+ def concat( other_array )
39
+ super( other_array )
40
+ resize
41
+ self
42
+ end
43
+
44
+ def fill( *args )
45
+ retval = super( *args )
46
+ resize
47
+ self
48
+ end
49
+
50
+ def <<( item )
51
+ retval = super( item )
52
+ if size > @capacity
53
+ retval = shift
54
+ end
55
+ retval
56
+ end
57
+
58
+ def push( item )
59
+ self << item
60
+ end
61
+
62
+ def unshift( item )
63
+ retval = super( item )
64
+ if size > @capacity
65
+ retval = pop
66
+ end
67
+ retval
68
+ end
69
+ end
70
+
@@ -352,7 +352,12 @@ module Textpow
352
352
  end
353
353
  end
354
354
 
355
- position = end_pos
355
+ if position >= end_pos
356
+ # raise "Parser didn't move forward on line: %p" % [line]
357
+ return
358
+ else
359
+ position = end_pos
360
+ end
356
361
  end
357
362
  end
358
363
  end
@@ -0,0 +1,3 @@
1
+ module VER
2
+ VERSION = "2009.12.14"
3
+ end
@@ -26,21 +26,25 @@ module VER
26
26
  # | @status |
27
27
  # +-----------+
28
28
  def setup
29
- setup_text
30
- # setup_scrollbars # enable if you really want some.
31
- setup_status
29
+ setup_widgets
32
30
  setup_grid
33
31
  setup_misc
34
32
  setup_events
35
33
  end
36
34
 
35
+ def setup_widgets
36
+ setup_text
37
+ setup_vertical_scrollbar if VER.options.vertical_scrollbar
38
+ setup_horizontal_scrollbar if VER.options.horizontal_scrollbar
39
+ setup_status
40
+ end
41
+
37
42
  def setup_text
38
43
  font, tabstop = VER.options.font, VER.options.tabstop
39
44
  tabs = font.measure('0') * tabstop
40
45
 
41
46
  @text = VER::Text.new(
42
47
  self,
43
- autoseparators: true, # insert separators into the undo flow
44
48
  borderwidth: 0,
45
49
  exportselection: true, # copy into X11 buffer automatically
46
50
  font: font,
@@ -50,17 +54,16 @@ module VER
50
54
  takefocus: true,
51
55
  tabs: tabs,
52
56
  tabstyle: :wordprocessor,
53
- undo: true, # enable undo capabilities
54
57
  wrap: :word
55
58
  )
56
59
  end
57
60
 
58
- def setup_scrollbars
59
- # vertical scrollbar
61
+ def setup_vertical_scrollbar
60
62
  @ybar = Tk::Tile::YScrollbar.new(self)
61
63
  @text.yscrollbar(@ybar)
64
+ end
62
65
 
63
- # horizontal scrollbar
66
+ def setup_horizontal_scrollbar
64
67
  @xbar = Tk::Tile::XScrollbar.new(self)
65
68
  @text.xscrollbar(@xbar)
66
69
  end
@@ -1,5 +1,12 @@
1
1
  module VER
2
2
  class View::List::Grep < View::List
3
+ def initialize(parent, glob = nil, &block)
4
+ super(parent, &block)
5
+
6
+ @glob = nil
7
+ @glob = glob.to_s unless glob.nil?
8
+ end
9
+
3
10
  def update
4
11
  list.clear
5
12
 
@@ -17,11 +24,15 @@ module VER
17
24
  def grep(input)
18
25
  @choices = []
19
26
 
20
- input, query = input.split(/ /, 2)
21
- input, query = nil, input unless query
22
- input ||= '*'
27
+ if @glob
28
+ input, query = @glob, input
29
+ else
30
+ input, query = input.split(/ /, 2)
31
+ input, query = nil, input unless query
32
+ input ||= '*'
23
33
 
24
- return [] if !query || query.size < 3 # protect a little
34
+ return [] if !query || query.size < 3 # protect a little
35
+ end
25
36
 
26
37
  regex = /#{Regexp.escape(query)}/
27
38