Initial commit of multicursor. Next step is to investigate how multicursor works on various other IDEs and ape those.
This commit is contained in:
parent
0d65725b27
commit
37a3884ee2
|
@ -24,13 +24,19 @@ local function get_indent_string()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function doc_multiline_selection(sort)
|
local function doc_multiline_selections(sort)
|
||||||
local line1, col1, line2, col2, swap = doc():get_selection(sort)
|
local iter = doc():get_selections(sort)
|
||||||
if line2 > line1 and col2 == 1 then
|
return function()
|
||||||
line2 = line2 - 1
|
local idx, line1, col1, line2, col2 = iter()
|
||||||
col2 = #doc().lines[line2]
|
if not idx then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if line2 > line1 and col2 == 1 then
|
||||||
|
line2 = line2 - 1
|
||||||
|
col2 = #doc().lines[line2]
|
||||||
|
end
|
||||||
|
return idx, line1, col1, line2, col2
|
||||||
end
|
end
|
||||||
return line1, col1, line2, col2, swap
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function append_line_if_last_line(line)
|
local function append_line_if_last_line(line)
|
||||||
|
@ -76,46 +82,51 @@ local commands = {
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:newline"] = function()
|
["doc:newline"] = function()
|
||||||
local line, col = doc():get_selection()
|
for idx, line, col in doc():get_selections() do
|
||||||
local indent = doc().lines[line]:match("^[\t ]*")
|
local indent = doc().lines[line]:match("^[\t ]*")
|
||||||
if col <= #indent then
|
if col <= #indent then
|
||||||
indent = indent:sub(#indent + 2 - col)
|
indent = indent:sub(#indent + 2 - col)
|
||||||
|
end
|
||||||
|
doc():text_input("\n" .. indent, idx)
|
||||||
end
|
end
|
||||||
doc():text_input("\n" .. indent)
|
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:newline-below"] = function()
|
["doc:newline-below"] = function()
|
||||||
local line = doc():get_selection()
|
for idx, line in doc():get_selections() do
|
||||||
local indent = doc().lines[line]:match("^[\t ]*")
|
local indent = doc().lines[line]:match("^[\t ]*")
|
||||||
doc():insert(line, math.huge, "\n" .. indent)
|
doc():insert(line, math.huge, "\n" .. indent)
|
||||||
doc():set_selection(line + 1, math.huge)
|
doc():set_selections(idx, line + 1, math.huge)
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:newline-above"] = function()
|
["doc:newline-above"] = function()
|
||||||
local line = doc():get_selection()
|
for idx, line in doc():get_selections() do
|
||||||
local indent = doc().lines[line]:match("^[\t ]*")
|
local indent = doc().lines[line]:match("^[\t ]*")
|
||||||
doc():insert(line, 1, indent .. "\n")
|
doc():insert(line, 1, indent .. "\n")
|
||||||
doc():set_selection(line, math.huge)
|
doc():set_selections(idx, line, math.huge)
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:delete"] = function()
|
["doc:delete"] = function()
|
||||||
local line, col = doc():get_selection()
|
for idx, line, col in doc():get_selections() do
|
||||||
if not doc():has_selection() and doc().lines[line]:find("^%s*$", col) then
|
if not doc():has_selection(idx) and doc().lines[line]:find("^%s*$", col) then
|
||||||
doc():remove(line, col, line, math.huge)
|
doc():remove(line, col, line, math.huge)
|
||||||
|
end
|
||||||
|
doc():delete_to(idx, translate.next_char)
|
||||||
end
|
end
|
||||||
doc():delete_to(translate.next_char)
|
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:backspace"] = function()
|
["doc:backspace"] = function()
|
||||||
local line, col = doc():get_selection()
|
for idx, line, col in doc():get_selections() do
|
||||||
if not doc():has_selection() then
|
if not doc():has_selection(idx) then
|
||||||
local text = doc():get_text(line, 1, line, col)
|
local text = doc():get_text(line, 1, line, col)
|
||||||
if #text >= config.indent_size and text:find("^ *$") then
|
if #text >= config.indent_size and text:find("^ *$") then
|
||||||
doc():delete_to(0, -config.indent_size)
|
doc():delete_to(idx, 0, -config.indent_size)
|
||||||
return
|
return
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
doc():delete_to(idx, translate.previous_char)
|
||||||
end
|
end
|
||||||
doc():delete_to(translate.previous_char)
|
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:select-all"] = function()
|
["doc:select-all"] = function()
|
||||||
|
@ -128,75 +139,92 @@ local commands = {
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:select-lines"] = function()
|
["doc:select-lines"] = function()
|
||||||
local line1, _, line2, _, swap = doc():get_selection(true)
|
for idx, line1, _, line2 in doc():get_selections(true) do
|
||||||
append_line_if_last_line(line2)
|
append_line_if_last_line(line2)
|
||||||
doc():set_selection(line1, 1, line2 + 1, 1, swap)
|
doc():set_selections(idx, line1, 1, line2 + 1, 1, swap)
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:select-word"] = function()
|
["doc:select-word"] = function()
|
||||||
local line1, col1 = doc():get_selection(true)
|
for idx, line1, col1 in doc():get_selections(true) do
|
||||||
local line1, col1 = translate.start_of_word(doc(), line1, col1)
|
local line1, col1 = translate.start_of_word(doc(), line1, col1)
|
||||||
local line2, col2 = translate.end_of_word(doc(), line1, col1)
|
local line2, col2 = translate.end_of_word(doc(), line1, col1)
|
||||||
doc():set_selection(line2, col2, line1, col1)
|
doc():set_selections(idx, line2, col2, line1, col1)
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:join-lines"] = function()
|
["doc:join-lines"] = function()
|
||||||
local line1, _, line2 = doc():get_selection(true)
|
for idx, line1, _, line2 in doc():get_selections(true) do
|
||||||
if line1 == line2 then line2 = line2 + 1 end
|
if line1 == line2 then line2 = line2 + 1 end
|
||||||
local text = doc():get_text(line1, 1, line2, math.huge)
|
local text = doc():get_text(line1, 1, line2, math.huge)
|
||||||
text = text:gsub("(.-)\n[\t ]*", function(x)
|
text = text:gsub("(.-)\n[\t ]*", function(x)
|
||||||
return x:find("^%s*$") and x or x .. " "
|
return x:find("^%s*$") and x or x .. " "
|
||||||
end)
|
end)
|
||||||
doc():insert(line1, 1, text)
|
doc():insert(line1, 1, text)
|
||||||
doc():remove(line1, #text + 1, line2, math.huge)
|
doc():remove(line1, #text + 1, line2, math.huge)
|
||||||
if doc():has_selection() then
|
if doc():has_selection(idx) then
|
||||||
doc():set_selection(line1, math.huge)
|
doc():set_selections(idx, line1, math.huge)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:indent"] = function()
|
["doc:indent"] = function()
|
||||||
doc():indent_text(false, doc_multiline_selection(true))
|
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
|
||||||
|
local l1, c1, l2, c2 = doc():indent_text(false, line1, col1, line2, col2)
|
||||||
|
if not l1 then
|
||||||
|
doc():set_selections(idx, l1, c1, l2, c2)
|
||||||
|
end
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:unindent"] = function()
|
["doc:unindent"] = function()
|
||||||
doc():indent_text(true, doc_multiline_selection(true))
|
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
|
||||||
|
local l1, c1, l2, c2 = doc():indent_text(true, line1, col1, line2, col2)
|
||||||
|
if not l1 then
|
||||||
|
doc():set_selections(idx, l1, c1, l2, c2)
|
||||||
|
end
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:duplicate-lines"] = function()
|
["doc:duplicate-lines"] = function()
|
||||||
local line1, col1, line2, col2, swap = doc_multiline_selection(true)
|
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
|
||||||
append_line_if_last_line(line2)
|
append_line_if_last_line(line2)
|
||||||
local text = doc():get_text(line1, 1, line2 + 1, 1)
|
local text = doc():get_text(line1, 1, line2 + 1, 1)
|
||||||
doc():insert(line2 + 1, 1, text)
|
doc():insert(line2 + 1, 1, text)
|
||||||
local n = line2 - line1 + 1
|
local n = line2 - line1 + 1
|
||||||
doc():set_selection(line1 + n, col1, line2 + n, col2, swap)
|
doc():set_selections(idx, line1 + n, col1, line2 + n, col2, swap)
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:delete-lines"] = function()
|
["doc:delete-lines"] = function()
|
||||||
local line1, col1, line2 = doc_multiline_selection(true)
|
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
|
||||||
append_line_if_last_line(line2)
|
append_line_if_last_line(line2)
|
||||||
doc():remove(line1, 1, line2 + 1, 1)
|
doc():remove(line1, 1, line2 + 1, 1)
|
||||||
doc():set_selection(line1, col1)
|
doc():set_selections(idx, line1, col1)
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:move-lines-up"] = function()
|
["doc:move-lines-up"] = function()
|
||||||
local line1, col1, line2, col2, swap = doc_multiline_selection(true)
|
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
|
||||||
append_line_if_last_line(line2)
|
append_line_if_last_line(line2)
|
||||||
if line1 > 1 then
|
if line1 > 1 then
|
||||||
local text = doc().lines[line1 - 1]
|
local text = doc().lines[line1 - 1]
|
||||||
doc():insert(line2 + 1, 1, text)
|
doc():insert(line2 + 1, 1, text)
|
||||||
doc():remove(line1 - 1, 1, line1, 1)
|
doc():remove(line1 - 1, 1, line1, 1)
|
||||||
doc():set_selection(line1 - 1, col1, line2 - 1, col2, swap)
|
doc():set_selections(idx, line1 - 1, col1, line2 - 1, col2)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["doc:move-lines-down"] = function()
|
["doc:move-lines-down"] = function()
|
||||||
local line1, col1, line2, col2, swap = doc_multiline_selection(true)
|
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
|
||||||
append_line_if_last_line(line2 + 1)
|
append_line_if_last_line(line2 + 1)
|
||||||
if line2 < #doc().lines then
|
if line2 < #doc().lines then
|
||||||
local text = doc().lines[line2 + 1]
|
local text = doc().lines[line2 + 1]
|
||||||
doc():remove(line2 + 1, 1, line2 + 2, 1)
|
doc():remove(line2 + 1, 1, line2 + 2, 1)
|
||||||
doc():insert(line1, 1, text)
|
doc():insert(line1, 1, text)
|
||||||
doc():set_selection(line1 + 1, col1, line2 + 1, col2, swap)
|
doc():set_selections(idx, line1 + 1, col1, line2 + 1, col2)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
@ -205,28 +233,29 @@ local commands = {
|
||||||
if not comment then return end
|
if not comment then return end
|
||||||
local indentation = get_indent_string()
|
local indentation = get_indent_string()
|
||||||
local comment_text = comment .. " "
|
local comment_text = comment .. " "
|
||||||
local line1, _, line2 = doc_multiline_selection(true)
|
for idx, line1, _, line2 in doc_multiline_selections(true) do
|
||||||
local uncomment = true
|
local uncomment = true
|
||||||
local start_offset = math.huge
|
local start_offset = math.huge
|
||||||
for line = line1, line2 do
|
for line = line1, line2 do
|
||||||
local text = doc().lines[line]
|
local text = doc().lines[line]
|
||||||
local s = text:find("%S")
|
local s = text:find("%S")
|
||||||
local cs, ce = text:find(comment_text, s, true)
|
|
||||||
if s and cs ~= s then
|
|
||||||
uncomment = false
|
|
||||||
start_offset = math.min(start_offset, s)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for line = line1, line2 do
|
|
||||||
local text = doc().lines[line]
|
|
||||||
local s = text:find("%S")
|
|
||||||
if uncomment then
|
|
||||||
local cs, ce = text:find(comment_text, s, true)
|
local cs, ce = text:find(comment_text, s, true)
|
||||||
if ce then
|
if s and cs ~= s then
|
||||||
doc():remove(line, cs, line, ce + 1)
|
uncomment = false
|
||||||
|
start_offset = math.min(start_offset, s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for line = line1, line2 do
|
||||||
|
local text = doc().lines[line]
|
||||||
|
local s = text:find("%S")
|
||||||
|
if uncomment then
|
||||||
|
local cs, ce = text:find(comment_text, s, true)
|
||||||
|
if ce then
|
||||||
|
doc():remove(line, cs, line, ce + 1)
|
||||||
|
end
|
||||||
|
elseif s then
|
||||||
|
doc():insert(line, start_offset, comment_text)
|
||||||
end
|
end
|
||||||
elseif s then
|
|
||||||
doc():insert(line, start_offset, comment_text)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
@ -350,26 +379,30 @@ local translations = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, fn in pairs(translations) do
|
for name, fn in pairs(translations) do
|
||||||
commands["doc:move-to-" .. name] = function() doc():move_to(fn, dv()) end
|
commands["doc:move-to-" .. name] = function() doc():move_to(nil, fn, dv()) end
|
||||||
commands["doc:select-to-" .. name] = function() doc():select_to(fn, dv()) end
|
commands["doc:select-to-" .. name] = function() doc():select_to(nil, fn, dv()) end
|
||||||
commands["doc:delete-to-" .. name] = function() doc():delete_to(fn, dv()) end
|
commands["doc:delete-to-" .. name] = function() doc():delete_to(nil, fn, dv()) end
|
||||||
end
|
end
|
||||||
|
|
||||||
commands["doc:move-to-previous-char"] = function()
|
commands["doc:move-to-previous-char"] = function()
|
||||||
if doc():has_selection() then
|
for idx, line, col in doc():get_selections(true) do
|
||||||
local line, col = doc():get_selection(true)
|
if doc():has_selection(idx) then
|
||||||
doc():set_selection(line, col)
|
doc():set_selections(idx, line, col)
|
||||||
else
|
end
|
||||||
doc():move_to(translate.previous_char)
|
end
|
||||||
|
if not doc():has_selection() then
|
||||||
|
doc():move_to(nil, translate.previous_char)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
commands["doc:move-to-next-char"] = function()
|
commands["doc:move-to-next-char"] = function()
|
||||||
if doc():has_selection() then
|
for idx, _, _, line, col in doc():get_selections(true) do
|
||||||
local _, _, line, col = doc():get_selection(true)
|
if doc():has_selection(idx) then
|
||||||
doc():set_selection(line, col)
|
doc():set_selections(idx, line, col)
|
||||||
else
|
end
|
||||||
doc():move_to(translate.next_char)
|
end
|
||||||
|
if not doc():has_selection() then
|
||||||
|
doc():move_to(nil, translate.next_char)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ end
|
||||||
|
|
||||||
function Doc:reset()
|
function Doc:reset()
|
||||||
self.lines = { "\n" }
|
self.lines = { "\n" }
|
||||||
self.selection = { a = { line=1, col=1 }, b = { line=1, col=1 } }
|
self.selections = { 1, 1, 1, 1 }
|
||||||
self.undo_stack = { idx = 1 }
|
self.undo_stack = { idx = 1 }
|
||||||
self.redo_stack = { idx = 1 }
|
self.redo_stack = { idx = 1 }
|
||||||
self.clean_change_id = 1
|
self.clean_change_id = 1
|
||||||
|
@ -131,9 +131,20 @@ function Doc:set_selection(line1, col1, line2, col2, swap)
|
||||||
assert(not line2 == not col2, "expected 2 or 4 arguments")
|
assert(not line2 == not col2, "expected 2 or 4 arguments")
|
||||||
if swap then line1, col1, line2, col2 = line2, col2, line1, col1 end
|
if swap then line1, col1, line2, col2 = line2, col2, line1, col1 end
|
||||||
line1, col1 = self:sanitize_position(line1, col1)
|
line1, col1 = self:sanitize_position(line1, col1)
|
||||||
|
line2, col2 = self:sanitize_position(line2 or line1, col2 or col1)
|
||||||
|
self.selections = { line1, col1, line2, col2 }
|
||||||
|
end
|
||||||
|
|
||||||
|
function Doc:set_selections(idx, line1, col1, line2, col2, swap)
|
||||||
|
assert(not line2 == not col2, "expected 3 or 5 arguments")
|
||||||
|
if swap then line1, col1, line2, col2 = line2, col2, line1, col1 end
|
||||||
|
line1, col1 = self:sanitize_position(line1, col1)
|
||||||
line2, col2 = self:sanitize_position(line2 or line1, col2 or col1)
|
line2, col2 = self:sanitize_position(line2 or line1, col2 or col1)
|
||||||
self.selection.a.line, self.selection.a.col = line1, col1
|
local target = (idx - 1)*4 + 1
|
||||||
self.selection.b.line, self.selection.b.col = line2, col2
|
self.selections[target] = line1
|
||||||
|
self.selections[target+1] = col1
|
||||||
|
self.selections[target+2] = line2
|
||||||
|
self.selections[target+3] = col2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,22 +158,53 @@ end
|
||||||
|
|
||||||
|
|
||||||
function Doc:get_selection(sort)
|
function Doc:get_selection(sort)
|
||||||
local a, b = self.selection.a, self.selection.b
|
|
||||||
if sort then
|
if sort then
|
||||||
return sort_positions(a.line, a.col, b.line, b.col)
|
return sort_positions(self.selections[1], self.selections[2], self.selections[3], self.selections[4])
|
||||||
|
end
|
||||||
|
return self.selections[1], self.selections[2], self.selections[3], self.selections[4]
|
||||||
|
end
|
||||||
|
|
||||||
|
function Doc:get_selection_count()
|
||||||
|
return #self.selections / 4
|
||||||
|
end
|
||||||
|
|
||||||
|
function Doc:get_selections(sort)
|
||||||
|
local idx = 1
|
||||||
|
return function()
|
||||||
|
if idx >= #self.selections then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
idx = idx + 4
|
||||||
|
if sort then
|
||||||
|
return ((idx - 5) / 4) + 1, sort_positions(self.selections[idx - 4], self.selections[idx - 3], self.selections[idx - 2], self.selections[idx - 1])
|
||||||
|
else
|
||||||
|
return ((idx - 5) / 4) + 1, self.selections[idx - 4], self.selections[idx - 3], self.selections[idx - 2], self.selections[idx - 1]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return a.line, a.col, b.line, b.col
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function Doc:has_selection()
|
function Doc:has_selection(idx)
|
||||||
local a, b = self.selection.a, self.selection.b
|
if idx then
|
||||||
return not (a.line == b.line and a.col == b.col)
|
local target = (idx-1)*4+1
|
||||||
|
return
|
||||||
|
self.selections[target] ~= self.selections[target+2] or
|
||||||
|
self.selections[target+1] ~= self.selections[target+3]
|
||||||
|
end
|
||||||
|
for target = 1, #self.selections, 4 do
|
||||||
|
if self.selections[target] ~= self.selections[target+2] or
|
||||||
|
self.selections[target+1] ~= self.selections[target+3] then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function Doc:sanitize_selection()
|
function Doc:sanitize_selection()
|
||||||
self:set_selection(self:get_selection())
|
for idx, line1, col1, line2, col2 in self:get_selections() do
|
||||||
|
self:set_selections(idx, line1, col1, line2, col2)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -348,13 +390,16 @@ function Doc:redo()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function Doc:text_input(text)
|
function Doc:text_input(text, idx)
|
||||||
if self:has_selection() then
|
for sidx, line, col in self:get_selections() do
|
||||||
self:delete_to()
|
if not idx or idx == sidx then
|
||||||
|
if self:has_selection(sidx) then
|
||||||
|
self:delete_to(sidx)
|
||||||
|
end
|
||||||
|
self:insert(line, col, text)
|
||||||
|
self:move_to(sidx, #text)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local line, col = self:get_selection()
|
|
||||||
self:insert(line, col, text)
|
|
||||||
self:move_to(#text)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -380,29 +425,38 @@ function Doc:replace(fn)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function Doc:delete_to(...)
|
function Doc:delete_to(idx, ...)
|
||||||
local line, col = self:get_selection(true)
|
for sidx, line1, col1, line2, col2 in self:get_selections(true) do
|
||||||
if self:has_selection() then
|
if not idx or sidx == idx then
|
||||||
self:remove(self:get_selection())
|
if self:has_selection(sidx) then
|
||||||
else
|
self:remove(line1, col1, line2, col2)
|
||||||
local line2, col2 = self:position_offset(line, col, ...)
|
else
|
||||||
self:remove(line, col, line2, col2)
|
local l2, c2 = self:position_offset(line, col, ...)
|
||||||
line, col = sort_positions(line, col, line2, col2)
|
self:remove(line1, col1, l2, c2)
|
||||||
|
line1, col1 = sort_positions(line1, col1, l2, c2)
|
||||||
|
end
|
||||||
|
self:set_selections(sidx, line1, col1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
self:set_selection(line, col)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function Doc:move_to(...)
|
function Doc:move_to(idx, ...)
|
||||||
local line, col = self:get_selection()
|
for sidx, line, col in self:get_selections() do
|
||||||
self:set_selection(self:position_offset(line, col, ...))
|
if not idx or sidx == idx then
|
||||||
|
self:set_selections(sidx, self:position_offset(line, col, ...))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function Doc:select_to(...)
|
function Doc:select_to(idx, ...)
|
||||||
local line, col, line2, col2 = self:get_selection()
|
for sidx, line, col, line2, col2 in self:get_selections() do
|
||||||
line, col = self:position_offset(line, col, ...)
|
if not idx or idx == sidx then
|
||||||
self:set_selection(line, col, line2, col2)
|
line, col = self:position_offset(line, col, ...)
|
||||||
|
self:set_selections(sidx, line, col, line2, col2)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -439,7 +493,7 @@ end
|
||||||
-- inserts the appropriate whitespace, as if you typed them normally.
|
-- inserts the appropriate whitespace, as if you typed them normally.
|
||||||
-- * if you are unindenting, the cursor will jump to the start of the line,
|
-- * if you are unindenting, the cursor will jump to the start of the line,
|
||||||
-- and remove the appropriate amount of spaces (or a tab).
|
-- and remove the appropriate amount of spaces (or a tab).
|
||||||
function Doc:indent_text(unindent, line1, col1, line2, col2, swap)
|
function Doc:indent_text(unindent, line1, col1, line2, col2)
|
||||||
local text = get_indent_string()
|
local text = get_indent_string()
|
||||||
local _, se = self.lines[line1]:find("^[ \t]+")
|
local _, se = self.lines[line1]:find("^[ \t]+")
|
||||||
local in_beginning_whitespace = col1 == 1 or (se and col1 <= se + 1)
|
local in_beginning_whitespace = col1 == 1 or (se and col1 <= se + 1)
|
||||||
|
@ -455,9 +509,9 @@ function Doc:indent_text(unindent, line1, col1, line2, col2, swap)
|
||||||
l1d, l2d = #self.lines[line1] - l1d, #self.lines[line2] - l2d
|
l1d, l2d = #self.lines[line1] - l1d, #self.lines[line2] - l2d
|
||||||
if (unindent or in_beginning_whitespace) and not self:has_selection() then
|
if (unindent or in_beginning_whitespace) and not self:has_selection() then
|
||||||
local start_cursor = (se and se + 1 or 1) + l1d or #(self.lines[line1])
|
local start_cursor = (se and se + 1 or 1) + l1d or #(self.lines[line1])
|
||||||
self:set_selection(line1, start_cursor, line2, start_cursor, swap)
|
return line1, start_cursor, line2, start_cursor
|
||||||
else
|
else
|
||||||
self:set_selection(line1, col1 + l1d, line2, col2 + l2d, swap)
|
return line1, col1 + l1d, line2, col2 + l2d
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:text_input(text)
|
self:text_input(text)
|
||||||
|
|
|
@ -276,7 +276,18 @@ function DocView:on_mouse_moved(x, y, ...)
|
||||||
local l1, c1 = self:resolve_screen_position(x, y)
|
local l1, c1 = self:resolve_screen_position(x, y)
|
||||||
local l2, c2 = table.unpack(self.mouse_selecting)
|
local l2, c2 = table.unpack(self.mouse_selecting)
|
||||||
local clicks = self.mouse_selecting.clicks
|
local clicks = self.mouse_selecting.clicks
|
||||||
self.doc:set_selection(mouse_selection(self.doc, clicks, l1, c1, l2, c2))
|
if keymap.modkeys["ctrl"] then
|
||||||
|
if l1 > l2 then
|
||||||
|
l2 = l1
|
||||||
|
end
|
||||||
|
local idx = 1
|
||||||
|
for i = l1, l2 do
|
||||||
|
idx = idx + 1
|
||||||
|
self.doc:set_selections(idx, i, math.min(c1, #self.doc.lines[i]), i, math.min(c1, #self.doc.lines[i]))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.doc:set_selection(mouse_selection(self.doc, clicks, l1, c1, l2, c2))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -340,46 +351,50 @@ end
|
||||||
|
|
||||||
|
|
||||||
function DocView:draw_line_body(idx, x, y)
|
function DocView:draw_line_body(idx, x, y)
|
||||||
local line, col = self.doc:get_selection()
|
|
||||||
|
|
||||||
-- draw selection if it overlaps this line
|
-- draw selection if it overlaps this line
|
||||||
local line1, col1, line2, col2 = self.doc:get_selection(true)
|
for lidx, line1, col1, line2, col2 in self.doc:get_selections(true) do
|
||||||
if idx >= line1 and idx <= line2 then
|
if idx >= line1 and idx <= line2 then
|
||||||
local text = self.doc.lines[idx]
|
local text = self.doc.lines[idx]
|
||||||
if line1 ~= idx then col1 = 1 end
|
if line1 ~= idx then col1 = 1 end
|
||||||
if line2 ~= idx then col2 = #text + 1 end
|
if line2 ~= idx then col2 = #text + 1 end
|
||||||
local x1 = x + self:get_col_x_offset(idx, col1)
|
local x1 = x + self:get_col_x_offset(idx, col1)
|
||||||
local x2 = x + self:get_col_x_offset(idx, col2)
|
local x2 = x + self:get_col_x_offset(idx, col2)
|
||||||
local lh = self:get_line_height()
|
local lh = self:get_line_height()
|
||||||
renderer.draw_rect(x1, y, x2 - x1, lh, style.selection)
|
renderer.draw_rect(x1, y, x2 - x1, lh, style.selection)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
for lidx, line1, col1, line2, col2 in self.doc:get_selections(true) do
|
||||||
-- draw line highlight if caret is on this line
|
-- draw line highlight if caret is on this line
|
||||||
if config.highlight_current_line and not self.doc:has_selection()
|
if config.highlight_current_line and not self.doc:has_selection(lidx)
|
||||||
and line == idx and core.active_view == self then
|
and line1 == idx and core.active_view == self then
|
||||||
self:draw_line_highlight(x + self.scroll.x, y)
|
self:draw_line_highlight(x + self.scroll.x, y)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- draw line's text
|
-- draw line's text
|
||||||
self:draw_line_text(idx, x, y)
|
self:draw_line_text(idx, x, y)
|
||||||
|
|
||||||
-- draw caret if it overlaps this line
|
-- draw caret if it overlaps this line
|
||||||
local T = config.blink_period
|
local T = config.blink_period
|
||||||
if line == idx and core.active_view == self
|
for _, line, col in self.doc:get_selections() do
|
||||||
and (core.blink_timer - core.blink_start) % T < T / 2
|
if line == idx and core.active_view == self
|
||||||
and system.window_has_focus() then
|
and (core.blink_timer - core.blink_start) % T < T / 2
|
||||||
local lh = self:get_line_height()
|
and system.window_has_focus() then
|
||||||
local x1 = x + self:get_col_x_offset(line, col)
|
local lh = self:get_line_height()
|
||||||
renderer.draw_rect(x1, y, style.caret_width, lh, style.caret)
|
local x1 = x + self:get_col_x_offset(line, col)
|
||||||
|
renderer.draw_rect(x1, y, style.caret_width, lh, style.caret)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function DocView:draw_line_gutter(idx, x, y)
|
function DocView:draw_line_gutter(idx, x, y)
|
||||||
local color = style.line_number
|
local color = style.line_number
|
||||||
local line1, _, line2, _ = self.doc:get_selection(true)
|
for _, line1, _, line2 in self.doc:get_selections(true) do
|
||||||
if idx >= line1 and idx <= line2 then
|
if idx >= line1 and idx <= line2 then
|
||||||
color = style.line_number2
|
color = style.line_number2
|
||||||
|
break
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local yoffset = self:get_line_text_y_offset()
|
local yoffset = self:get_line_text_y_offset()
|
||||||
x = x + style.padding.x
|
x = x + style.padding.x
|
||||||
|
|
Loading…
Reference in New Issue