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
126
127
128
129
|
-- helpers for the search bar (C-f)
function Text.draw_search_bar(State)
local h = State.line_height+2
local y = App.screen.height-h
love.graphics.setColor(0.9,0.9,0.9)
love.graphics.rectangle('fill', 0, y-10, App.screen.width-1, h+8)
love.graphics.setColor(0.6,0.6,0.6)
love.graphics.line(0, y-10, App.screen.width-1, y-10)
love.graphics.setColor(1,1,1)
love.graphics.rectangle('fill', 20, y-6, App.screen.width-40, h+2, 2,2)
love.graphics.setColor(0.6,0.6,0.6)
love.graphics.rectangle('line', 20, y-6, App.screen.width-40, h+2, 2,2)
App.color(Text_color)
App.screen.print(State.search_term, 25,y-5)
Text.draw_cursor(State, 25+App.width(State.search_term),y-5)
end
function Text.search_next(State)
-- search current line from cursor
local pos = find(State.lines[State.cursor1.line].data, State.search_term, State.cursor1.pos, --[[literal]] true)
if pos then
State.cursor1.pos = pos
end
if pos == nil then
-- search lines below cursor
for i=State.cursor1.line+1,#State.lines do
pos = find(State.lines[i].data, State.search_term, --[[from start]] nil, --[[literal]] true)
if pos then
State.cursor1 = {line=i, pos=pos}
break
end
end
end
if pos == nil then
-- wrap around
for i=1,State.cursor1.line-1 do
pos = find(State.lines[i].data, State.search_term, --[[from start]] nil, --[[literal]] true)
if pos then
State.cursor1 = {line=i, pos=pos}
break
end
end
end
if pos == nil then
-- search current line until cursor
pos = find(State.lines[State.cursor1.line].data, State.search_term, --[[from start]] nil, --[[literal]] true)
if pos and pos < State.cursor1.pos then
State.cursor1.pos = pos
end
end
if pos == nil then
State.cursor1.line = State.search_backup.cursor.line
State.cursor1.pos = State.search_backup.cursor.pos
State.screen_top1.line = State.search_backup.screen_top.line
State.screen_top1.pos = State.search_backup.screen_top.pos
end
if Text.lt1(State.cursor1, State.screen_top1) or Text.lt1(State.screen_bottom1, State.cursor1) then
State.screen_top1.line = State.cursor1.line
local pos = Text.pos_at_start_of_screen_line(State, State.cursor1)
State.screen_top1.pos = pos
end
end
function Text.search_previous(State)
-- search current line before cursor
local pos = rfind(State.lines[State.cursor1.line].data, State.search_term, State.cursor1.pos-1, --[[literal]] true)
if pos then
State.cursor1.pos = pos
end
if pos == nil then
-- search lines above cursor
for i=State.cursor1.line-1,1,-1 do
pos = rfind(State.lines[i].data, State.search_term, --[[from end]] nil, --[[literal]] true)
if pos then
State.cursor1 = {line=i, pos=pos}
break
end
end
end
if pos == nil then
-- wrap around
for i=#State.lines,State.cursor1.line+1,-1 do
pos = rfind(State.lines[i].data, State.search_term, --[[from end]] nil, --[[literal]] true)
if pos then
State.cursor1 = {line=i, pos=pos}
break
end
end
end
if pos == nil then
-- search current line after cursor
pos = rfind(State.lines[State.cursor1.line].data, State.search_term, --[[from end]] nil, --[[literal]] true)
if pos and pos > State.cursor1.pos then
State.cursor1.pos = pos
end
end
if pos == nil then
State.cursor1.line = State.search_backup.cursor.line
State.cursor1.pos = State.search_backup.cursor.pos
State.screen_top1.line = State.search_backup.screen_top.line
State.screen_top1.pos = State.search_backup.screen_top.pos
end
if Text.lt1(State.cursor1, State.screen_top1) or Text.lt1(State.screen_bottom1, State.cursor1) then
State.screen_top1.line = State.cursor1.line
local pos = Text.pos_at_start_of_screen_line(State, State.cursor1)
State.screen_top1.pos = pos
end
end
function find(s, pat, i, plain)
if s == nil then return end
return s:find(pat, i, plain)
end
-- TODO: avoid the expensive reverse() operations
-- Particularly if we only care about literal matches, we don't need all of string.find
function rfind(s, pat, i, plain)
if s == nil then return end
local rs = s:reverse()
local rpat = pat:reverse()
if i == nil then i = #s end
local ri = #s - i + 1
local rendpos = rs:find(rpat, ri, plain)
if rendpos == nil then return nil end
local endpos = #s - rendpos + 1
assert (endpos >= #pat)
return endpos-#pat+1
end
|