Added in tooltips, the ability to swap between different find modes with a keybind.
This commit is contained in:
parent
2486f253eb
commit
305921299f
|
@ -2,67 +2,70 @@ local core = require "core"
|
||||||
local command = require "core.command"
|
local command = require "core.command"
|
||||||
local config = require "core.config"
|
local config = require "core.config"
|
||||||
local search = require "core.doc.search"
|
local search = require "core.doc.search"
|
||||||
|
local keymap = require "core.keymap"
|
||||||
local DocView = require "core.docview"
|
local DocView = require "core.docview"
|
||||||
|
local CommandView = require "core.commandview"
|
||||||
|
local StatusView = require "core.statusview"
|
||||||
|
|
||||||
local max_previous_finds = 50
|
local max_last_finds = 50
|
||||||
|
local last_finds, last_view, last_fn, last_text, last_sel
|
||||||
|
|
||||||
|
local case_insensitive = config.find_case_insensitive or false
|
||||||
|
local plain = config.find_plain or false
|
||||||
|
|
||||||
local function doc()
|
local function doc()
|
||||||
return core.active_view.doc
|
return last_view and last_view.doc or core.active_view.doc
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function get_find_tooltip()
|
||||||
local previous_finds
|
local rf = keymap.get_binding("find-replace:repeat-find")
|
||||||
local last_doc
|
local ti = keymap.get_binding("find-replace:toggle-insensitivity")
|
||||||
local last_fn, last_text
|
local tr = keymap.get_binding("find-replace:toggle-plain")
|
||||||
|
return (plain and "[Plain] " or "") ..
|
||||||
|
(case_insensitive and "[Insensitive] " or "") ..
|
||||||
local function push_previous_find(doc, sel)
|
(rf and ("Press " .. rf .. " to select the next match.") or "") ..
|
||||||
if last_doc ~= doc then
|
(ti and (" " .. ti .. " toggles case sensitivity.") or "") ..
|
||||||
last_doc = doc
|
(tr and (" " .. tr .. " toggles plain find.") or "")
|
||||||
previous_finds = {}
|
|
||||||
end
|
|
||||||
if #previous_finds >= max_previous_finds then
|
|
||||||
table.remove(previous_finds, 1)
|
|
||||||
end
|
|
||||||
table.insert(previous_finds, sel or { doc:get_selection() })
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function update_preview(sel, search_fn, text)
|
||||||
|
local ok, line1, col1, line2, col2 =
|
||||||
|
pcall(search_fn, last_view.doc, sel[1], sel[2], text, case_insensitive, plain)
|
||||||
|
if ok and line1 and text ~= "" then
|
||||||
|
last_view.doc:set_selection(line2, col2, line1, col1)
|
||||||
|
last_view:scroll_to_line(line2, true)
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
last_view.doc:set_selection(unpack(sel))
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function find(label, search_fn)
|
local function find(label, search_fn)
|
||||||
local dv = core.active_view
|
last_view, last_sel, last_finds = core.active_view,
|
||||||
local sel = { dv.doc:get_selection() }
|
{ core.active_view.doc:get_selection() }, {}
|
||||||
local text = dv.doc:get_text(table.unpack(sel))
|
local text, found = last_view.doc:get_text(unpack(last_sel)), false
|
||||||
local found = false
|
|
||||||
|
|
||||||
core.command_view:set_text(text, true)
|
core.command_view:set_text(text, true)
|
||||||
|
core.status_view:show_tooltip(get_find_tooltip())
|
||||||
|
|
||||||
core.command_view:enter(label, function(text)
|
core.command_view:enter(label, function(text)
|
||||||
|
core.status_view:remove_tooltip()
|
||||||
if found then
|
if found then
|
||||||
last_fn, last_text = search_fn, text
|
last_fn, last_text = search_fn, text
|
||||||
previous_finds = {}
|
|
||||||
push_previous_find(dv.doc, sel)
|
|
||||||
else
|
else
|
||||||
core.error("Couldn't find %q", text)
|
core.error("Couldn't find %q", text)
|
||||||
dv.doc:set_selection(table.unpack(sel))
|
last_view.doc:set_selection(unpack(last_sel))
|
||||||
dv:scroll_to_make_visible(sel[1], sel[2])
|
last_view:scroll_to_make_visible(unpack(last_sel))
|
||||||
end
|
end
|
||||||
|
|
||||||
end, function(text)
|
end, function(text)
|
||||||
local ok, line1, col1, line2, col2 = pcall(search_fn, dv.doc, sel[1], sel[2], text)
|
found = update_preview(last_sel, search_fn, text)
|
||||||
if ok and line1 and text ~= "" then
|
last_fn, last_text = search_fn, text
|
||||||
dv.doc:set_selection(line2, col2, line1, col1)
|
|
||||||
dv:scroll_to_line(line2, true)
|
|
||||||
found = true
|
|
||||||
else
|
|
||||||
dv.doc:set_selection(table.unpack(sel))
|
|
||||||
found = false
|
|
||||||
end
|
|
||||||
|
|
||||||
end, function(explicit)
|
end, function(explicit)
|
||||||
|
core.status_view:remove_tooltip()
|
||||||
if explicit then
|
if explicit then
|
||||||
dv.doc:set_selection(table.unpack(sel))
|
last_view.doc:set_selection(unpack(last_sel))
|
||||||
dv:scroll_to_make_visible(sel[1], sel[2])
|
last_view:scroll_to_make_visible(unpack(last_sel))
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@ -71,6 +74,7 @@ end
|
||||||
local function replace(kind, default, fn)
|
local function replace(kind, default, fn)
|
||||||
core.command_view:set_text(default, true)
|
core.command_view:set_text(default, true)
|
||||||
|
|
||||||
|
core.status_view:show_tooltip(get_find_tooltip())
|
||||||
core.command_view:enter("Find To Replace " .. kind, function(old)
|
core.command_view:enter("Find To Replace " .. kind, function(old)
|
||||||
core.command_view:set_text(old, true)
|
core.command_view:set_text(old, true)
|
||||||
|
|
||||||
|
@ -80,75 +84,39 @@ local function replace(kind, default, fn)
|
||||||
return fn(text, old, new)
|
return fn(text, old, new)
|
||||||
end)
|
end)
|
||||||
core.log("Replaced %d instance(s) of %s %q with %q", n, kind, old, new)
|
core.log("Replaced %d instance(s) of %s %q with %q", n, kind, old, new)
|
||||||
|
end, function() end, function()
|
||||||
|
core.status_view:remove_tooltip()
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function has_selection()
|
local function has_selection()
|
||||||
return core.active_view:is(DocView)
|
return core.active_view:is(DocView) and core.active_view.doc:has_selection()
|
||||||
and core.active_view.doc:has_selection()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
command.add(has_selection, {
|
command.add(has_selection, {
|
||||||
["find-replace:select-next"] = function()
|
["find-replace:select-next"] = function()
|
||||||
local l1, c1, l2, c2 = doc():get_selection(true)
|
local l1, c1, l2, c2 = doc():get_selection(true)
|
||||||
local text = doc():get_text(l1, c1, l2, c2)
|
local text = doc():get_text(l1, c1, l2, c2)
|
||||||
local l1, c1, l2, c2 = search.find(doc(), l2, c2, text, { wrap = true })
|
l1, c1, l2, c2 = search.find(doc(), l2, c2, text, { wrap = true })
|
||||||
if l2 then doc():set_selection(l2, c2, l1, c1) end
|
if l2 then doc():set_selection(l2, c2, l1, c1) end
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
command.add("core.docview", {
|
command.add("core.docview", {
|
||||||
["find-replace:find"] = function()
|
["find-replace:find"] = function()
|
||||||
find("Find Text", function(doc, line, col, text)
|
find("Find Text", function(doc, line, col, text, case_insensitive, plain)
|
||||||
local opt = { wrap = true, no_case = true }
|
local opt = { wrap = true, no_case = case_insensitive, regex = not plain }
|
||||||
return search.find(doc, line, col, text, opt)
|
return search.find(doc, line, col, text, opt)
|
||||||
end)
|
end)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["find-replace:find-regex"] = function()
|
|
||||||
find("Find Text Regex", function(doc, line, col, text)
|
|
||||||
local opt = { wrap = true, no_case = true, regex = true }
|
|
||||||
return search.find(doc, line, col, text, opt)
|
|
||||||
end)
|
|
||||||
end,
|
|
||||||
|
|
||||||
["find-replace:repeat-find"] = function()
|
|
||||||
if not last_fn then
|
|
||||||
core.error("No find to continue from")
|
|
||||||
else
|
|
||||||
local line, col = doc():get_selection()
|
|
||||||
local line1, col1, line2, col2 = last_fn(doc(), line, col, last_text)
|
|
||||||
if line1 then
|
|
||||||
push_previous_find(doc())
|
|
||||||
doc():set_selection(line2, col2, line1, col1)
|
|
||||||
core.active_view:scroll_to_line(line2, true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
["find-replace:previous-find"] = function()
|
|
||||||
local sel = table.remove(previous_finds)
|
|
||||||
if not sel or doc() ~= last_doc then
|
|
||||||
core.error("No previous finds")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
doc():set_selection(table.unpack(sel))
|
|
||||||
core.active_view:scroll_to_line(sel[3], true)
|
|
||||||
end,
|
|
||||||
|
|
||||||
["find-replace:replace"] = function()
|
["find-replace:replace"] = function()
|
||||||
replace("Text", "", function(text, old, new)
|
replace("Text", function(text, old, new)
|
||||||
return text:gsub(old:gsub("%W", "%%%1"), new:gsub("%%", "%%%%"), nil)
|
if plain then
|
||||||
end)
|
return text:gsub(old:gsub("%W", "%%%1"), new:gsub("%%", "%%%%"), nil)
|
||||||
end,
|
end
|
||||||
|
return regex.gsub(regex.compile(old), text, new)
|
||||||
["find-replace:replace-regex"] = function()
|
|
||||||
replace("Regex", "", function(text, old, new)
|
|
||||||
local re = regex.compile(old)
|
|
||||||
return regex.gsub(re, text, new)
|
|
||||||
end)
|
end)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
@ -170,3 +138,53 @@ command.add("core.docview", {
|
||||||
end)
|
end)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
local function valid_for_finding()
|
||||||
|
return core.active_view:is(DocView) or core.active_view:is(CommandView)
|
||||||
|
end
|
||||||
|
|
||||||
|
command.add(valid_for_finding, {
|
||||||
|
["find-replace:repeat-find"] = function()
|
||||||
|
if not last_fn then
|
||||||
|
core.error("No find to continue from")
|
||||||
|
else
|
||||||
|
local line, col = doc():get_selection()
|
||||||
|
local line1, col1, line2, col2 = last_fn(doc(), line, col, last_text, case_insensitive, plain)
|
||||||
|
if line1 then
|
||||||
|
if last_view.doc ~= doc() then
|
||||||
|
last_finds = {}
|
||||||
|
end
|
||||||
|
if #last_finds >= max_last_finds then
|
||||||
|
table.remove(last_finds, 1)
|
||||||
|
end
|
||||||
|
table.insert(last_finds, { line, col })
|
||||||
|
doc():set_selection(line2, col2, line1, col1)
|
||||||
|
last_view:scroll_to_line(line2, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
["find-replace:previous-find"] = function()
|
||||||
|
local sel = table.remove(last_finds)
|
||||||
|
if not sel or doc() ~= last_view.doc then
|
||||||
|
core.error("No previous finds")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
doc():set_selection(table.unpack(sel))
|
||||||
|
last_view:scroll_to_line(sel[3], true)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
command.add("core.commandview", {
|
||||||
|
["find-replace:toggle-insensitivity"] = function()
|
||||||
|
case_insensitive = not case_insensitive
|
||||||
|
core.status_view:show_tooltip(get_find_tooltip())
|
||||||
|
update_preview(last_sel, last_fn, last_text)
|
||||||
|
end,
|
||||||
|
|
||||||
|
["find-replace:toggle-plain"] = function()
|
||||||
|
plain = not plain
|
||||||
|
core.status_view:show_tooltip(get_find_tooltip())
|
||||||
|
update_preview(last_sel, last_fn, last_text)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
|
@ -137,6 +137,8 @@ keymap.add_direct {
|
||||||
["ctrl+r"] = "find-replace:replace",
|
["ctrl+r"] = "find-replace:replace",
|
||||||
["f3"] = "find-replace:repeat-find",
|
["f3"] = "find-replace:repeat-find",
|
||||||
["shift+f3"] = "find-replace:previous-find",
|
["shift+f3"] = "find-replace:previous-find",
|
||||||
|
["ctrl+i"] = "find-replace:toggle-insensitivity",
|
||||||
|
["ctrl+shift+i"] = "find-replace:toggle-plain",
|
||||||
["ctrl+g"] = "doc:go-to-line",
|
["ctrl+g"] = "doc:go-to-line",
|
||||||
["ctrl+s"] = "doc:save",
|
["ctrl+s"] = "doc:save",
|
||||||
["ctrl+shift+s"] = "doc:save-as",
|
["ctrl+shift+s"] = "doc:save-as",
|
||||||
|
|
Loading…
Reference in New Issue