lines2.love/select.lua

100 lines
3.6 KiB
Lua

-- helpers for selecting portions of text
function edit.mouse_loc(editor)
local mx,my = love.mouse.getPosition()
return edit.to_loc(editor, mx, my)
end
function Text.cut_selection_and_record_undo_event(editor)
if editor.selection1.line == nil then return end
local result = Text.selection(editor)
Text.delete_selection_and_record_undo_event(editor)
return result
end
function Text.delete_selection_and_record_undo_event(editor)
if editor.selection1.line == nil then return end
local minl,maxl = minmax(editor.selection1.line, editor.cursor.line)
local before = snapshot(editor, minl, maxl)
Text.delete_selection_without_undo(editor)
record_undo_event(editor, {before=before, after=snapshot(editor, editor.cursor.line)})
end
function Text.delete_selection_without_undo(editor)
if editor.selection1.line == nil then return end
-- min,max = sorted(editor.selection1,editor.cursor)
local minl,minp = editor.selection1.line,editor.selection1.pos
local maxl,maxp = editor.cursor.line,editor.cursor.pos
if minl > maxl then
minl,maxl = maxl,minl
minp,maxp = maxp,minp
elseif minl == maxl then
if minp > maxp then
minp,maxp = maxp,minp
end
end
-- update editor.cursor and editor.selection1
editor.cursor.line = minl
editor.cursor.pos = minp
if edit.lt(editor.cursor, editor.screen_top) then
editor.screen_top = edit.hor(editor, editor.cursor, editor.left)
end
editor.selection1 = {}
-- delete everything between min (inclusive) and max (exclusive)
local min_offset = Text.offset(editor.lines[minl].data, minp)
local max_offset = Text.offset(editor.lines[maxl].data, maxp)
if minl == maxl then
editor.lines[minl].data = editor.lines[minl].data:sub(1, min_offset-1)..editor.lines[minl].data:sub(max_offset)
return
end
assert(minl < maxl, ('minl %d not < maxl %d'):format(minl, maxl))
local rhs = editor.lines[maxl].data:sub(max_offset)
for i=maxl,minl+1,-1 do
table.remove(editor.lines, i)
end
editor.lines[minl].data = editor.lines[minl].data:sub(1, min_offset-1)..rhs
end
function Text.selection(editor)
if editor.selection1.line == nil then return end
-- min,max = sorted(editor.selection1,editor.cursor)
local minl,minp = editor.selection1.line,editor.selection1.pos
local maxl,maxp = editor.cursor.line,editor.cursor.pos
if minl > maxl then
minl,maxl = maxl,minl
minp,maxp = maxp,minp
elseif minl == maxl then
if minp > maxp then
minp,maxp = maxp,minp
end
end
local min_offset = Text.offset(editor.lines[minl].data, minp)
local max_offset = Text.offset(editor.lines[maxl].data, maxp)
if minl == maxl then
return editor.lines[minl].data:sub(min_offset, max_offset-1)
end
assert(minl < maxl, ('minl %d not < maxl %d'):format(minl, maxl))
local result = {editor.lines[minl].data:sub(min_offset)}
for i=minl+1,maxl-1 do
if editor.lines[i].mode == 'text' then
table.insert(result, editor.lines[i].data)
end
end
table.insert(result, editor.lines[maxl].data:sub(1, max_offset-1))
return table.concat(result, '\n')
end
function in_selection(editor, line_index, pos, cursor)
if editor.selection1.line == nil then return false end
assert(cursor.mode == 'text')
assert(editor.lines[line_index].mode == 'text')
local curr = {mode='text', line=line_index, pos=pos}
if edit.eq(cursor, editor.selection1) then
return false
elseif edit.lt(cursor, editor.selection1) then
return edit.le(cursor, curr) and edit.lt(curr, editor.selection1)
elseif edit.lt(editor.selection1, cursor) then
return edit.le(editor.selection1, curr) and edit.lt(curr, cursor)
end
end