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
95
96
97
98
99
100
101
|
local M = {}
---
-- Validate that `search_lines` matches exactly once in `buffer_lines`.
-- Returns the start index (1-based) and end index (inclusive) of the match,
-- or errors if there is not exactly one match.
local function find_exact_match(buffer_lines, search_lines)
local search_text = table.concat(search_lines, "\n")
local matches = {}
local search_len = #search_lines
for i = 1, #buffer_lines - search_len + 1 do
local candidate = table.concat(vim.list_slice(buffer_lines, i, i + search_len - 1), "\n")
if candidate == search_text then
table.insert(matches, { start = i, end_ = i + search_len - 1 })
end
end
if #matches == 0 then
error("search text not found in buffer")
elseif #matches > 1 then
error("search text matches multiple times")
end
return matches[1].start, matches[1].end_
end
---
-- Insert `lines` before the lines matched by `search_lines`.
-- Returns a new table of lines with the insertion applied.
-- Errors if `search_lines` does not match exactly once.
function M.insert_before(buffer_lines, search_lines, insert_lines)
local start, end_ = find_exact_match(buffer_lines, search_lines)
local result = {}
for i = 1, start - 1 do
table.insert(result, buffer_lines[i])
end
for _, line in ipairs(insert_lines) do
table.insert(result, line)
end
for i = start, #buffer_lines do
table.insert(result, buffer_lines[i])
end
return result
end
---
-- Append `lines` after the lines matched by `search_lines`.
-- Returns a new table of lines with the append applied.
-- Errors if `search_lines` does not match exactly once.
function M.append_after(buffer_lines, search_lines, append_lines)
local start, end_ = find_exact_match(buffer_lines, search_lines)
local result = {}
for i = 1, end_ do
table.insert(result, buffer_lines[i])
end
for _, line in ipairs(append_lines) do
table.insert(result, line)
end
for i = end_ + 1, #buffer_lines do
table.insert(result, buffer_lines[i])
end
return result
end
---
-- Replace the lines matched by `search_lines` with `replace_lines`.
-- Returns a new table of lines with the replacement applied.
-- Errors if `search_lines` does not match exactly once.
function M.replace(buffer_lines, search_lines, replace_lines)
local start, end_ = find_exact_match(buffer_lines, search_lines)
local result = {}
for i = 1, start - 1 do
table.insert(result, buffer_lines[i])
end
for _, line in ipairs(replace_lines) do
table.insert(result, line)
end
for i = end_ + 1, #buffer_lines do
table.insert(result, buffer_lines[i])
end
return result
end
return M
|