Allow command predicates to manage parameters passed to the commands

When a command is performed with parameters, those are now passed to the
predicate.
The predicate can then return, after the validity boolean, any other
value that will then be passed to the actual command.
If the predicate only returns the validity boolean, the original
parameters are passed through to the actual command.

This allows predicates to manipulate the received parameters, and allows
them to pass the result of an expensive computation to the actual
command, which won't have to recalculate it.

String and table predicates will now also return `core.active_view`.
This commit is contained in:
Guldoman 2022-08-14 01:56:58 +02:00
parent 6ccc5f6dde
commit cf29a6a45f
No known key found for this signature in database
GPG Key ID: EA928C8BDA1A8825
13 changed files with 223 additions and 233 deletions

View File

@ -33,9 +33,9 @@ function command.generate_predicate(predicate)
if type(predicate) == "table" then if type(predicate) == "table" then
local class = predicate local class = predicate
if not strict then if not strict then
predicate = function() return core.active_view:extends(class) end predicate = function(...) return core.active_view:extends(class), core.active_view, ... end
else else
predicate = function() return core.active_view:is(class) end predicate = function(...) return core.active_view:is(class), core.active_view, ... end
end end
end end
return predicate return predicate
@ -76,8 +76,16 @@ end
local function perform(name, ...) local function perform(name, ...)
local cmd = command.map[name] local cmd = command.map[name]
if cmd and cmd.predicate(...) then if not cmd then return false end
cmd.perform(...) local res = { cmd.predicate(...) }
if table.remove(res, 1) then
if #res > 0 then
-- send values returned from predicate
cmd.perform(table.unpack(res))
else
-- send original parameters
cmd.perform(...)
end
return true return true
end end
return false return false

View File

@ -2,23 +2,23 @@ local core = require "core"
local command = require "core.command" local command = require "core.command"
command.add("core.commandview", { command.add("core.commandview", {
["command:submit"] = function() ["command:submit"] = function(active_view)
core.active_view:submit() active_view:submit()
end, end,
["command:complete"] = function() ["command:complete"] = function(active_view)
core.active_view:complete() active_view:complete()
end, end,
["command:escape"] = function() ["command:escape"] = function(active_view)
core.active_view:exit() active_view:exit()
end, end,
["command:select-previous"] = function() ["command:select-previous"] = function(active_view)
core.active_view:move_suggestion_idx(1) active_view:move_suggestion_idx(1)
end, end,
["command:select-next"] = function() ["command:select-next"] = function(active_view)
core.active_view:move_suggestion_idx(-1) active_view:move_suggestion_idx(-1)
end, end,
}) })

View File

@ -3,30 +3,25 @@ local command = require "core.command"
local common = require "core.common" local common = require "core.common"
command.add("core.nagview", { command.add("core.nagview", {
["dialog:previous-entry"] = function() ["dialog:previous-entry"] = function(v)
local v = core.active_view
local hover = v.hovered_item or 1 local hover = v.hovered_item or 1
v:change_hovered(hover == 1 and #v.options or hover - 1) v:change_hovered(hover == 1 and #v.options or hover - 1)
end, end,
["dialog:next-entry"] = function() ["dialog:next-entry"] = function(v)
local v = core.active_view
local hover = v.hovered_item or 1 local hover = v.hovered_item or 1
v:change_hovered(hover == #v.options and 1 or hover + 1) v:change_hovered(hover == #v.options and 1 or hover + 1)
end, end,
["dialog:select-yes"] = function() ["dialog:select-yes"] = function(v)
local v = core.active_view
if v ~= core.nag_view then return end if v ~= core.nag_view then return end
v:change_hovered(common.find_index(v.options, "default_yes")) v:change_hovered(common.find_index(v.options, "default_yes"))
command.perform "dialog:select" command.perform "dialog:select"
end, end,
["dialog:select-no"] = function() ["dialog:select-no"] = function(v)
local v = core.active_view
if v ~= core.nag_view then return end if v ~= core.nag_view then return end
v:change_hovered(common.find_index(v.options, "default_no")) v:change_hovered(common.find_index(v.options, "default_no"))
command.perform "dialog:select" command.perform "dialog:select"
end, end,
["dialog:select"] = function() ["dialog:select"] = function(v)
local v = core.active_view
if v.hovered_item then if v.hovered_item then
v.on_selected(v.options[v.hovered_item]) v.on_selected(v.options[v.hovered_item])
v:next() v:next()

View File

@ -89,13 +89,13 @@ local function split_cursor(direction)
core.blink_reset() core.blink_reset()
end end
local function set_cursor(x, y, snap_type) local function set_cursor(dv, x, y, snap_type)
local line, col = dv():resolve_screen_position(x, y) local line, col = dv:resolve_screen_position(x, y)
doc():set_selection(line, col, line, col) dv.doc:set_selection(line, col, line, col)
if snap_type == "word" or snap_type == "lines" then if snap_type == "word" or snap_type == "lines" then
command.perform("doc:select-" .. snap_type) command.perform("doc:select-" .. snap_type)
end end
dv().mouse_selecting = { line, col, snap_type } dv.mouse_selecting = { line, col, snap_type }
core.blink_reset() core.blink_reset()
end end
@ -178,9 +178,9 @@ local function block_comment(comment, line1, col1, line2, col2)
end end
local commands = { local commands = {
["doc:select-none"] = function() ["doc:select-none"] = function(dv)
local line, col = doc():get_selection() local line, col = dv.doc:get_selection()
doc():set_selection(line, col) dv.doc:set_selection(line, col)
end, end,
["doc:cut"] = function() ["doc:cut"] = function()
@ -191,15 +191,15 @@ local commands = {
cut_or_copy(false) cut_or_copy(false)
end, end,
["doc:undo"] = function() ["doc:undo"] = function(dv)
doc():undo() dv.doc:undo()
end, end,
["doc:redo"] = function() ["doc:redo"] = function(dv)
doc():redo() dv.doc:redo()
end, end,
["doc:paste"] = function() ["doc:paste"] = function(dv)
local clipboard = system.get_clipboard() local clipboard = system.get_clipboard()
-- If the clipboard has changed since our last look, use that instead -- If the clipboard has changed since our last look, use that instead
local external_paste = core.cursor_clipboard["full"] ~= clipboard local external_paste = core.cursor_clipboard["full"] ~= clipboard
@ -208,8 +208,8 @@ local commands = {
core.cursor_clipboard_whole_line = {} core.cursor_clipboard_whole_line = {}
end end
local value, whole_line local value, whole_line
for idx, line1, col1, line2, col2 in doc():get_selections() do for idx, line1, col1, line2, col2 in dv.doc:get_selections() do
if #core.cursor_clipboard_whole_line == (#doc().selections/4) then if #core.cursor_clipboard_whole_line == (#dv.doc.selections/4) then
value = core.cursor_clipboard[idx] value = core.cursor_clipboard[idx]
whole_line = core.cursor_clipboard_whole_line[idx] == true whole_line = core.cursor_clipboard_whole_line[idx] == true
else else
@ -217,172 +217,172 @@ local commands = {
whole_line = not external_paste and clipboard:find("\n") ~= nil whole_line = not external_paste and clipboard:find("\n") ~= nil
end end
if whole_line then if whole_line then
doc():insert(line1, 1, value:gsub("\r", "")) dv.doc:insert(line1, 1, value:gsub("\r", ""))
if col1 == 1 then if col1 == 1 then
doc():move_to_cursor(idx, #value) dv.doc:move_to_cursor(idx, #value)
end end
else else
doc():text_input(value:gsub("\r", ""), idx) dv.doc:text_input(value:gsub("\r", ""), idx)
end end
end end
end, end,
["doc:newline"] = function() ["doc:newline"] = function(dv)
for idx, line, col in doc():get_selections(false, true) do for idx, line, col in dv.doc:get_selections(false, true) do
local indent = doc().lines[line]:match("^[\t ]*") local indent = dv.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 end
-- Remove current line if it contains only whitespace -- Remove current line if it contains only whitespace
if doc().lines[line]:match("^%s+$") then if dv.doc.lines[line]:match("^%s+$") then
doc():remove(line, 1, line, math.huge) dv.doc:remove(line, 1, line, math.huge)
end end
doc():text_input("\n" .. indent, idx) dv.doc:text_input("\n" .. indent, idx)
end end
end, end,
["doc:newline-below"] = function() ["doc:newline-below"] = function(dv)
for idx, line in doc():get_selections(false, true) do for idx, line in dv.doc:get_selections(false, true) do
local indent = doc().lines[line]:match("^[\t ]*") local indent = dv.doc.lines[line]:match("^[\t ]*")
doc():insert(line, math.huge, "\n" .. indent) dv.doc:insert(line, math.huge, "\n" .. indent)
doc():set_selections(idx, line + 1, math.huge) dv.doc:set_selections(idx, line + 1, math.huge)
end end
end, end,
["doc:newline-above"] = function() ["doc:newline-above"] = function(dv)
for idx, line in doc():get_selections(false, true) do for idx, line in dv.doc:get_selections(false, true) do
local indent = doc().lines[line]:match("^[\t ]*") local indent = dv.doc.lines[line]:match("^[\t ]*")
doc():insert(line, 1, indent .. "\n") dv.doc:insert(line, 1, indent .. "\n")
doc():set_selections(idx, line, math.huge) dv.doc:set_selections(idx, line, math.huge)
end end
end, end,
["doc:delete"] = function() ["doc:delete"] = function(dv)
for idx, line1, col1, line2, col2 in doc():get_selections() do for idx, line1, col1, line2, col2 in dv.doc:get_selections() do
if line1 == line2 and col1 == col2 and doc().lines[line1]:find("^%s*$", col1) then if line1 == line2 and col1 == col2 and dv.doc.lines[line1]:find("^%s*$", col1) then
doc():remove(line1, col1, line1, math.huge) dv.doc:remove(line1, col1, line1, math.huge)
end end
doc():delete_to_cursor(idx, translate.next_char) dv.doc:delete_to_cursor(idx, translate.next_char)
end end
end, end,
["doc:backspace"] = function() ["doc:backspace"] = function(dv)
local _, indent_size = doc():get_indent_info() local _, indent_size = dv.doc:get_indent_info()
for idx, line1, col1, line2, col2 in doc():get_selections() do for idx, line1, col1, line2, col2 in dv.doc:get_selections() do
if line1 == line2 and col1 == col2 then if line1 == line2 and col1 == col2 then
local text = doc():get_text(line1, 1, line1, col1) local text = dv.doc:get_text(line1, 1, line1, col1)
if #text >= indent_size and text:find("^ *$") then if #text >= indent_size and text:find("^ *$") then
doc():delete_to_cursor(idx, 0, -indent_size) dv.doc:delete_to_cursor(idx, 0, -indent_size)
return return
end end
end end
doc():delete_to_cursor(idx, translate.previous_char) dv.doc:delete_to_cursor(idx, translate.previous_char)
end end
end, end,
["doc:select-all"] = function() ["doc:select-all"] = function(dv)
doc():set_selection(1, 1, math.huge, math.huge) dv.doc:set_selection(1, 1, math.huge, math.huge)
-- avoid triggering DocView:scroll_to_make_visible -- avoid triggering DocView:scroll_to_make_visible
dv().last_line1 = 1 dv.last_line1 = 1
dv().last_col1 = 1 dv.last_col1 = 1
dv().last_line2 = #doc().lines dv.last_line2 = #dv.doc.lines
dv().last_col2 = #doc().lines[#doc().lines] dv.last_col2 = #dv.doc.lines[#dv.doc.lines]
end, end,
["doc:select-lines"] = function() ["doc:select-lines"] = function(dv)
for idx, line1, _, line2 in doc():get_selections(true) do for idx, line1, _, line2 in dv.doc:get_selections(true) do
append_line_if_last_line(line2) append_line_if_last_line(line2)
doc():set_selections(idx, line1, 1, line2 + 1, 1) dv.doc:set_selections(idx, line1, 1, line2 + 1, 1)
end end
end, end,
["doc:select-word"] = function() ["doc:select-word"] = function(dv)
for idx, line1, col1 in doc():get_selections(true) do for idx, line1, col1 in dv.doc:get_selections(true) do
local line1, col1 = translate.start_of_word(doc(), line1, col1) local line1, col1 = translate.start_of_word(dv.doc, line1, col1)
local line2, col2 = translate.end_of_word(doc(), line1, col1) local line2, col2 = translate.end_of_word(dv.doc, line1, col1)
doc():set_selections(idx, line2, col2, line1, col1) dv.doc:set_selections(idx, line2, col2, line1, col1)
end end
end, end,
["doc:join-lines"] = function() ["doc:join-lines"] = function(dv)
for idx, line1, col1, line2, col2 in doc():get_selections(true) do for idx, line1, col1, line2, col2 in dv.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 = dv.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) dv.doc:insert(line1, 1, text)
doc():remove(line1, #text + 1, line2, math.huge) dv.doc:remove(line1, #text + 1, line2, math.huge)
if line1 ~= line2 or col1 ~= col2 then if line1 ~= line2 or col1 ~= col2 then
doc():set_selections(idx, line1, math.huge) dv.doc:set_selections(idx, line1, math.huge)
end end
end end
end, end,
["doc:indent"] = function() ["doc:indent"] = function(dv)
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do 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) local l1, c1, l2, c2 = dv.doc:indent_text(false, line1, col1, line2, col2)
if l1 then if l1 then
doc():set_selections(idx, l1, c1, l2, c2) dv.doc:set_selections(idx, l1, c1, l2, c2)
end end
end end
end, end,
["doc:unindent"] = function() ["doc:unindent"] = function(dv)
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do 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) local l1, c1, l2, c2 = dv.doc:indent_text(true, line1, col1, line2, col2)
if l1 then if l1 then
doc():set_selections(idx, l1, c1, l2, c2) dv.doc:set_selections(idx, l1, c1, l2, c2)
end end
end end
end, end,
["doc:duplicate-lines"] = function() ["doc:duplicate-lines"] = function(dv)
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do 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) dv.doc:insert(line2 + 1, 1, text)
local n = line2 - line1 + 1 local n = line2 - line1 + 1
doc():set_selections(idx, line1 + n, col1, line2 + n, col2) dv.doc:set_selections(idx, line1 + n, col1, line2 + n, col2)
end end
end, end,
["doc:delete-lines"] = function() ["doc:delete-lines"] = function(dv)
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do 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) dv.doc:remove(line1, 1, line2 + 1, 1)
doc():set_selections(idx, line1, col1) dv.doc:set_selections(idx, line1, col1)
end end
end, end,
["doc:move-lines-up"] = function() ["doc:move-lines-up"] = function(dv)
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do 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) dv.doc:insert(line2 + 1, 1, text)
doc():remove(line1 - 1, 1, line1, 1) dv.doc:remove(line1 - 1, 1, line1, 1)
doc():set_selections(idx, line1 - 1, col1, line2 - 1, col2) dv.doc:set_selections(idx, line1 - 1, col1, line2 - 1, col2)
end end
end end
end, end,
["doc:move-lines-down"] = function() ["doc:move-lines-down"] = function(dv)
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do 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 < #dv.doc.lines then
local text = doc().lines[line2 + 1] local text = dv.doc.lines[line2 + 1]
doc():remove(line2 + 1, 1, line2 + 2, 1) dv.doc:remove(line2 + 1, 1, line2 + 2, 1)
doc():insert(line1, 1, text) dv.doc:insert(line1, 1, text)
doc():set_selections(idx, line1 + 1, col1, line2 + 1, col2) dv.doc:set_selections(idx, line1 + 1, col1, line2 + 1, col2)
end end
end end
end, end,
["doc:toggle-block-comments"] = function() ["doc:toggle-block-comments"] = function(dv)
local comment = doc().syntax.block_comment local comment = dv.doc.syntax.block_comment
if not comment then if not comment then
if doc().syntax.comment then if dv.doc.syntax.comment then
command.perform "doc:toggle-line-comments" command.perform "doc:toggle-line-comments"
end end
return return
@ -392,32 +392,30 @@ local commands = {
-- if nothing is selected, toggle the whole line -- if nothing is selected, toggle the whole line
if line1 == line2 and col1 == col2 then if line1 == line2 and col1 == col2 then
col1 = 1 col1 = 1
col2 = #doc().lines[line2] col2 = #dv.doc.lines[line2]
end end
doc():set_selections(idx, block_comment(comment, line1, col1, line2, col2)) dv.doc:set_selections(idx, block_comment(comment, line1, col1, line2, col2))
end end
end, end,
["doc:toggle-line-comments"] = function() ["doc:toggle-line-comments"] = function(dv)
local comment = doc().syntax.comment or doc().syntax.block_comment local comment = dv.doc.syntax.comment or dv.doc.syntax.block_comment
if comment then if comment then
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
doc():set_selections(idx, line_comment(comment, line1, col1, line2, col2)) dv.doc:set_selections(idx, line_comment(comment, line1, col1, line2, col2))
end end
end end
end, end,
["doc:upper-case"] = function() ["doc:upper-case"] = function(dv)
doc():replace(string.uupper) dv.doc:replace(string.uupper)
end, end,
["doc:lower-case"] = function() ["doc:lower-case"] = function(dv)
doc():replace(string.ulower) dv.doc:replace(string.ulower)
end, end,
["doc:go-to-line"] = function() ["doc:go-to-line"] = function(dv)
local dv = dv()
local items local items
local function init_items() local function init_items()
if items then return end if items then return end
@ -448,15 +446,15 @@ local commands = {
}) })
end, end,
["doc:toggle-line-ending"] = function() ["doc:toggle-line-ending"] = function(dv)
doc().crlf = not doc().crlf dv.doc.crlf = not dv.doc.crlf
end, end,
["doc:save-as"] = function() ["doc:save-as"] = function(dv)
local last_doc = core.last_active_view and core.last_active_view.doc local last_doc = core.last_active_view and core.last_active_view.doc
local text local text
if doc().filename then if dv.doc.filename then
text = doc().filename text = dv.doc.filename
elseif last_doc and last_doc.filename then elseif last_doc and last_doc.filename then
local dirname, filename = core.last_active_view.doc.abs_filename:match("(.*)[/\\](.+)$") local dirname, filename = core.last_active_view.doc.abs_filename:match("(.*)[/\\](.+)$")
text = core.normalize_to_project_dir(dirname) .. PATHSEP text = core.normalize_to_project_dir(dirname) .. PATHSEP
@ -472,20 +470,20 @@ local commands = {
}) })
end, end,
["doc:save"] = function() ["doc:save"] = function(dv)
if doc().filename then if dv.doc.filename then
save() save()
else else
command.perform("doc:save-as") command.perform("doc:save-as")
end end
end, end,
["doc:reload"] = function() ["doc:reload"] = function(dv)
doc():reload() dv.doc:reload()
end, end,
["file:rename"] = function() ["file:rename"] = function(dv)
local old_filename = doc().filename local old_filename = dv.doc.filename
if not old_filename then if not old_filename then
core.error("Cannot rename unsaved doc") core.error("Cannot rename unsaved doc")
return return
@ -506,13 +504,13 @@ local commands = {
end, end,
["file:delete"] = function() ["file:delete"] = function(dv)
local filename = doc().abs_filename local filename = dv.doc.abs_filename
if not filename then if not filename then
core.error("Cannot remove unsaved doc") core.error("Cannot remove unsaved doc")
return return
end end
for i,docview in ipairs(core.get_views_referencing_doc(doc())) do for i,docview in ipairs(core.get_views_referencing_doc(dv.doc)) do
local node = core.root_view.root_node:get_node_for_view(docview) local node = core.root_view.root_node:get_node_for_view(docview)
node:close_view(core.root_view.root_node, docview) node:close_view(core.root_view.root_node, docview)
end end
@ -520,56 +518,57 @@ local commands = {
core.log("Removed \"%s\"", filename) core.log("Removed \"%s\"", filename)
end, end,
["doc:select-to-cursor"] = function(x, y, clicks) ["doc:select-to-cursor"] = function(dv, x, y, clicks)
local line1, col1 = select(3, doc():get_selection()) local line1, col1 = select(3, doc():get_selection())
local line2, col2 = dv():resolve_screen_position(x, y) local line2, col2 = dv:resolve_screen_position(x, y)
dv().mouse_selecting = { line1, col1, nil } dv.mouse_selecting = { line1, col1, nil }
doc():set_selection(line2, col2, line1, col1) dv.doc:set_selection(line2, col2, line1, col1)
end, end,
["doc:create-cursor-previous-line"] = function() ["doc:create-cursor-previous-line"] = function(dv)
split_cursor(-1) split_cursor(-1)
doc():merge_cursors() dv.doc:merge_cursors()
end, end,
["doc:create-cursor-next-line"] = function() ["doc:create-cursor-next-line"] = function(dv)
split_cursor(1) split_cursor(1)
doc():merge_cursors() dv.doc:merge_cursors()
end end
} }
command.add(function(x, y) command.add(function(x, y)
if x == nil or y == nil or not doc() then return false end if x == nil or y == nil or not core.active_view:is(DocView) then return false end
local x1,y1,x2,y2 = dv().position.x, dv().position.y, dv().position.x + dv().size.x, dv().position.y + dv().size.y local dv = core.active_view
return x >= x1 + dv():get_gutter_width() and x < x2 and y >= y1 and y < y2 local x1,y1,x2,y2 = dv.position.x, dv.position.y, dv.position.x + dv.size.x, dv.position.y + dv.size.y
return x >= x1 + dv:get_gutter_width() and x < x2 and y >= y1 and y < y2, dv, x, y
end, { end, {
["doc:set-cursor"] = function(x, y) ["doc:set-cursor"] = function(dv, x, y)
set_cursor(x, y, "set") set_cursor(dv, x, y, "set")
end, end,
["doc:set-cursor-word"] = function(x, y) ["doc:set-cursor-word"] = function(dv, x, y)
set_cursor(x, y, "word") set_cursor(dv, x, y, "word")
end, end,
["doc:set-cursor-line"] = function(x, y, clicks) ["doc:set-cursor-line"] = function(dv, x, y, clicks)
set_cursor(x, y, "lines") set_cursor(dv, x, y, "lines")
end, end,
["doc:split-cursor"] = function(x, y, clicks) ["doc:split-cursor"] = function(dv, x, y, clicks)
local line, col = dv():resolve_screen_position(x, y) local line, col = dv:resolve_screen_position(x, y)
local removal_target = nil local removal_target = nil
for idx, line1, col1 in doc():get_selections(true) do for idx, line1, col1 in dv.doc:get_selections(true) do
if line1 == line and col1 == col and #doc().selections > 4 then if line1 == line and col1 == col and #doc().selections > 4 then
removal_target = idx removal_target = idx
end end
end end
if removal_target then if removal_target then
doc():remove_selection(removal_target) dv.doc:remove_selection(removal_target)
else else
doc():add_selection(line, col, line, col) dv.doc:add_selection(line, col, line, col)
end end
dv().mouse_selecting = { line, col, "set" } dv.mouse_selecting = { line, col, "set" }
end end
}) })
@ -594,27 +593,27 @@ local translations = {
} }
for name, obj in pairs(translations) do for name, obj in pairs(translations) do
commands["doc:move-to-" .. name] = function() doc():move_to(obj[name:gsub("-", "_")], dv()) end commands["doc:move-to-" .. name] = function(dv) dv.doc:move_to(obj[name:gsub("-", "_")], dv) end
commands["doc:select-to-" .. name] = function() doc():select_to(obj[name:gsub("-", "_")], dv()) end commands["doc:select-to-" .. name] = function(dv) dv.doc:select_to(obj[name:gsub("-", "_")], dv) end
commands["doc:delete-to-" .. name] = function() doc():delete_to(obj[name:gsub("-", "_")], dv()) end commands["doc:delete-to-" .. name] = function(dv) dv.doc:delete_to(obj[name:gsub("-", "_")], dv) end
end end
commands["doc:move-to-previous-char"] = function() commands["doc:move-to-previous-char"] = function(dv)
for idx, line1, col1, line2, col2 in doc():get_selections(true) do for idx, line1, col1, line2, col2 in dv.doc:get_selections(true) do
if line1 ~= line2 or col1 ~= col2 then if line1 ~= line2 or col1 ~= col2 then
doc():set_selections(idx, line1, col1) dv.doc:set_selections(idx, line1, col1)
else else
doc():move_to_cursor(idx, translate.previous_char) dv.doc:move_to_cursor(idx, translate.previous_char)
end end
end end
end end
commands["doc:move-to-next-char"] = function() commands["doc:move-to-next-char"] = function(dv)
for idx, line1, col1, line2, col2 in doc():get_selections(true) do for idx, line1, col1, line2, col2 in dv.doc:get_selections(true) do
if line1 ~= line2 or col1 ~= col2 then if line1 ~= line2 or col1 ~= col2 then
doc():set_selections(idx, line2, col2) dv.doc:set_selections(idx, line2, col2)
else else
doc():move_to_cursor(idx, translate.next_char) dv.doc:move_to_cursor(idx, translate.next_char)
end end
end end
end end

View File

@ -7,13 +7,11 @@ local config = require "core.config"
local t = { local t = {
["root:close"] = function() ["root:close"] = function(node)
local node = core.root_view:get_active_node()
node:close_active_view(core.root_view.root_node) node:close_active_view(core.root_view.root_node)
end, end,
["root:close-or-quit"] = function() ["root:close-or-quit"] = function(node)
local node = core.root_view:get_active_node()
if node and (not node:is_empty() or not node.is_primary_node) then if node and (not node:is_empty() or not node.is_primary_node) then
node:close_active_view(core.root_view.root_node) node:close_active_view(core.root_view.root_node)
else else
@ -31,24 +29,21 @@ local t = {
core.confirm_close_docs(docs, core.root_view.close_all_docviews, core.root_view, true) core.confirm_close_docs(docs, core.root_view.close_all_docviews, core.root_view, true)
end, end,
["root:switch-to-previous-tab"] = function() ["root:switch-to-previous-tab"] = function(node)
local node = core.root_view:get_active_node()
local idx = node:get_view_idx(core.active_view) local idx = node:get_view_idx(core.active_view)
idx = idx - 1 idx = idx - 1
if idx < 1 then idx = #node.views end if idx < 1 then idx = #node.views end
node:set_active_view(node.views[idx]) node:set_active_view(node.views[idx])
end, end,
["root:switch-to-next-tab"] = function() ["root:switch-to-next-tab"] = function(node)
local node = core.root_view:get_active_node()
local idx = node:get_view_idx(core.active_view) local idx = node:get_view_idx(core.active_view)
idx = idx + 1 idx = idx + 1
if idx > #node.views then idx = 1 end if idx > #node.views then idx = 1 end
node:set_active_view(node.views[idx]) node:set_active_view(node.views[idx])
end, end,
["root:move-tab-left"] = function() ["root:move-tab-left"] = function(node)
local node = core.root_view:get_active_node()
local idx = node:get_view_idx(core.active_view) local idx = node:get_view_idx(core.active_view)
if idx > 1 then if idx > 1 then
table.remove(node.views, idx) table.remove(node.views, idx)
@ -56,8 +51,7 @@ local t = {
end end
end, end,
["root:move-tab-right"] = function() ["root:move-tab-right"] = function(node)
local node = core.root_view:get_active_node()
local idx = node:get_view_idx(core.active_view) local idx = node:get_view_idx(core.active_view)
if idx < #node.views then if idx < #node.views then
table.remove(node.views, idx) table.remove(node.views, idx)
@ -65,15 +59,13 @@ local t = {
end end
end, end,
["root:shrink"] = function() ["root:shrink"] = function(node)
local node = core.root_view:get_active_node()
local parent = node:get_parent_node(core.root_view.root_node) local parent = node:get_parent_node(core.root_view.root_node)
local n = (parent.a == node) and -0.1 or 0.1 local n = (parent.a == node) and -0.1 or 0.1
parent.divider = common.clamp(parent.divider + n, 0.1, 0.9) parent.divider = common.clamp(parent.divider + n, 0.1, 0.9)
end, end,
["root:grow"] = function() ["root:grow"] = function(node)
local node = core.root_view:get_active_node()
local parent = node:get_parent_node(core.root_view.root_node) local parent = node:get_parent_node(core.root_view.root_node)
local n = (parent.a == node) and 0.1 or -0.1 local n = (parent.a == node) and 0.1 or -0.1
parent.divider = common.clamp(parent.divider + n, 0.1, 0.9) parent.divider = common.clamp(parent.divider + n, 0.1, 0.9)
@ -82,8 +74,7 @@ local t = {
for i = 1, 9 do for i = 1, 9 do
t["root:switch-to-tab-" .. i] = function() t["root:switch-to-tab-" .. i] = function(node)
local node = core.root_view:get_active_node()
local view = node.views[i] local view = node.views[i]
if view then if view then
node:set_active_view(view) node:set_active_view(view)
@ -93,8 +84,7 @@ end
for _, dir in ipairs { "left", "right", "up", "down" } do for _, dir in ipairs { "left", "right", "up", "down" } do
t["root:split-" .. dir] = function() t["root:split-" .. dir] = function(node)
local node = core.root_view:get_active_node()
local av = node.active_view local av = node.active_view
node:split(dir) node:split(dir)
if av:is(DocView) then if av:is(DocView) then
@ -102,8 +92,7 @@ for _, dir in ipairs { "left", "right", "up", "down" } do
end end
end end
t["root:switch-to-" .. dir] = function() t["root:switch-to-" .. dir] = function(node)
local node = core.root_view:get_active_node()
local x, y local x, y
if dir == "left" or dir == "right" then if dir == "left" or dir == "right" then
y = node.position.y + node.size.y / 2 y = node.position.y + node.size.y / 2
@ -123,7 +112,7 @@ end
command.add(function() command.add(function()
local node = core.root_view:get_active_node() local node = core.root_view:get_active_node()
local sx, sy = node:get_locked_size() local sx, sy = node:get_locked_size()
return not sx and not sy return not sx and not sy, node
end, t) end, t)
command.add(nil, { command.add(nil, {

View File

@ -621,12 +621,13 @@ end
-- Commands -- Commands
-- --
local function predicate() local function predicate()
return get_active_view() and #suggestions > 0 local active_docview = get_active_view()
return active_docview and #suggestions > 0, active_docview
end end
command.add(predicate, { command.add(predicate, {
["autocomplete:complete"] = function() ["autocomplete:complete"] = function(dv)
local doc = core.active_view.doc local doc = dv.doc
local line, col = doc:get_selection() local line, col = doc:get_selection()
local item = suggestions[suggestions_idx] local item = suggestions[suggestions_idx]
local text = item.text local text = item.text

View File

@ -33,8 +33,8 @@ function RootView:draw(...)
end end
command.add("core.docview!", { command.add("core.docview!", {
["context:show"] = function() ["context:show"] = function(dv)
menu:show(core.active_view.position.x, core.active_view.position.y) menu:show(dv.position.x, dv.position.y)
end end
}) })

View File

@ -299,10 +299,10 @@ local function set_indent_type(doc, type)
doc.indent_info = cache[doc] doc.indent_info = cache[doc]
end end
local function set_indent_type_command() local function set_indent_type_command(dv)
core.command_view:enter("Specify indent style for this file", { core.command_view:enter("Specify indent style for this file", {
submit = function(value) submit = function(value)
local doc = core.active_view.doc local doc = dv.doc
value = value:lower() value = value:lower()
set_indent_type(doc, value == "tabs" and "hard" or "soft") set_indent_type(doc, value == "tabs" and "hard" or "soft")
end, end,
@ -327,11 +327,11 @@ local function set_indent_size(doc, size)
doc.indent_info = cache[doc] doc.indent_info = cache[doc]
end end
local function set_indent_size_command() local function set_indent_size_command(dv)
core.command_view:enter("Specify indent size for current file", { core.command_view:enter("Specify indent size for current file", {
submit = function(value) submit = function(value)
value = math.floor(tonumber(value)) value = math.floor(tonumber(value))
local doc = core.active_view.doc local doc = dv.doc
set_indent_size(doc, value) set_indent_size(doc, value)
end, end,
validate = function(value) validate = function(value)

View File

@ -19,8 +19,8 @@ end
command.add("core.docview", { command.add("core.docview", {
["quote:quote"] = function() ["quote:quote"] = function(dv)
core.active_view.doc:replace(function(text) dv.doc:replace(function(text)
return '"' .. text:gsub("[\0-\31\\\"]", replace) .. '"' return '"' .. text:gsub("[\0-\31\\\"]", replace) .. '"'
end) end)
end, end,

View File

@ -25,8 +25,8 @@ end
command.add("core.docview", { command.add("core.docview", {
["reflow:reflow"] = function() ["reflow:reflow"] = function(dv)
local doc = core.active_view.doc local doc = dv.doc
doc:replace(function(text) doc:replace(function(text)
local prefix_set = "[^%w\n%[%](){}`'\"]*" local prefix_set = "[^%w\n%[%](){}`'\"]*"

View File

@ -41,17 +41,17 @@ end
command.add("core.docview", { command.add("core.docview", {
["tabularize:tabularize"] = function() ["tabularize:tabularize"] = function(dv)
core.command_view:enter("Tabularize On Delimiter", { core.command_view:enter("Tabularize On Delimiter", {
submit = function(delim) submit = function(delim)
if delim == "" then delim = " " end if delim == "" then delim = " " end
local doc = core.active_view.doc local doc = dv.doc
local line1, col1, line2, col2, swap = doc:get_selection(true) local line1, col1, line2, col2, swap = doc:get_selection(true)
line1, col1 = doc:position_offset(line1, col1, translate.start_of_line) line1, col1 = doc:position_offset(line1, col1, translate.start_of_line)
line2, col2 = doc:position_offset(line2, col2, translate.end_of_line) line2, col2 = doc:position_offset(line2, col2, translate.end_of_line)
doc:set_selection(line1, col1, line2, col2, swap) doc:set_selection(line1, col1, line2, col2, swap)
doc:replace(function(text) doc:replace(function(text)
local lines = gmatch_to_array(text, "[^\n]*\n?") local lines = gmatch_to_array(text, "[^\n]*\n?")
tabularize_lines(lines, delim) tabularize_lines(lines, delim)

View File

@ -679,16 +679,16 @@ local function treeitem() return view.hovered_item or view.selected_item end
command.add( command.add(
function() function()
return treeitem() ~= nil local item = treeitem()
return item ~= nil
and ( and (
core.active_view == view or core.active_view == menu core.active_view == view or core.active_view == menu
or (view.toolbar and core.active_view == view.toolbar) or (view.toolbar and core.active_view == view.toolbar)
-- sometimes the context menu is shown on top of statusbar -- sometimes the context menu is shown on top of statusbar
or core.active_view == core.status_view or core.active_view == core.status_view
) ), item
end, { end, {
["treeview:delete"] = function() ["treeview:delete"] = function(item)
local item = treeitem()
local filename = item.abs_filename local filename = item.abs_filename
local relfilename = item.filename local relfilename = item.filename
if item.dir_name ~= core.project_dir then if item.dir_name ~= core.project_dir then
@ -732,9 +732,11 @@ command.add(
}) })
command.add(function() return treeitem() ~= nil end, { command.add(function()
["treeview:rename"] = function()
local item = treeitem() local item = treeitem()
return item ~= nil, item
end, {
["treeview:rename"] = function(item)
local old_filename = item.filename local old_filename = item.filename
local old_abs_filename = item.abs_filename local old_abs_filename = item.abs_filename
core.command_view:enter("Rename", { core.command_view:enter("Rename", {
@ -764,9 +766,8 @@ command.add(function() return treeitem() ~= nil end, {
}) })
end, end,
["treeview:new-file"] = function() ["treeview:new-file"] = function(item)
local text local text
local item = treeitem()
if not is_project_folder(item.abs_filename) then if not is_project_folder(item.abs_filename) then
text = item.filename .. PATHSEP text = item.filename .. PATHSEP
end end
@ -787,9 +788,8 @@ command.add(function() return treeitem() ~= nil end, {
}) })
end, end,
["treeview:new-folder"] = function() ["treeview:new-folder"] = function(item)
local text local text
local item = treeitem()
if not is_project_folder(item.abs_filename) then if not is_project_folder(item.abs_filename) then
text = item.filename .. PATHSEP text = item.filename .. PATHSEP
end end
@ -806,15 +806,13 @@ command.add(function() return treeitem() ~= nil end, {
}) })
end, end,
["treeview:open-in-system"] = function() ["treeview:open-in-system"] = function(item)
local hovered_item = treeitem()
if PLATFORM == "Windows" then if PLATFORM == "Windows" then
system.exec(string.format("start \"\" %q", hovered_item.abs_filename)) system.exec(string.format("start \"\" %q", item.abs_filename))
elseif string.find(PLATFORM, "Mac") then elseif string.find(PLATFORM, "Mac") then
system.exec(string.format("open %q", hovered_item.abs_filename)) system.exec(string.format("open %q", item.abs_filename))
elseif PLATFORM == "Linux" or string.find(PLATFORM, "BSD") then elseif PLATFORM == "Linux" or string.find(PLATFORM, "BSD") then
system.exec(string.format("xdg-open %q", hovered_item.abs_filename)) system.exec(string.format("xdg-open %q", item.abs_filename))
end end
end end
}) })
@ -823,10 +821,10 @@ command.add(function()
local item = treeitem() local item = treeitem()
return item return item
and not is_primary_project_folder(item.abs_filename) and not is_primary_project_folder(item.abs_filename)
and is_project_folder(item.abs_filename) and is_project_folder(item.abs_filename), item
end, { end, {
["treeview:remove-project-directory"] = function() ["treeview:remove-project-directory"] = function(item)
core.remove_project_directory(treeitem().dir_name) core.remove_project_directory(item.dir_name)
end, end,
}) })

View File

@ -24,8 +24,8 @@ end
command.add("core.docview", { command.add("core.docview", {
["trim-whitespace:trim-trailing-whitespace"] = function() ["trim-whitespace:trim-trailing-whitespace"] = function(dv)
trim_trailing_whitespace(core.active_view.doc) trim_trailing_whitespace(dv.doc)
end, end,
}) })