-- Scan all panes, while delegating as much work as possible to lines.love search.
-- * Text.search_next in lines.love scans from cursor while wrapping around
-- within the pane, so we need to work around that.
-- * Each pane's search_term field influences whether the search term at
-- cursor is highlighted, so we need to manage that as well. At any moment
-- we want the search_term and search_text to be set for at most a single
-- pane.
--
-- Side-effect: we perturb the cursor of panes as we scan them.
function search_next()
if Cursor_pane.col < 1 then return end
clear_all_search_terms()
local pane = Surface[Cursor_pane.col][Cursor_pane.row]
if pane == nil then
return
end
print('search next', Cursor_pane.col, Cursor_pane.row, pane.cursor1.line, pane.cursor1.pos)
local old_cursor_in_cursor_pane = {line=pane.cursor1.line, pos=pane.cursor1.pos}
-- scan current pane down from cursor
if search_next_in_pane(Surface[Cursor_pane.col][Cursor_pane.row]) then
print('found in same pane', pane.cursor1.line, pane.cursor1.pos)
return
end
pane.cursor1 = old_cursor_in_cursor_pane
-- scan current column down from current pane
for current_pane_index=Cursor_pane.row+1,#Surface[Cursor_pane.col] do
local pane = Surface[Cursor_pane.col][current_pane_index]
pane.cursor1 = {line=1, pos=1}
pane.screen_top1 = {line=1, pos=1}
if search_next_in_pane(pane) then
Cursor_pane.row = current_pane_index
print('found in same column', Cursor_pane.col, Cursor_pane.row, pane.cursor1.line, pane.cursor1.pos)
return
end
end
local current_column_index = 1 + Cursor_pane.col%#Surface -- (i+1)%#Surface in the presence of 1-indexing
-- scan columns past current, looping around
while true do
for current_pane_index,pane in ipairs(Surface[current_column_index]) do
pane.cursor1 = {line=1, pos=1}
pane.screen_top1 = {line=1, pos=1}
if search_next_in_pane(pane) then
Cursor_pane = {col=current_column_index, row=current_pane_index}
print('found', Cursor_pane.col, Cursor_pane.row, pane.cursor1.line, pane.cursor1.pos)
return
end
end
-- loop update
current_column_index = 1 + current_column_index%#Surface -- i = (i+1)%#Surface in the presence of 1-indexing
-- termination check
if current_column_index == Cursor_pane.col then
break
end
end
-- scan current column until current pane
for current_pane_index=1,Cursor_pane.row-1 do
if search_next_in_pane(Surface[Cursor_pane.col][current_pane_index]) then
Cursor_pane.row = current_pane_index
print('found in same column', Cursor_pane.col, Cursor_pane.row, pane.cursor1.line, pane.cursor1.pos)
return
end
end
-- finally, scan the cursor pane until the cursor
local pane = Surface[Cursor_pane.col][Cursor_pane.row]
local old_cursor = pane.cursor1
pane.cursor1 = {line=1, pos=1}
pane.screen_top1 = {line=1, pos=1}
if search_next_in_pane(pane) then
if Text.lt1(pane.cursor1, old_cursor) then
return
end
end
-- nothing found
print('f')
pane.cursor1 = old_cursor_in_cursor_pane
end
-- returns whether it found an occurrence
function search_next_in_pane(pane)
pane.search_term = Display_settings.search_term
pane.search_text = Display_settings.search_text
pane.search_backup = {cursor={line=pane.cursor1.line, pos=pane.cursor1.pos}, screen_top={line=pane.screen_top1.line, pos=pane.screen_top1.pos}}
for i=1,#pane.lines do
if pane.line_cache[i] == nil then
pane.line_cache[i] = {}
end
end
if Text.search_next(pane) then
if Text.le1(pane.search_backup.cursor, pane.cursor1) then
-- select this occurrence
return true
end
-- Otherwise cursor wrapped around. Skip this pane.
end
-- Clean up this pane before moving on to the next one.
pane.search_term = nil
pane.search_text = nil
pane.cursor1.line = pane.search_backup.cursor.line
pane.cursor1.pos = pane.search_backup.cursor.pos
pane.screen_top1.line = pane.search_backup.screen_top.line
pane.screen_top1.pos = pane.search_backup.screen_top.pos
pane.search_backup = nil
end
-- Scan all panes, while delegating as much work as possible to lines.love search.
function search_previous()
end
function bring_cursor_of_cursor_pane_in_view(dir)
if Cursor_pane.col < 1 then
return
end
local pane = Surface[Cursor_pane.col][Cursor_pane.row]
if pane == nil then
return
end
--? print('viewport before', Display_settings.x, Display_settings.y)
local left_edge_sx = left_edge_sx(Cursor_pane.col)
local cursor_sx = left_edge_sx + Text.x_of_schema1(pane, pane.cursor1)
local vertically_ok = cursor_sx > Display_settings.x and cursor_sx < Display_settings.x + App.screen.width - App.width(Em)
local cursor_sy = up_edge_sy(Cursor_pane.col, Cursor_pane.row) + y_of_schema1(pane, pane.cursor1)
--? print(cursor_sy, Display_settings.y, App.screen.height, Line_height, Display_settings.y + App.screen.height - 2*Line_height)
local horizontally_ok = cursor_sy > Display_settings.y and cursor_sy < Display_settings.y + App.screen.height - Header_height - 2*Line_height -- account for search bar along the bottom
if vertically_ok and horizontally_ok then
return
end
if dir == 'up' then
if not vertically_ok then
Display_settings.x = left_edge_sx - Margin_left - Padding_horizontal
end
if not horizontally_ok then
Display_settings.y = cursor_sy - 3*Line_height
end
else
assert(dir == 'down')
if not vertically_ok then
Display_settings.x = left_edge_sx + Display_settings.column_width + Margin_right + Padding_horizontal - App.screen.width
end
if not horizontally_ok then
Display_settings.y = cursor_sy + 3*Line_height - (App.screen.height - Header_height)
end
end
--? print('viewport before clamp', Display_settings.x, Display_settings.y)
Display_settings.x = math.max(Display_settings.x, 0)
Display_settings.y = math.max(Display_settings.y, 0)
--? print('viewport now', Display_settings.x, Display_settings.y)
end
function clear_all_search_terms()
for col,column in ipairs(Surface) do
for row,pane in ipairs(column) do
pane.search_term = ''
pane.search_text = nil
end
end
end