function source.link_exists(State, filename)
if State.link_cache == nil then
State.link_cache = {}
end
if State.link_cache[filename] == nil then
State.link_cache[filename] = file_exists(filename)
end
return State.link_cache[filename]
end
State.link_cache = {}
end
function starts_with(s, sub)
return s:find(sub, 1, --[[no escapes]] true) == 1
end
function ends_with(s, sub)
return s:reverse():find(sub:reverse(), 1, --[[no escapes]] true) == 1
end
end
function Text.clear_screen_line_cache(State, line_index)
State.line_cache[line_index].fragments = nil
State.line_cache[line_index].fragmentsB = nil
State.line_cache[line_index].screen_line_starting_pos = nil
State.line_cache[line_index].screen_line_starting_posB = nil
end
function trim(s)
return s:gsub('^%s+', ''):gsub('%s+$', '')
end
function ltrim(s)
return s:gsub('^%s+', '')
end
function rtrim(s)
return s:gsub('%s+$', '')
function Text.redraw_all(State)
--? print('clearing fragments')
State.line_cache = {}
for i=1,#State.lines do
State.line_cache[i] = {}
end
-- Make [[WikiWords]] (single word, all in one screen line) clickable.
local trimmed_word = rtrim(frag) -- compute_fragments puts whitespace at the end
if starts_with(trimmed_word, '[[') and ends_with(trimmed_word, ']]') then
local filename = trimmed_word:gsub('^..(.*)..$', '%1')
if source.link_exists(State, filename) then
local filename_text = App.newText(love.graphics.getFont(), filename)
button(State, 'link', {x=x+App.width(to_text('[[')), y=y, w=App.width(filename_text), h=State.line_height, color={1,1,1},
icon = icon.hyperlink_decoration,
onpress1 = function()
source.switch_to_file(filename)
end,
})
end
end
App.screen.draw(frag_text, x,y)
-- render cursor if necessary
if State.cursor1.pos and line_index == State.cursor1.line then
if pos <= State.cursor1.pos and pos + frag_len > State.cursor1.pos then
if State.search_term then
if State.lines[State.cursor1.line].data:sub(State.cursor1.pos, State.cursor1.pos+utf8.len(State.search_term)-1) == State.search_term then
local lo_px = Text.draw_highlight(State, line, x,y, pos, State.cursor1.pos, State.cursor1.pos+utf8.len(State.search_term))
App.color(Text_color)
love.graphics.print(State.search_term, x+lo_px,y)
end
elseif Focus == 'edit' then
Text.draw_cursor(State, x+Text.x(frag, State.cursor1.pos-pos+1), y)
App.color(Text_color)
end
end
end
x = x + frag_width
end
pos = pos + frag_len
end
return false, x,y, pos, screen_line_starting_pos
end
function Text.draw_wrapping_lineB(State, line_index, x,y, startpos)
local line = State.lines[line_index]
local line_cache = State.line_cache[line_index]
local screen_line_starting_pos = startpos
Text.compute_fragmentsB(State, line_index, x)
local pos = 1
for _, f in ipairs(line_cache.fragmentsB) do
local frag, frag_text = f.data, f.text
local frag_len = utf8.len(frag)
--? print('text.draw:', frag, 'at', line_index,pos, 'after', x,y)
if pos < startpos then
-- render nothing
--? print('skipping', frag)
else
-- render fragment
local frag_width = App.width(frag_text)
if x + frag_width > State.right then
assert(x > State.left) -- no overfull lines
y = y + State.line_height
if y + State.line_height > App.screen.height then
return --[[screen filled]] true, x,y, pos, screen_line_starting_pos
end
screen_line_starting_pos = pos
x = State.left
end
App.screen.draw(frag_text, x,y)
-- render cursor if necessary
if State.cursor1.posB and line_index == State.cursor1.line then
if pos <= State.cursor1.posB and pos + frag_len > State.cursor1.posB then
if State.search_term then
if State.lines[State.cursor1.line].dataB:sub(State.cursor1.posB, State.cursor1.posB+utf8.len(State.search_term)-1) == State.search_term then
local lo_px = Text.draw_highlight(State, line, x,y, pos, State.cursor1.posB, State.cursor1.posB+utf8.len(State.search_term))
App.color(Fold_color)
love.graphics.print(State.search_term, x+lo_px,y)
end
elseif Focus == 'edit' then
Text.draw_cursor(State, x+Text.x(frag, State.cursor1.posB-pos+1), y)
App.color(Fold_color)
end
end
end
x = x + frag_width
end
pos = pos + frag_len
end
return false, x,y, pos, screen_line_starting_pos
end
function Text.draw_cursor(State, x, y)
-- blink every 0.5s
if math.floor(Cursor_time*2)%2 == 0 then
App.color(Cursor_color)
love.graphics.rectangle('fill', x,y, 3,State.line_height)
end
State.cursor_x = x
State.cursor_y = y+State.line_height
end
function Text.populate_screen_line_starting_pos(State, line_index)
local line = State.lines[line_index]