cursor 0.6 → 0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,105 @@
1
+ # $Id: position.rb,v 1.2 2005/07/18 14:46:28 eric_mahurin Exp $
2
+
3
+ require 'cursor/circular'
4
+
5
+ class Cursor
6
+ class Circular
7
+ class Position < Cursor::Position # :nodoc:
8
+ def initialize(parent,reverse=false)
9
+ @parent = parent
10
+ @anchor_after = reverse
11
+ @pos = @parent.__send__(:_pos)
12
+ if @anchor_after
13
+ if @pos==@parent.size
14
+ if @pos.zero?
15
+ @anchor_after = false
16
+ else
17
+ @pos = 0
18
+ end
19
+ end
20
+ else
21
+ @pos = @parent.size if @pos.zero?
22
+ end
23
+ prop(nil,@parent.prop)
24
+ end
25
+ def position=(p)
26
+ self._pos = p.__send__(:_pos,nil)
27
+ self.prop(nil,p.prop)
28
+ nil
29
+ end
30
+ def pos(reverse=false)
31
+ reverse ? -0.0 : 0
32
+ end
33
+ def pos=(p)
34
+ skip(p)
35
+ p
36
+ end
37
+ protected
38
+ def _pos(reverse=false)
39
+ if reverse.nil? ? @anchor_after : reverse
40
+ (@pos.to_i-@parent.size).nonzero? || -0.0
41
+ else
42
+ @pos
43
+ end
44
+ end
45
+ def _pos=(p)
46
+ if (p.nonzero?||1.0/p)<0
47
+ @anchor_after = true
48
+ @pos = p.to_i
49
+ if @pos.zero?
50
+ @anchor_after = false if @parent.size.zero?
51
+ else
52
+ @pos += @parent.size
53
+ end
54
+ else
55
+ @anchor_after = false
56
+ @pos = p.nonzero? || @parent.size
57
+ end
58
+ p
59
+ end
60
+ def _deletion(pos,len=1,reverse=false,size=nil)
61
+ if @pos==pos
62
+ @anchor_after = false
63
+ @pos = (size ||= @parent.size) if @pos.zero?
64
+ elsif @pos>pos
65
+ @pos -= len
66
+ if @pos<pos
67
+ @pos = pos
68
+ if @anchor_after==reverse
69
+ @anchor_after = !reverse
70
+ if @anchor_after
71
+ if @pos==(size ||= @parent.size)
72
+ if @pos.zero?
73
+ @anchor_after = false
74
+ else
75
+ @pos = 0
76
+ end
77
+ end
78
+ else
79
+ @pos = (size ||= @parent.size) if @pos.zero?
80
+ end
81
+ end
82
+ elsif @pos==pos && !@anchor_after
83
+ @anchor_after = true
84
+ if @pos==(size ||= @parent.size)
85
+ if @pos.zero?
86
+ @anchor_after = false
87
+ else
88
+ @pos = 0
89
+ end
90
+ end
91
+ end
92
+ end
93
+ size
94
+ end
95
+ def _insertion(pos,len=1,dummy=nil)
96
+ if @pos>=pos+((@anchor_after||@pos.zero?) ? 0 : 1)
97
+ @pos += len
98
+ end
99
+ nil
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+
@@ -0,0 +1,48 @@
1
+ # $Id: shifting.rb,v 1.4 2005/07/21 15:15:38 eric_mahurin Exp $
2
+
3
+ require 'cursor/circular'
4
+ require 'cursor/usedeleteinsert'
5
+
6
+ class Cursor
7
+ class Circular
8
+ # This Cursor class puts a cursor at the ends of an Array/String (or something
9
+ # like those). Assuming insertions/deletions are efficient at both ends of that
10
+ # structure, all insertions/deletions at the cursor will be also.
11
+ class Shifting < Circular
12
+ include UseDeleteInsert
13
+ def initialize(data=[],pos0=0)
14
+ @data = data
15
+ @pos0 = pos0
16
+ end
17
+ # :stopdoc:
18
+ def new_data
19
+ @data.class.new
20
+ end
21
+ protected
22
+ def _delete1after?
23
+ @pos0 = (@data.size.nonzero?||return) if @pos0.zero?
24
+ @pos0 -= 1
25
+ @data.slice!(0)
26
+ end
27
+ def _delete1before?
28
+ @pos0 = 0 if @pos0==@data.size
29
+ @data.slice!(-1)
30
+ end
31
+ def _insert1before(v)
32
+ @data << v
33
+ true
34
+ end
35
+ def _insert1after(v)
36
+ @data[0,0] = (@data.class.new << v)
37
+ @pos0 += 1
38
+ true
39
+ end
40
+ def _pos(reverse=false)
41
+ reverse ? -(@pos0.nonzero?||0.0) : @data.size-@pos0
42
+ end
43
+ # :startdoc:
44
+ end
45
+ end
46
+ end
47
+
48
+
@@ -0,0 +1,106 @@
1
+ # $Id: split.rb,v 1.3 2005/07/18 14:46:28 eric_mahurin Exp $
2
+
3
+ require 'cursor/circular'
4
+ require 'cursor/usedeleteinsert'
5
+
6
+ class Cursor
7
+ class Circular
8
+ # This Cursor class uses an Array/String for data before the cursor
9
+ # and another one for data after the cursor. The result of this is that
10
+ # data is only deleted/inserted at the end of these 2. Because of that
11
+ # most operations have similar expense and are linear with respect to the
12
+ # number of elements being moved, inserted, deleted, replaced, etc.
13
+ class Split < Circular
14
+ include UseDeleteInsert
15
+ def initialize(before=[],after=before.class.new)
16
+ @before = before
17
+ @after = after
18
+ @middle = before.class.new
19
+ @middle_start = nil
20
+ @middle_before = false
21
+ @size = @before.size+@after.size
22
+ @pos0 = @after.size
23
+ end
24
+ # :stopdoc:
25
+ def new_data
26
+ @before.class.new
27
+ end
28
+ protected
29
+ def _delete1after?
30
+ @pos0 = (@size.nonzero?||return) if @pos0.zero?
31
+ @pos0 -= 1
32
+ @size -= 1
33
+ v = @after.slice!(-1)
34
+ if v.nil?
35
+ if !@middle_start
36
+ @before,@middle = @middle,@before
37
+ @middle_before = true
38
+ @middle_start = 0
39
+ end
40
+ if @middle_before
41
+ v = @middle[@middle_start]
42
+ @middle_start += 1
43
+ else
44
+ v = @middle.slice!(-1)
45
+ end
46
+ if @middle_start>=@middle.size
47
+ @middle.replace(@middle.class.new)
48
+ @middle_start = nil
49
+ end
50
+ end
51
+ v
52
+ end
53
+ def _delete1before?
54
+ if @pos0==@size
55
+ return if @size.zero?
56
+ @pos0 = 0
57
+ end
58
+ @size -= 1
59
+ v = @before.slice!(-1)
60
+ if v.nil?
61
+ if !@middle_start
62
+ @after,@middle = @middle,@after
63
+ @middle_before = false
64
+ @middle_start = 0
65
+ end
66
+ if !@middle_before
67
+ v = @middle[@middle_start]
68
+ @middle_start += 1
69
+ else
70
+ v = @middle.slice!(-1)
71
+ end
72
+ if @middle_start>=@middle.size
73
+ @middle.replace(@middle.class.new)
74
+ @middle_start = nil
75
+ end
76
+ end
77
+ v
78
+ end
79
+ def _insert1before(v)
80
+ @size += 1
81
+ if !@middle_before and @middle_start and @middle_start.nonzero?
82
+ @middle[@middle_start -= 1] = v
83
+ else
84
+ @before << v
85
+ end
86
+ true
87
+ end
88
+ def _insert1after(v)
89
+ @pos0 += 1
90
+ @size += 1
91
+ if @middle_before and @middle_start and @middle_start.nonzero?
92
+ @middle[@middle_start -= 1] = v
93
+ else
94
+ @after << v
95
+ end
96
+ true
97
+ end
98
+ def _pos(reverse=false)
99
+ reverse ? -(@pos0.nonzero?||0.0) : @size-@pos0
100
+ end
101
+ # :startdoc:
102
+ end
103
+ end
104
+ end
105
+
106
+
@@ -0,0 +1,52 @@
1
+ # $Id: indexed.rb,v 1.7 2005/07/21 15:15:38 eric_mahurin Exp $
2
+
3
+ require 'cursor'
4
+ require 'cursor/usedeleteinsert'
5
+
6
+ class Cursor
7
+ # This class puts a cursor on an Array or String.
8
+ class Indexed < Cursor
9
+ include UseDeleteInsert
10
+ def initialize(data=[],pos=0)
11
+ @data = data
12
+ @pos = pos
13
+ end
14
+ # :stopdoc:
15
+ def new_data
16
+ @data.class.new
17
+ end
18
+ protected
19
+ def _delete1after?
20
+ @data.slice!(@pos)
21
+ end
22
+ def _delete1before?
23
+ @pos==0 ? nil : @data.slice!(@pos-=1)
24
+ end
25
+ def _insert1before(v)
26
+ @data[@pos,0] = (new_data << v)
27
+ @pos += 1
28
+ true
29
+ end
30
+ def _insert1after(v)
31
+ @data[@pos,0] = (new_data << v)
32
+ true
33
+ end
34
+ # :startdoc:
35
+ end
36
+ end
37
+
38
+ class Array
39
+ # convert an array to a cursor starting at +pos+
40
+ def to_cursor(pos=0)
41
+ Cursor::Indexed.new(self,pos)
42
+ end
43
+ end
44
+
45
+ class String
46
+ # convert a string to a cursor starting at +pos+
47
+ def to_cursor(pos=0)
48
+ Cursor::Indexed.new(self,pos)
49
+ end
50
+ end
51
+
52
+
@@ -0,0 +1,342 @@
1
+ # $Id: io.rb,v 1.15 2005/07/21 15:15:38 eric_mahurin Exp $
2
+
3
+ require 'cursor'
4
+ require 'cursor/usenext'
5
+
6
+ class Cursor
7
+ # This class treats an IO (or StringIO) as a Cursor. An IO is already
8
+ # like a Cursor, but doesn't have as robust an interface. Keep in mind that deleting and
9
+ # inserting is a slow/painful process.
10
+ class IO < Cursor
11
+ include UseNext
12
+ def initialize(io)
13
+ @io = io
14
+ end
15
+ # :stopdoc:
16
+ def new_data
17
+ String.new
18
+ end
19
+ protected
20
+ def _delete1after?
21
+ ret = @io.getc or return(nil)
22
+ after = 0
23
+ while c = @io.getc
24
+ after += 1
25
+ @io.seek(-2,::IO::SEEK_CUR)
26
+ @io.putc(c)
27
+ @io.seek(+1,::IO::SEEK_CUR)
28
+ end
29
+ @io.seek(-1,::IO::SEEK_CUR)
30
+ @io.truncate(@io.pos)
31
+ @io.seek(-after,::IO::SEEK_CUR)
32
+ ret
33
+ end
34
+ def _insert1before(v)
35
+ after = 0
36
+ while c = @io.getc
37
+ after += 1
38
+ @io.seek(-1,::IO::SEEK_CUR)
39
+ @io.putc(v)
40
+ v = c
41
+ end
42
+ @io.putc(v)
43
+ @io.seek(-after,::IO::SEEK_CUR)
44
+ true
45
+ end
46
+ public
47
+ def read1next
48
+ @io.getc
49
+ end
50
+ def write1next(v)
51
+ @io.eof? ? nil : (@io.putc(v);true)
52
+ end
53
+ def write1next!(v)
54
+ @io.putc(v)
55
+ true
56
+ end
57
+ def skip1prev
58
+ @io.pos.nonzero? && (@io.seek(-1,::IO::SEEK_CUR);true)
59
+ end
60
+ def read1after
61
+ v0 = @io.getc
62
+ v0 && @io.ungetc(v0)
63
+ v0
64
+ end
65
+ def write1after!(v)
66
+ @io.putc(v)
67
+ @io.seek(-1,::IO::SEEK_CUR)
68
+ true
69
+ end
70
+ def skip1next
71
+ @io.getc ? true : nil
72
+ end
73
+ def skip1after
74
+ @io.eof? ? nil : true
75
+ end
76
+ def skip1before
77
+ @io.pos.zero? ? nil : true
78
+ end
79
+ def read(len,hold=false,buffer=nil)
80
+ len.nonzero? or return(buffer||"")
81
+ reverse = len<0
82
+ len = len.abs
83
+ if reverse
84
+ p0 = @io.pos
85
+ len = p0.nonzero? or return if (p0-len)<0
86
+ @io.seek(-len,::IO::SEEK_CUR)
87
+ buffer1 = @io.read(len)
88
+ if hold.nil?
89
+ buffer2 = @io.read(nil)
90
+ len2 = buffer2.size
91
+ @io.seek(-(len+len2),::IO::SEEK_CUR)
92
+ @io.write(buffer2)
93
+ @io.truncate(@io.pos)
94
+ @io.seek(-len2,::IO::SEEK_CUR)
95
+ @positions && _adjust_delete(len,reverse)
96
+ elsif !hold
97
+ @io.seek(-len,::IO::SEEK_CUR)
98
+ end
99
+ buffer1.reverse!
100
+ else
101
+ buffer1 = @io.read(len) or return
102
+ len = buffer1.size
103
+ if hold.nil?
104
+ buffer2 = @io.read(nil)
105
+ len2 = buffer2.size
106
+ @io.seek(-(len+len2),::IO::SEEK_CUR)
107
+ @io.write(buffer2)
108
+ @io.truncate(@io.pos)
109
+ @io.seek(-len2,::IO::SEEK_CUR)
110
+ @positions && _adjust_delete(len,reverse)
111
+ elsif hold
112
+ @io.seek(-len,::IO::SEEK_CUR)
113
+ end
114
+ end
115
+ if buffer
116
+ if String===buffer
117
+ buffer.concat(buffer1)
118
+ else
119
+ buffer1.each_byte { |c| buffer << c }
120
+ end
121
+ else
122
+ buffer = buffer1
123
+ end
124
+ buffer
125
+ end
126
+ def read!(reverse=false,hold=false,buffer=new_data)
127
+ if reverse
128
+ len = @io.pos.nonzero? or return
129
+ @io.seek(0,::IO::SEEK_SET)
130
+ #@io.pos = 0 # BUGGY in v1.8.2
131
+ buffer1 = @io.read(len) or return
132
+ if hold.nil?
133
+ buffer2 = @io.read(nil)
134
+ len2 = buffer2.size
135
+ @io.seek(-(len+len2),::IO::SEEK_CUR)
136
+ @io.write(buffer2)
137
+ @io.truncate(@io.pos)
138
+ @io.seek(-len2,::IO::SEEK_CUR)
139
+ @positions && _adjust_delete(len,reverse)
140
+ elsif !hold
141
+ @io.seek(-len,::IO::SEEK_CUR)
142
+ end
143
+ buffer1.reverse!
144
+ else
145
+ buffer1 = @io.read(nil)
146
+ len = buffer1.size.nonzero? or return
147
+ if hold.nil?
148
+ @io.seek(-len,::IO::SEEK_CUR)
149
+ @io.truncate(@io.pos)
150
+ @positions && _adjust_delete(len,reverse)
151
+ elsif hold
152
+ @io.seek(-len,::IO::SEEK_CUR)
153
+ end
154
+ end
155
+ if buffer
156
+ if String===buffer
157
+ buffer.concat(buffer1)
158
+ else
159
+ buffer1.each_byte { |c| buffer << c }
160
+ end
161
+ else
162
+ buffer = buffer1
163
+ end
164
+ buffer
165
+ end
166
+ def skip(len,hold=false)
167
+ len.nonzero? or return(0)
168
+ reverse = len<0
169
+ len = len.abs
170
+ if reverse
171
+ p0 = @io.pos
172
+ len = p0.nonzero? or return if (p0-len)<0
173
+ if hold.nil?
174
+ buffer2 = @io.read(nil)
175
+ len2 = buffer2.size
176
+ @io.seek(-(len+len2),::IO::SEEK_CUR)
177
+ @io.write(buffer2)
178
+ @io.truncate(@io.pos)
179
+ @io.seek(-len2,::IO::SEEK_CUR)
180
+ @positions && _adjust_delete(len,reverse)
181
+ elsif !hold
182
+ @io.seek(-len,::IO::SEEK_CUR)
183
+ end
184
+ else
185
+ @io.seek(len,::IO::SEEK_CUR)
186
+ if @io.eof?
187
+ p0 = @io.pos
188
+ @io.seek(0,::IO::SEEK_END)
189
+ len -= p0-@io.pos
190
+ len.nonzero? or return
191
+ end
192
+ if hold.nil?
193
+ buffer2 = @io.read(nil)
194
+ len2 = buffer2.size
195
+ @io.seek(-(len+len2),::IO::SEEK_CUR)
196
+ @io.write(buffer2)
197
+ @io.truncate(@io.pos)
198
+ @io.seek(-len2,::IO::SEEK_CUR)
199
+ @positions && _adjust_delete(len,reverse)
200
+ elsif hold
201
+ @io.seek(-len,::IO::SEEK_CUR)
202
+ end
203
+ end
204
+ len
205
+ end
206
+ def skip!(reverse=false,hold=false)
207
+ if reverse
208
+ len = @io.pos.nonzero? or return
209
+ if hold.nil?
210
+ buffer2 = @io.read(nil)
211
+ len2 = buffer2.size
212
+ @io.seek(-(len+len2),::IO::SEEK_CUR)
213
+ @io.write(buffer2)
214
+ @io.truncate(@io.pos)
215
+ @io.seek(-len2,::IO::SEEK_CUR)
216
+ @positions && _adjust_delete(len,reverse)
217
+ elsif !hold
218
+ @io.seek(0,::IO::SEEK_SET)
219
+ end
220
+ else
221
+ p0 = @io.pos
222
+ @io.seek(0,::IO::SEEK_END)
223
+ len = @io.pos-p0
224
+ len.nonzero? or return
225
+ @io.seek(-len,::IO::SEEK_CUR) if hold!=false
226
+ if hold.nil?
227
+ @io.truncate(@io.pos)
228
+ @positions && _adjust_delete(len,reverse)
229
+ end
230
+ end
231
+ len
232
+ end
233
+ def write(value,reverse=false,hold=false,overwrite_only=false)
234
+ if String===value
235
+ value1 = reverse ? value.reverse : value
236
+ len = value.size
237
+ else
238
+ value1 = ""
239
+ len = 0;
240
+ until (v = value[len]).nil?
241
+ value1 << v
242
+ len += 1
243
+ end
244
+ value1 = value1.reverse if reverse
245
+ end
246
+ if reverse
247
+ if hold.nil?
248
+ @positions && _adjust_insert(len)
249
+ buffer2 = @io.read(nil)
250
+ len2 = buffer2.size
251
+ @io.seek(-len2,::IO::SEEK_CUR)
252
+ @io.write(value1)
253
+ @io.write(buffer2)
254
+ @io.seek(-(len+len2),::IO::SEEK_CUR)
255
+ else
256
+ len_overwrite = @io.pos
257
+ len_insert = len-len_overwrite
258
+ if len_insert<=0
259
+ @io.seek(-len,::IO::SEEK_CUR)
260
+ @io.write(value1)
261
+ else
262
+ @io.seek(-len_overwrite,::IO::SEEK_CUR)
263
+ if overwrite_only
264
+ len = len_overwrite.nonzero? or return
265
+ else
266
+ @positions && _adjust_insert(len_insert)
267
+ buffer2 = @io.read(nil)
268
+ len2 = buffer2.size
269
+ @io.seek(-len2,::IO::SEEK_CUR)
270
+ @io.write(value1[0,len_insert])
271
+ @io.write(buffer2)
272
+ @io.seek(-len2,::IO::SEEK_CUR)
273
+ end
274
+ @io.write(value1[len_insert,len_overwrite])
275
+
276
+ end
277
+ @io.seek(-len,::IO::SEEK_CUR) if !hold
278
+ end
279
+ else
280
+ if hold.nil?
281
+ @positions && _adjust_insert(len)
282
+ buffer2 = @io.read(nil)
283
+ len2 = buffer2.size
284
+ @io.seek(-len2,::IO::SEEK_CUR)
285
+ @io.write(value1)
286
+ @io.write(buffer2)
287
+ @io.seek(-len2,::IO::SEEK_CUR)
288
+ else
289
+ if overwrite_only
290
+ len.nonzero? or return(0)
291
+ @io.seek(len,::IO::SEEK_CUR)
292
+ if @io.eof?
293
+ p0 = @io.pos
294
+ @io.seek(0,::IO::SEEK_END)
295
+ len -= p0-@io.pos
296
+ len.nonzero? or return
297
+ value1 = value1[0,len]
298
+ end
299
+ @io.seek(-len,::IO::SEEK_CUR)
300
+ end
301
+ @io.write(value1)
302
+ @io.seek(-len,::IO::SEEK_CUR) if hold
303
+ end
304
+ end
305
+ len
306
+ end
307
+ def scan_until(value,reverse=false,hold=false,buffer=nil)
308
+ if String===value && !reverse && hold==false && !buffer && !value.empty?
309
+ @io.gets(value)
310
+ else
311
+ super(value,reverse,hold,buffer||value.class.new)
312
+ end
313
+ end
314
+ def pos=(p)
315
+ @io.seek(p,(p.nonzero?||1.0/p)<0 ? ::IO::SEEK_END : ::IO::SEEK_SET)
316
+ p
317
+ end
318
+
319
+ public
320
+ def close
321
+ @io.close
322
+ super
323
+ end
324
+ # :startdoc:
325
+ end
326
+ end
327
+
328
+ class IO
329
+ # convert an IO to a cursor
330
+ def to_cursor
331
+ Cursor::IO.new(self)
332
+ end
333
+ end
334
+
335
+ class StringIO
336
+ # convert an IO to a cursor
337
+ def to_cursor
338
+ Cursor::IO.new(self)
339
+ end
340
+ end
341
+
342
+