blob: bb3684b42bfc40c5e8a5f2d08034c930e51958a1 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
class Reline::KillRing
include Enumerable
module State
FRESH = :fresh
CONTINUED = :continued
PROCESSED = :processed
YANK = :yank
end
RingPoint = Struct.new(:backward, :forward, :str) do
def initialize(str)
super(nil, nil, str)
end
def ==(other)
object_id == other.object_id
end
end
class RingBuffer
attr_reader :size
attr_reader :head
def initialize(max = 1024)
@max = max
@size = 0
@head = nil # reading head of ring-shaped tape
end
def <<(point)
if @size.zero?
@head = point
@head.backward = @head
@head.forward = @head
@size = 1
elsif @size >= @max
tail = @head.forward
new_tail = tail.forward
@head.forward = point
point.backward = @head
new_tail.backward = point
point.forward = new_tail
@head = point
else
tail = @head.forward
@head.forward = point
point.backward = @head
tail.backward = point
point.forward = tail
@head = point
@size += 1
end
end
def empty?
@size.zero?
end
end
def initialize(max = 1024)
@ring = RingBuffer.new(max)
@ring_pointer = nil
@buffer = nil
@state = State::FRESH
end
def append(string, before_p = false)
case @state
when State::FRESH, State::YANK
@ring << RingPoint.new(string)
@state = State::CONTINUED
when State::CONTINUED, State::PROCESSED
if before_p
@ring.head.str.prepend(string)
else
@ring.head.str.concat(string)
end
@state = State::CONTINUED
end
end
def process
case @state
when State::FRESH
# nothing to do
when State::CONTINUED
@state = State::PROCESSED
when State::PROCESSED
@state = State::FRESH
when State::YANK
# nothing to do
end
end
def yank
unless @ring.empty?
@state = State::YANK
@ring_pointer = @ring.head
@ring_pointer.str
else
nil
end
end
def yank_pop
if @state == State::YANK
prev_yank = @ring_pointer.str
@ring_pointer = @ring_pointer.backward
[@ring_pointer.str, prev_yank]
else
nil
end
end
def each
start = head = @ring.head
loop do
break if head.nil?
yield head.str
head = head.backward
break if head == start
end
end
end
|