findreplace.lua 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. local core = require "core"
  2. local common = require "core.common"
  3. local command = require "core.command"
  4. local config = require "core.config"
  5. local search = require "core.doc.search"
  6. local DocView = require "core.docview"
  7. local max_previous_finds = 50
  8. local function doc()
  9. return core.active_view.doc
  10. end
  11. local previous_finds
  12. local last_doc
  13. local last_fn, last_text
  14. local function push_previous_find(doc, sel)
  15. if last_doc ~= doc then
  16. last_doc = doc
  17. previous_finds = {}
  18. end
  19. if #previous_finds >= max_previous_finds then
  20. table.remove(previous_finds, 1)
  21. end
  22. table.insert(previous_finds, sel or { doc:get_selection() })
  23. end
  24. local function find(label, search_fn)
  25. local dv = core.active_view
  26. local sel = { dv.doc:get_selection() }
  27. local text = dv.doc:get_text(table.unpack(sel))
  28. local found = false
  29. core.command_view:set_text(text)
  30. core.command_view.doc:set_selection(math.huge, math.huge, 1, 1)
  31. core.command_view:enter(label, function(text)
  32. if found then
  33. last_fn, last_text = search_fn, text
  34. previous_finds = {}
  35. push_previous_find(dv.doc, sel)
  36. else
  37. core.error("Couldn't find %q", text)
  38. dv.doc:set_selection(table.unpack(sel))
  39. end
  40. end, function(text)
  41. local ok, line1, col1, line2, col2 = pcall(search_fn, dv.doc, sel[1], sel[2], text)
  42. if text == "" then
  43. dv.doc:set_selection(table.unpack(sel))
  44. elseif ok and line1 then
  45. dv.doc:set_selection(line2, col2, line1, col1)
  46. dv:scroll_to_line(line2, true)
  47. found = true
  48. else
  49. found = false
  50. end
  51. end, function(explicit)
  52. if explicit then
  53. dv.doc:set_selection(table.unpack(sel))
  54. end
  55. end)
  56. end
  57. local function replace(pattern_escape)
  58. core.command_view:enter("Find To Replace", function(old)
  59. core.command_view:enter("Replace \"" .. old .. "\" With", function(new)
  60. local n = doc():replace(function(text)
  61. if pattern_escape then
  62. return text:gsub(old:gsub("%W", "%%%1"), new:gsub("%%", "%%%%"), nil)
  63. else
  64. return text:gsub(old, new)
  65. end
  66. end)
  67. core.log("Replaced %d instance(s) of %q with %q", n, old, new)
  68. end)
  69. end)
  70. end
  71. command.add("core.docview", {
  72. ["find-replace:find"] = function()
  73. find("Find Text", function(doc, line, col, text)
  74. local opt = { wrap = true, no_case = true }
  75. return search.find(doc, line, col, text, opt)
  76. end)
  77. end,
  78. ["find-replace:find-pattern"] = function()
  79. find("Find Text Pattern", function(doc, line, col, text)
  80. local opt = { wrap = true, no_case = true, pattern = true }
  81. return search.find(doc, line, col, text, opt)
  82. end)
  83. end,
  84. ["find-replace:repeat-find"] = function()
  85. if not last_fn then
  86. core.error("No find to continue from")
  87. else
  88. local line, col = doc():get_selection()
  89. local line1, col1, line2, col2 = last_fn(doc(), line, col, last_text)
  90. if line1 then
  91. push_previous_find(doc())
  92. doc():set_selection(line2, col2, line1, col1)
  93. core.active_view:scroll_to_line(line2, true)
  94. end
  95. end
  96. end,
  97. ["find-replace:previous-find"] = function()
  98. local sel = table.remove(previous_finds)
  99. if not sel or doc() ~= last_doc then
  100. core.error("No previous finds")
  101. return
  102. end
  103. doc():set_selection(table.unpack(sel))
  104. core.active_view:scroll_to_line(sel[3], true)
  105. end,
  106. ["find-replace:replace"] = function()
  107. replace(true)
  108. end,
  109. ["find-replace:replace-pattern"] = function()
  110. replace(false)
  111. end,
  112. })