cursor 0.6 → 0.8

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.
@@ -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
+