From c0c6bc5be9d412d34d263d6371384b3b3722c9fb Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Tue, 4 May 2021 18:31:46 -0400 Subject: [PATCH] Replaced pattern-based commands with regexes. --- data/core/commands/findreplace.lua | 14 +++++++----- data/core/doc/search.lua | 36 ++++++++++++++++++------------ data/core/regex.lua | 5 +++-- data/plugins/projectsearch.lua | 9 +++++--- src/api/regex.c | 12 +++++----- 5 files changed, 46 insertions(+), 30 deletions(-) diff --git a/data/core/commands/findreplace.lua b/data/core/commands/findreplace.lua index 937c410a..af60f33f 100644 --- a/data/core/commands/findreplace.lua +++ b/data/core/commands/findreplace.lua @@ -90,6 +90,7 @@ local function has_selection() and core.active_view.doc:has_selection() end + command.add(has_selection, { ["find-replace:select-next"] = function() local l1, c1, l2, c2 = doc():get_selection(true) @@ -107,9 +108,9 @@ command.add("core.docview", { end) end, - ["find-replace:find-pattern"] = function() - find("Find Text Pattern", function(doc, line, col, text) - local opt = { wrap = true, no_case = true, pattern = true } + ["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, @@ -144,9 +145,10 @@ command.add("core.docview", { end) end, - ["find-replace:replace-pattern"] = function() - replace("Pattern", "", function(text, old, new) - return text:gsub(old, 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, diff --git a/data/core/doc/search.lua b/data/core/doc/search.lua index fe57523e..3fc19c70 100644 --- a/data/core/doc/search.lua +++ b/data/core/doc/search.lua @@ -15,12 +15,8 @@ local function init_args(doc, line, col, text, opt) opt = opt or default_opt line, col = doc:sanitize_position(line, col) - if opt.no_case then - if opt.pattern then - text = text:gsub("%%?.", pattern_lower) - else - text = text:lower() - end + if opt.no_case and not opt.regex then + text = text:lower() end return doc, line, col, text, opt @@ -30,20 +26,32 @@ end function search.find(doc, line, col, text, opt) doc, line, col, text, opt = init_args(doc, line, col, text, opt) + local re + if opt.regex then + re = regex.compile(text, opt.no_case and "i" or "") + end for line = line, #doc.lines do local line_text = doc.lines[line] - if opt.no_case then - line_text = line_text:lower() + if opt.regex then + local s, e = re:match(line_text, col, true) + if s then + return line, s, line, e + 1 + end + col = 1 + else + if opt.no_case then + line_text = line_text:lower() + end + local s, e = line_text:find(text, col, true) + if s then + return line, s, line, e + 1 + end + col = 1 end - local s, e = line_text:find(text, col, not opt.pattern) - if s then - return line, s, line, e + 1 - end - col = 1 end if opt.wrap then - opt = { no_case = opt.no_case, pattern = opt.pattern } + opt = { no_case = opt.no_case, regex = opt.regex } return search.find(doc, 1, 1, text, opt) end end diff --git a/data/core/regex.lua b/data/core/regex.lua index 7704c14e..3b343238 100644 --- a/data/core/regex.lua +++ b/data/core/regex.lua @@ -38,10 +38,11 @@ end regex.gsub = function(pattern_string, string, replacement) local pattern = type(pattern_string) == "table" and pattern_string or regex.compile(pattern_string) - local result, str, indices = "", string + local result, str, indices, n = "", string repeat indices = { regex.cmatch(pattern, str) } if #indices > 0 then + n = n + 1 local currentReplacement = replacement if #indices > 2 then for i = 1, (#indices/2 - 1) do @@ -62,6 +63,6 @@ regex.gsub = function(pattern_string, string, replacement) str = str:sub(indices[2]) end until #indices == 0 or indices[1] == indices[2] - return result .. str + return result .. str, n end diff --git a/data/plugins/projectsearch.lua b/data/plugins/projectsearch.lua index 4c1fca6d..e4d10fb3 100644 --- a/data/plugins/projectsearch.lua +++ b/data/plugins/projectsearch.lua @@ -229,9 +229,12 @@ command.add(nil, { end) end, - ["project-search:find-pattern"] = function() - core.command_view:enter("Find Pattern In Project", function(text) - begin_search(text, function(line_text) return line_text:find(text) end) + ["project-search:find-regex"] = function() + core.command_view:enter("Find Regex In Project", function(text) + local re = regex.compile(text, "i") + begin_search(text, function(line_text) + return regex.cmatch(re, line_text) + end) end) end, diff --git a/src/api/regex.c b/src/api/regex.c index ba3dddac..05df8eee 100644 --- a/src/api/regex.c +++ b/src/api/regex.c @@ -53,13 +53,15 @@ static int f_pcre_compile(lua_State *L) { // Takes string, compiled regex, returns list of indices of matched groups // (including the whole match), if a match was found. static int f_pcre_match(lua_State *L) { - size_t len; - const char* str = luaL_checklstring(L, -1, &len); - luaL_checktype(L, -2, LUA_TTABLE); - lua_rawgeti(L, -2, 1); + size_t len, offset = 0; + luaL_checktype(L, 1, LUA_TTABLE); + const char* str = luaL_checklstring(L, 2, &len); + if (lua_gettop(L) > 2) + offset = luaL_checknumber(L, 3); + lua_rawgeti(L, 1, 1); pcre2_code* re = (pcre2_code*)lua_touserdata(L, -1); pcre2_match_data* md = pcre2_match_data_create_from_pattern(re, NULL); - int rc = pcre2_match(re, (PCRE2_SPTR)str, len, 0, 0, md, NULL); + int rc = pcre2_match(re, (PCRE2_SPTR)str, len, offset, 0, md, NULL); if (rc < 0) { pcre2_match_data_free(md); if (rc != PCRE2_ERROR_NOMATCH)