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,49 @@
1
+ # $Id: lined.rb,v 1.5 2005/07/01 22:06:45 eric_mahurin Exp $
2
+
3
+ require 'cursor'
4
+ require 'cursor/usedeleteinsert'
5
+
6
+ class Cursor
7
+ # This class tracks the current line and column. Both line and column
8
+ # start at 0. When a newline is found, the line is incremented and the
9
+ # column is reset. With other characters, the column is incremented.
10
+ # The line and column numbers are only tracked when reading forward, but
11
+ # using #position (and friends) will hold the line and column.
12
+ class Lined < Cursor
13
+ include UseDeleteInsert
14
+ # Create a new Cursor from another that tracks line and column.
15
+ # +newline+ can be any valid argument for String#index. For example,
16
+ # +newline+=+/\n|\r(?!\n)/+ could be used for unix, mac, dos/cpm style
17
+ # newlines.
18
+ def initialize(cursor,newline=?\n)
19
+ @cursor = cursor
20
+ @newline = newline
21
+ prop(:line,0)
22
+ prop(:column,0)
23
+ end
24
+ # :stopdoc:
25
+ protected
26
+ def _delete1after?
27
+ @cursor.delete1after?
28
+ end
29
+ def _delete1before?
30
+ @cursor.delete1before?
31
+ end
32
+ def _insert1before(v)
33
+ if @newline==v
34
+ prop(:line,prop(:line)+1)
35
+ prop(:column,0)
36
+ else
37
+ prop(:column,prop(:column)+1)
38
+ end
39
+ @cursor.insert1before(v)
40
+ end
41
+ def _insert1after(v)
42
+ @cursor.insert1after(v)
43
+ end
44
+ public
45
+ # :startdoc:
46
+ end
47
+ end
48
+
49
+
@@ -0,0 +1,62 @@
1
+ # $Id: linked.rb,v 1.3 2005/07/21 15:15:38 eric_mahurin Exp $
2
+
3
+ require 'cursor'
4
+ require 'cursor/usedeleteinsert'
5
+
6
+ class Cursor
7
+ # Double-linked list
8
+ class Linked < Cursor
9
+ include UseDeleteInsert
10
+ def initialize(before=[],after=before.class.new)
11
+ @next = nil
12
+ @prev = nil
13
+ @data_class = before.class
14
+ write(before,false,nil)
15
+ write(after,true,nil)
16
+ end
17
+ # :stopdoc:
18
+ def new_data
19
+ @data_class.new
20
+ end
21
+ protected
22
+ def _delete1after?
23
+ if @next
24
+ begin
25
+ @next[1]
26
+ ensure
27
+ @next = @next[2]
28
+ @next[0] = @prev if @next
29
+ @prev[2] = @next if @prev
30
+ end
31
+ end
32
+ end
33
+ def _delete1before?
34
+ if @prev
35
+ begin
36
+ @prev[1]
37
+ ensure
38
+ @prev = @prev[0]
39
+ @next[0] = @prev if @next
40
+ @prev[2] = @next if @prev
41
+ end
42
+ end
43
+ end
44
+ def _insert1before(v)
45
+ node = [@prev,v,@next]
46
+ @prev[2] = node if @prev
47
+ @next[0] = node if @next
48
+ @prev = node
49
+ true
50
+ end
51
+ def _insert1after(v)
52
+ node = [@prev,v,@next]
53
+ @prev[2] = node if @prev
54
+ @next[0] = node if @next
55
+ @next = node
56
+ true
57
+ end
58
+ # :startdoc:
59
+ end
60
+ end
61
+
62
+
@@ -0,0 +1,145 @@
1
+ # $Id: position.rb,v 1.18 2005/07/18 14:46:28 eric_mahurin Exp $
2
+
3
+ require 'cursor'
4
+
5
+ class Cursor
6
+ # Objects in this class are mainly used to simply mark/remember the location
7
+ # of a parent cursor. But, this class also has the fully functionality of the
8
+ # parent. When this child wants to do an operation, it uses the parent to
9
+ # do it and returns the parent to where it was.
10
+ class Position < Cursor # :nodoc:
11
+ def initialize(parent,reverse=false)
12
+ @parent = parent
13
+ @anchor_after = reverse
14
+ @pos = @parent.__send__(:pos)
15
+ prop(nil,@parent.prop)
16
+ end
17
+ def new_data
18
+ @parent.new_data
19
+ end
20
+ public
21
+ localMethods = %w(
22
+ prop pos pos= to_s to_i position position= position? position!
23
+ close closed? each collect! map!)
24
+ stableMethods = %w(
25
+ read1after read1before skip1after skip1before
26
+ write1after write1before write1after? write1before?
27
+ position pos to_i begin end begin? end? succ pred + - <=>
28
+ )
29
+ stableMethods = %w()
30
+ anywhereMethods = %w(
31
+ replace clear empty? size length begin end position! close closed?
32
+ )
33
+ anywhereMethods = %w()
34
+ selfMethods = %w(
35
+ >> << begin! end! succ! pred! replace
36
+ )
37
+ repositionMethods = Cursor.public_instance_methods(false)
38
+ repositionMethods -= anywhereMethods
39
+ repositionMethods -= localMethods
40
+ repositionMethods.each { |m|
41
+ and_self = selfMethods.include?(m) ? " and self" : ""
42
+ update = stableMethods.include?(m) ? "" : "
43
+ ensure
44
+ self.position = @parent
45
+ "
46
+ eval("def #{m}(*args,&block)
47
+ @parent.position {
48
+ @parent.position = self
49
+ begin
50
+ @parent.__send__(#{m.to_sym.inspect},*args,&block)
51
+ #{update}
52
+ end
53
+ }#{and_self}
54
+ end")
55
+ }
56
+ anywhereMethods -= localMethods
57
+ anywhereMethods.each { |m|
58
+ and_self = selfMethods.include?(m) ? " and self" : ""
59
+ eval("def #{m}(*args,&block)
60
+ @parent.__send__(#{m.to_sym.inspect},*args,&block)#{and_self}
61
+ end")
62
+ }
63
+
64
+ def pos(reverse=false)
65
+ if reverse.nil? ? @anchor_after : reverse
66
+ (@pos.to_i-@parent.size).nonzero? || -0.0
67
+ else
68
+ @pos
69
+ end
70
+ end
71
+ def pos=(p)
72
+ if (p.nonzero?||1.0/p)<0
73
+ @anchor_after = true
74
+ @pos = p.to_i+@parent.size
75
+ p
76
+ else
77
+ @anchor_after = false
78
+ @pos = p
79
+ end
80
+ end
81
+ def position(reverse=false,&code) # :yield:
82
+ p = @parent.position {
83
+ @parent.position = self
84
+ @parent.position(reverse)
85
+ }
86
+ if code
87
+ begin
88
+ code[]
89
+ ensure
90
+ begin
91
+ self.position = p
92
+ ensure
93
+ p.close
94
+ end
95
+ end
96
+ else
97
+ p
98
+ end
99
+ end
100
+ def position?(p=nil,&code) # :yield:
101
+ if code
102
+ super
103
+ elsif p
104
+ @parent.position?(p)
105
+ else
106
+ nil
107
+ end
108
+ end
109
+ def position!(p=nil)
110
+ if p
111
+ @parent.position!(p)
112
+ self
113
+ else
114
+ nil
115
+ end
116
+ end
117
+ def close
118
+ @parent.position!(self)
119
+ super
120
+ end
121
+ protected
122
+ def _deletion(pos,len=1,reverse=false,dummy=nil)
123
+ if @pos==pos
124
+ @anchor_after = false
125
+ elsif @pos>pos
126
+ @pos -= len
127
+ if @pos<pos
128
+ @pos = pos
129
+ @anchor_after = !reverse
130
+ elsif @pos==pos
131
+ @anchor_after = true
132
+ end
133
+ end
134
+ nil
135
+ end
136
+ def _insertion(pos,len=1,dummmy=nil)
137
+ if @pos>=pos+(@anchor_after ? 0 : 1)
138
+ @pos += len
139
+ end
140
+ nil
141
+ end
142
+ end
143
+ end
144
+
145
+
@@ -0,0 +1,122 @@
1
+ # $Id: reversed.rb,v 1.10 2005/07/21 15:15:38 eric_mahurin Exp $
2
+
3
+ require 'cursor'
4
+
5
+ class Cursor
6
+ # This class can be used to reverse the direction of operations on a given
7
+ # cursor. It operates on the given cursor directly moving it around.
8
+ class Reversed < Cursor
9
+ def initialize(cursor)
10
+ @cursor = cursor
11
+ end
12
+ # :stopdoc:
13
+ def new_data
14
+ @cursor.new_data
15
+ end
16
+ def read1next
17
+ @cursor.read1prev
18
+ end
19
+ def read1prev
20
+ @cursor.read1next
21
+ end
22
+ def read1after
23
+ @cursor.read1before
24
+ end
25
+ def read1before
26
+ @cursor.read1after
27
+ end
28
+ def skip1next
29
+ @cursor.skip1prev
30
+ end
31
+ def skip1prev
32
+ @cursor.skip1next
33
+ end
34
+ def skip1after
35
+ @cursor.skip1before
36
+ end
37
+ def skip1before
38
+ @cursor.skip1after
39
+ end
40
+ def delete1after
41
+ v0 = @cursor.delete1before
42
+ v0 && @positions && _adjust_delete
43
+ v0
44
+ end
45
+ def delete1before
46
+ v0 = @cursor.delete1after
47
+ v0 && @positions && _adjust_delete
48
+ v0
49
+ end
50
+ def delete1after?
51
+ v0 = @cursor.delete1before?
52
+ v0.nil? || @positions && _adjust_delete
53
+ v0
54
+ end
55
+ def delete1before?
56
+ v0 = @cursor.delete1after?
57
+ v0.nil? || @positions && _adjust_delete
58
+ v0
59
+ end
60
+ def write1next(v)
61
+ @cursor.write1prev(v)
62
+ end
63
+ def write1prev(v)
64
+ @cursor.write1next(v)
65
+ end
66
+ def write1after(v)
67
+ @cursor.write1before(v)
68
+ end
69
+ def write1before(v)
70
+ @cursor.write1after(v)
71
+ end
72
+ def write1next?(v)
73
+ @cursor.write1prev?(v)
74
+ end
75
+ def write1prev?(v)
76
+ @cursor.write1next?(v)
77
+ end
78
+ def write1after?(v)
79
+ @cursor.write1before?(v)
80
+ end
81
+ def write1before?(v)
82
+ @cursor.write1after?(v)
83
+ end
84
+ def insert1before(v)
85
+ @positions && _adjust_insert
86
+ @cursor.insert1after(v)
87
+ end
88
+ def insert1after(v)
89
+ @positions && _adjust_insert
90
+ @cursor.insert1before(v)
91
+ end
92
+ def scan1next(v)
93
+ @cursor.scan1prev(v)
94
+ end
95
+ def scan1prev(v)
96
+ @cursor.scan1next(v)
97
+ end
98
+ def modify1next(lookup)
99
+ @cursor.modify1prev(lookup)
100
+ end
101
+ def modify1prev(lookup)
102
+ @cursor.modify1next(lookup)
103
+ end
104
+ def pos(reverse=false) # :yield:
105
+ -(@cursor.pos(!reverse).nonzero? or return(reverse ? -0.0 : 0))
106
+ end
107
+ def pos=(p)
108
+ if p.zero?
109
+ @cursor.pos = ((1.0/p)<0) ? 0 : -0.0
110
+ else
111
+ @cursor.pos = -p
112
+ end
113
+ p
114
+ end
115
+ def closed?
116
+ super or @cursor.closed?
117
+ end
118
+ # :startdoc:
119
+ end
120
+ end
121
+
122
+
@@ -0,0 +1,40 @@
1
+ # $Id: shifting.rb,v 1.3 2005/07/21 15:15:38 eric_mahurin Exp $
2
+
3
+ require 'cursor'
4
+ require 'cursor/usedeleteinsert'
5
+
6
+ class Cursor
7
+ # This Cursor class puts a cursor at the ends of an Array/String (or something
8
+ # like those). Assuming insertions/deletions are efficient at both ends of that
9
+ # structure, all insertions/deletions at the cursor will be also.
10
+ class Shifting < Cursor
11
+ include UseDeleteInsert
12
+ def initialize(data=[],pos0=0)
13
+ @data = data
14
+ @pos0 = pos0
15
+ end
16
+ # :stopdoc:
17
+ def new_data
18
+ @data.class.new
19
+ end
20
+ protected
21
+ def _delete1after?
22
+ @pos0.nonzero? && (@pos0 -= 1) && @data.slice!(0)
23
+ end
24
+ def _delete1before?
25
+ @pos0==@data.size ? nil : @data.slice!(-1)
26
+ end
27
+ def _insert1before(v)
28
+ @data << v
29
+ true
30
+ end
31
+ def _insert1after(v)
32
+ @data[0,0] = (@data.class.new << v)
33
+ @pos0 += 1
34
+ true
35
+ end
36
+ # :startdoc:
37
+ end
38
+ end
39
+
40
+
@@ -0,0 +1,45 @@
1
+ # $Id: split.rb,v 1.3 2005/07/21 15:15:38 eric_mahurin Exp $
2
+
3
+ require 'cursor'
4
+ require 'cursor/usedeleteinsert'
5
+
6
+ class Cursor
7
+ # This Cursor class uses an Array/String for data before the cursor
8
+ # and another one for data after the cursor. The result of this is that
9
+ # data is only deleted/inserted at the end of these 2. Because of that
10
+ # most operations have similar expense and are linear with respect to the
11
+ # number of elements being moved, inserted, deleted, replaced, etc.
12
+ class Split < Cursor
13
+ include UseDeleteInsert
14
+ def initialize(before=[],after=before.class.new)
15
+ @before = before
16
+ @after = after
17
+ end
18
+ # :stopdoc:
19
+ def new_data
20
+ @before.class.new
21
+ end
22
+ protected
23
+ def _delete1after?
24
+ @after.slice!(-1)
25
+ end
26
+ def _delete1before?
27
+ @before.slice!(-1)
28
+ end
29
+ def _insert1before(v)
30
+ @before << v
31
+ true
32
+ end
33
+ def _insert1after(v)
34
+ @after << v
35
+ true
36
+ end
37
+ public
38
+ def pos(reverse=false)
39
+ reverse ? -(@after.size.nonzero?||0.0) : @before.size
40
+ end
41
+ # :startdoc:
42
+ end
43
+ end
44
+
45
+