Initial commit of multicursor. Next step is to investigate how multicursor works on various other IDEs and ape those.

This commit is contained in:
Adam Harrison
2021-06-18 17:33:55 -04:00
parent 0d65725b27
commit 37a3884ee2
3 changed files with 270 additions and 168 deletions
+139 -106
View File
@@ -24,13 +24,19 @@ local function get_indent_string()
end
local function doc_multiline_selection(sort)
local line1, col1, line2, col2, swap = doc():get_selection(sort)
if line2 > line1 and col2 == 1 then
line2 = line2 - 1
col2 = #doc().lines[line2]
local function doc_multiline_selections(sort)
local iter = doc():get_selections(sort)
return function()
local idx, line1, col1, line2, col2 = iter()
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
return line1, col1, line2, col2, swap
end
local function append_line_if_last_line(line)
@@ -76,46 +82,51 @@ local commands = {
end,
["doc:newline"] = function()
local line, col = doc():get_selection()
local indent = doc().lines[line]:match("^[\t ]*")
if col <= #indent then
indent = indent:sub(#indent + 2 - col)
for idx, line, col in doc():get_selections() do
local indent = doc().lines[line]:match("^[\t ]*")
if col <= #indent then
indent = indent:sub(#indent + 2 - col)
end
doc():text_input("\n" .. indent, idx)
end
doc():text_input("\n" .. indent)
end,
["doc:newline-below"] = function()
local line = doc():get_selection()
local indent = doc().lines[line]:match("^[\t ]*")
doc():insert(line, math.huge, "\n" .. indent)
doc():set_selection(line + 1, math.huge)
for idx, line in doc():get_selections() do
local indent = doc().lines[line]:match("^[\t ]*")
doc():insert(line, math.huge, "\n" .. indent)
doc():set_selections(idx, line + 1, math.huge)
end
end,
["doc:newline-above"] = function()
local line = doc():get_selection()
local indent = doc().lines[line]:match("^[\t ]*")
doc():insert(line, 1, indent .. "\n")
doc():set_selection(line, math.huge)
for idx, line in doc():get_selections() do
local indent = doc().lines[line]:match("^[\t ]*")
doc():insert(line, 1, indent .. "\n")
doc():set_selections(idx, line, math.huge)
end
end,
["doc:delete"] = function()
local line, col = doc():get_selection()
if not doc():has_selection() and doc().lines[line]:find("^%s*$", col) then
doc():remove(line, col, line, math.huge)
for idx, line, col in doc():get_selections() do
if not doc():has_selection(idx) and doc().lines[line]:find("^%s*$", col) then
doc():remove(line, col, line, math.huge)
end
doc():delete_to(idx, translate.next_char)
end
doc():delete_to(translate.next_char)
end,
["doc:backspace"] = function()
local line, col = doc():get_selection()
if not doc():has_selection() then
local text = doc():get_text(line, 1, line, col)
if #text >= config.indent_size and text:find("^ *$") then
doc():delete_to(0, -config.indent_size)
return
for idx, line, col in doc():get_selections() do
if not doc():has_selection(idx) then
local text = doc():get_text(line, 1, line, col)
if #text >= config.indent_size and text:find("^ *$") then
doc():delete_to(idx, 0, -config.indent_size)
return
end
end
doc():delete_to(idx, translate.previous_char)
end
doc():delete_to(translate.previous_char)
end,
["doc:select-all"] = function()
@@ -128,75 +139,92 @@ local commands = {
end,
["doc:select-lines"] = function()
local line1, _, line2, _, swap = doc():get_selection(true)
append_line_if_last_line(line2)
doc():set_selection(line1, 1, line2 + 1, 1, swap)
for idx, line1, _, line2 in doc():get_selections(true) do
append_line_if_last_line(line2)
doc():set_selections(idx, line1, 1, line2 + 1, 1, swap)
end
end,
["doc:select-word"] = function()
local line1, col1 = doc():get_selection(true)
local line1, col1 = translate.start_of_word(doc(), line1, col1)
local line2, col2 = translate.end_of_word(doc(), line1, col1)
doc():set_selection(line2, col2, line1, col1)
for idx, line1, col1 in doc():get_selections(true) do
local line1, col1 = translate.start_of_word(doc(), line1, col1)
local line2, col2 = translate.end_of_word(doc(), line1, col1)
doc():set_selections(idx, line2, col2, line1, col1)
end
end,
["doc:join-lines"] = function()
local line1, _, line2 = doc():get_selection(true)
if line1 == line2 then line2 = line2 + 1 end
local text = doc():get_text(line1, 1, line2, math.huge)
text = text:gsub("(.-)\n[\t ]*", function(x)
return x:find("^%s*$") and x or x .. " "
end)
doc():insert(line1, 1, text)
doc():remove(line1, #text + 1, line2, math.huge)
if doc():has_selection() then
doc():set_selection(line1, math.huge)
for idx, line1, _, line2 in doc():get_selections(true) do
if line1 == line2 then line2 = line2 + 1 end
local text = doc():get_text(line1, 1, line2, math.huge)
text = text:gsub("(.-)\n[\t ]*", function(x)
return x:find("^%s*$") and x or x .. " "
end)
doc():insert(line1, 1, text)
doc():remove(line1, #text + 1, line2, math.huge)
if doc():has_selection(idx) then
doc():set_selections(idx, line1, math.huge)
end
end
end,
["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,
["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,
["doc:duplicate-lines"] = function()
local line1, col1, line2, col2, swap = doc_multiline_selection(true)
append_line_if_last_line(line2)
local text = doc():get_text(line1, 1, line2 + 1, 1)
doc():insert(line2 + 1, 1, text)
local n = line2 - line1 + 1
doc():set_selection(line1 + n, col1, line2 + n, col2, swap)
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
append_line_if_last_line(line2)
local text = doc():get_text(line1, 1, line2 + 1, 1)
doc():insert(line2 + 1, 1, text)
local n = line2 - line1 + 1
doc():set_selections(idx, line1 + n, col1, line2 + n, col2, swap)
end
end,
["doc:delete-lines"] = function()
local line1, col1, line2 = doc_multiline_selection(true)
append_line_if_last_line(line2)
doc():remove(line1, 1, line2 + 1, 1)
doc():set_selection(line1, col1)
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
append_line_if_last_line(line2)
doc():remove(line1, 1, line2 + 1, 1)
doc():set_selections(idx, line1, col1)
end
end,
["doc:move-lines-up"] = function()
local line1, col1, line2, col2, swap = doc_multiline_selection(true)
append_line_if_last_line(line2)
if line1 > 1 then
local text = doc().lines[line1 - 1]
doc():insert(line2 + 1, 1, text)
doc():remove(line1 - 1, 1, line1, 1)
doc():set_selection(line1 - 1, col1, line2 - 1, col2, swap)
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
append_line_if_last_line(line2)
if line1 > 1 then
local text = doc().lines[line1 - 1]
doc():insert(line2 + 1, 1, text)
doc():remove(line1 - 1, 1, line1, 1)
doc():set_selections(idx, line1 - 1, col1, line2 - 1, col2)
end
end
end,
["doc:move-lines-down"] = function()
local line1, col1, line2, col2, swap = doc_multiline_selection(true)
append_line_if_last_line(line2 + 1)
if line2 < #doc().lines then
local text = doc().lines[line2 + 1]
doc():remove(line2 + 1, 1, line2 + 2, 1)
doc():insert(line1, 1, text)
doc():set_selection(line1 + 1, col1, line2 + 1, col2, swap)
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
append_line_if_last_line(line2 + 1)
if line2 < #doc().lines then
local text = doc().lines[line2 + 1]
doc():remove(line2 + 1, 1, line2 + 2, 1)
doc():insert(line1, 1, text)
doc():set_selections(idx, line1 + 1, col1, line2 + 1, col2)
end
end
end,
@@ -205,28 +233,29 @@ local commands = {
if not comment then return end
local indentation = get_indent_string()
local comment_text = comment .. " "
local line1, _, line2 = doc_multiline_selection(true)
local uncomment = true
local start_offset = math.huge
for line = line1, line2 do
local text = doc().lines[line]
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
for idx, line1, _, line2 in doc_multiline_selections(true) do
local uncomment = true
local start_offset = math.huge
for line = line1, line2 do
local text = doc().lines[line]
local s = text:find("%S")
local cs, ce = text:find(comment_text, s, true)
if ce then
doc():remove(line, cs, line, ce + 1)
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)
if ce then
doc():remove(line, cs, line, ce + 1)
end
elseif s then
doc():insert(line, start_offset, comment_text)
end
elseif s then
doc():insert(line, start_offset, comment_text)
end
end
end,
@@ -350,26 +379,30 @@ local translations = {
}
for name, fn in pairs(translations) do
commands["doc:move-to-" .. name] = function() doc():move_to(fn, dv()) end
commands["doc:select-to-" .. name] = function() doc():select_to(fn, dv()) end
commands["doc:delete-to-" .. name] = function() doc():delete_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(nil, fn, dv()) end
commands["doc:delete-to-" .. name] = function() doc():delete_to(nil, fn, dv()) end
end
commands["doc:move-to-previous-char"] = function()
if doc():has_selection() then
local line, col = doc():get_selection(true)
doc():set_selection(line, col)
else
doc():move_to(translate.previous_char)
for idx, line, col in doc():get_selections(true) do
if doc():has_selection(idx) then
doc():set_selections(idx, line, col)
end
end
if not doc():has_selection() then
doc():move_to(nil, translate.previous_char)
end
end
commands["doc:move-to-next-char"] = function()
if doc():has_selection() then
local _, _, line, col = doc():get_selection(true)
doc():set_selection(line, col)
else
doc():move_to(translate.next_char)
for idx, _, _, line, col in doc():get_selections(true) do
if doc():has_selection(idx) then
doc():set_selections(idx, line, col)
end
end
if not doc():has_selection() then
doc():move_to(nil, translate.next_char)
end
end