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)
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
)
19 Text
.draw_cursor(State
, 25+App
.width(State
.search_text
),y
-5)
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)
26 State
.cursor1
.pos
= pos
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)
33 State
.cursor1
= {line
=i
, pos
=pos
}
40 for i
=1,State
.cursor1
.line
-1 do
41 pos
= find(State
.lines
[i
].data
, State
.search_term
, --[[from start]] nil, --[[literal]] true)
43 State
.cursor1
= {line
=i
, pos
=pos
}
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
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
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
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)
72 State
.cursor1
.pos
= pos
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)
79 State
.cursor1
= {line
=i
, pos
=pos
}
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)
89 State
.cursor1
= {line
=i
, pos
=pos
}
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
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
)