generated from chrisgrieser/nvim-pseudometa-plugin-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
regex.lua
94 lines (81 loc) · 3.32 KB
/
regex.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
local M = {}
--------------------------------------------------------------------------------
---converts string into a lua pattern that matches letters ignoring casing https://stackoverflow.com/a/11402486
---@param pattern string
---@return string lua pattern
local function caseInsensitivePattern(pattern)
-- find an optional '%' (group 1) followed by any character (group 2)
local p = pattern:gsub("(%%?)(.)", function(percent, letter)
if percent ~= "" or not letter:match("%a") then
-- if the '%' matched, or `letter` is not a letter, return "as is"
return percent .. letter
else
-- else, return a case-insensitive character class of the matched letter
return string.format("[%s%s]", letter:lower(), letter:upper())
end
end)
return p
end
--------------------------------------------------------------------------------
---function performing a search and returning the *first* match
---@param str string
---@param toSearch string *pattern* to search for
---@param fromIdx integer perform find from this index
---@param flags string
---@param language string -- the regex flavor to use
---@nodiscard
---@return integer? **one-based** startPos of match, nil if no match
---@return integer? **one-based** endPos of match, nil if no match
function M.find(str, toSearch, fromIdx, flags, language)
local startPos, endPos
local plain = false
-- flags
-- NOTE g-flag irrelevant here, since function only needs to return one match
if flags:find("f") then
plain = true
elseif flags:find("i") then
toSearch = caseInsensitivePattern(toSearch)
end
if language == "lua" then
startPos, endPos = str:find(toSearch, fromIdx, plain)
end
return startPos, endPos
end
---function performing the actual string substitution
---@param inputLines string[]
---@param toSearch string *pattern* to search for
---@param toReplace string replacement value
---@param numOfRepls? integer how often a replacement should be performed. only needed for the calculation of highlights in the incremental preview where this value can be different from "all" and 1. If the value is nil, will determine the number of replacements from from the presence of the g-flag
---@param flags string NOTE g-flag is ignored when numOfRepls is not nil
---@param language string
---@nodiscard
---@return string[] output as array of lines
---@return integer total number of replacements made (for notification)
function M.replace(inputLines, toSearch, toReplace, numOfRepls, flags, language)
local outputLines = {}
local totalReplCount = 0
if not numOfRepls and not (flags:find("g")) then
numOfRepls = 1
elseif not numOfRepls and flags:find("g") then
numOfRepls = nil -- for :gsub, "nil" means "all"
end
-- flags
if flags:find("f") then
-- escape all lua magic chars -> effectively fixed strings
-- (since `:gsub` has no option for "plain" strings like `:find`)
toSearch = vim.pesc(toSearch)
toReplace = vim.pesc(toReplace)
elseif flags:find("i") then
toSearch = caseInsensitivePattern(toSearch)
end
if language == "lua" then
for _, line in pairs(inputLines) do
local newLine, numOfReplMade = line:gsub(toSearch, toReplace, numOfRepls)
totalReplCount = totalReplCount + numOfReplMade
table.insert(outputLines, newLine)
end
end
return outputLines, totalReplCount
end
--------------------------------------------------------------------------------
return M