get rid of to_text
[lines.love.git] / search.lua
blobf7d4732b0a6c0b6cc8136dbe79570718732a8fca
1 -- helpers for the search bar (C-f)
3 function Text.draw_search_bar(State)
4 local h = State.line_height+2
5 local y = App.screen.height-h
6 love.graphics.setColor(0.9,0.9,0.9)
7 love.graphics.rectangle('fill', 0, y-10, App.screen.width-1, h+8)
8 love.graphics.setColor(0.6,0.6,0.6)
9 love.graphics.line(0, y-10, App.screen.width-1, y-10)
10 love.graphics.setColor(1,1,1)
11 love.graphics.rectangle('fill', 20, y-6, App.screen.width-40, h+2, 2,2)
12 love.graphics.setColor(0.6,0.6,0.6)
13 love.graphics.rectangle('line', 20, y-6, App.screen.width-40, h+2, 2,2)
14 App.color(Text_color)
15 App.screen.print(State.search_term, 25,y-5)
16 if State.search_text == nil then
17 State.search_text = App.newText(love.graphics.getFont(), State.search_term)
18 end
19 Text.draw_cursor(State, 25+App.width(State.search_text),y-5)
20 end
22 function Text.search_next(State)
23 -- search current line from cursor
24 local pos = find(State.lines[State.cursor1.line].data, State.search_term, State.cursor1.pos, --[[literal]] true)
25 if pos then
26 State.cursor1.pos = pos
27 end
28 if pos == nil then
29 -- search lines below cursor
30 for i=State.cursor1.line+1,#State.lines do
31 pos = find(State.lines[i].data, State.search_term, --[[from start]] nil, --[[literal]] true)
32 if pos then
33 State.cursor1 = {line=i, pos=pos}
34 break
35 end
36 end
37 end
38 if pos == nil then
39 -- wrap around
40 for i=1,State.cursor1.line-1 do
41 pos = find(State.lines[i].data, State.search_term, --[[from start]] nil, --[[literal]] true)
42 if pos then
43 State.cursor1 = {line=i, pos=pos}
44 break
45 end
46 end
47 end
48 if pos == nil then
49 -- search current line until cursor
50 pos = find(State.lines[State.cursor1.line].data, State.search_term, --[[from start]] nil, --[[literal]] true)
51 if pos and pos < State.cursor1.pos then
52 State.cursor1.pos = pos
53 end
54 end
55 if pos == nil then
56 State.cursor1.line = State.search_backup.cursor.line
57 State.cursor1.pos = State.search_backup.cursor.pos
58 State.screen_top1.line = State.search_backup.screen_top.line
59 State.screen_top1.pos = State.search_backup.screen_top.pos
60 end
61 if Text.lt1(State.cursor1, State.screen_top1) or Text.lt1(State.screen_bottom1, State.cursor1) then
62 State.screen_top1.line = State.cursor1.line
63 local pos = Text.pos_at_start_of_screen_line(State, State.cursor1)
64 State.screen_top1.pos = pos
65 end
66 end
68 function Text.search_previous(State)
69 -- search current line before cursor
70 local pos = rfind(State.lines[State.cursor1.line].data, State.search_term, State.cursor1.pos-1, --[[literal]] true)
71 if pos then
72 State.cursor1.pos = pos
73 end
74 if pos == nil then
75 -- search lines above cursor
76 for i=State.cursor1.line-1,1,-1 do
77 pos = rfind(State.lines[i].data, State.search_term, --[[from end]] nil, --[[literal]] true)
78 if pos then
79 State.cursor1 = {line=i, pos=pos}
80 break
81 end
82 end
83 end
84 if pos == nil then
85 -- wrap around
86 for i=#State.lines,State.cursor1.line+1,-1 do
87 pos = rfind(State.lines[i].data, State.search_term, --[[from end]] nil, --[[literal]] true)
88 if pos then
89 State.cursor1 = {line=i, pos=pos}
90 break
91 end
92 end
93 end
94 if pos == nil then
95 -- search current line after cursor
96 pos = rfind(State.lines[State.cursor1.line].data, State.search_term, --[[from end]] nil, --[[literal]] true)
97 if pos and pos > State.cursor1.pos then
98 State.cursor1.pos = pos
99 end
101 if pos == nil then
102 State.cursor1.line = State.search_backup.cursor.line
103 State.cursor1.pos = State.search_backup.cursor.pos
104 State.screen_top1.line = State.search_backup.screen_top.line
105 State.screen_top1.pos = State.search_backup.screen_top.pos
107 if Text.lt1(State.cursor1, State.screen_top1) or Text.lt1(State.screen_bottom1, State.cursor1) then
108 State.screen_top1.line = State.cursor1.line
109 local pos = Text.pos_at_start_of_screen_line(State, State.cursor1)
110 State.screen_top1.pos = pos
114 function find(s, pat, i, plain)
115 if s == nil then return end
116 return s:find(pat, i, plain)
119 -- TODO: avoid the expensive reverse() operations
120 -- Particularly if we only care about literal matches, we don't need all of string.find
121 function rfind(s, pat, i, plain)
122 if s == nil then return end
123 local rs = s:reverse()
124 local rpat = pat:reverse()
125 if i == nil then i = #s end
126 local ri = #s - i + 1
127 local rendpos = rs:find(rpat, ri, plain)
128 if rendpos == nil then return nil end
129 local endpos = #s - rendpos + 1
130 assert (endpos >= #pat)
131 return endpos-#pat+1