-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfile_insert_content.lua
More file actions
122 lines (104 loc) · 3.67 KB
/
Copy pathfile_insert_content.lua
File metadata and controls
122 lines (104 loc) · 3.67 KB
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
-- MCP Tool: file_insert_content
-- Insert content at specific line number(s) in a file
-- Supports batch insertions with automatic offset calculation
-- Entry kind: function.lua
local json = require("json")
local projects = require("projects")
--- Split content into lines preserving structure
local function split_lines(content)
local lines = {}
local pos = 1
while pos <= #content do
local nl = string.find(content, "\n", pos, true)
if nl then
table.insert(lines, string.sub(content, pos, nl - 1))
pos = nl + 1
else
table.insert(lines, string.sub(content, pos))
pos = #content + 1
end
end
return lines
end
--- Split insertion content into lines
local function split_insert_content(content)
local lines = split_lines(content)
-- If content ends with \n, remove trailing empty
if #content > 0 and string.sub(content, -1) == "\n" and #lines > 0 and lines[#lines] == "" then
table.remove(lines)
end
return lines
end
local function call(arguments)
local vol, err = projects.resolve(arguments.project)
if err then
return "Error: " .. err
end
local path = arguments.path
if not path or path == "" then
return "Error: path is required"
end
local insertions = arguments.insertions
if not insertions or #insertions == 0 then
return "Error: insertions is required — must provide at least one insertion"
end
-- Read current content
local content, read_err = vol:readfile(path)
if read_err then
return "Error reading file: " .. tostring(read_err)
end
local lines = split_lines(content)
local has_trailing_newline = #content > 0 and string.sub(content, -1) == "\n"
local position = arguments.position or "after"
-- Validate insertions
for i, ins in ipairs(insertions) do
if not ins.line then
return string.format("Error: insertion #%d missing 'line' field", i)
end
if not ins.content then
return string.format("Error: insertion #%d missing 'content' field", i)
end
end
-- Sort insertions by line number descending
-- This ensures earlier insertions don't shift line numbers for later ones
local sorted = {}
for i, ins in ipairs(insertions) do
table.insert(sorted, {index = i, line = ins.line, content = ins.content})
end
table.sort(sorted, function(a, b) return a.line > b.line end)
local total_inserted = 0
for _, ins in ipairs(sorted) do
local line_num = ins.line
local new_lines = split_insert_content(ins.content)
local insert_at
if line_num == -1 then
-- End of file
insert_at = #lines + 1
elseif position == "before" then
insert_at = math.max(1, line_num)
else -- "after"
insert_at = math.min(#lines + 1, line_num + 1)
end
-- Insert lines in reverse order at the same position
for j = #new_lines, 1, -1 do
table.insert(lines, insert_at, new_lines[j])
end
total_inserted = total_inserted + #new_lines
end
-- Reassemble content
local new_content = table.concat(lines, "\n")
if has_trailing_newline then
new_content = new_content .. "\n"
end
local _, write_err = vol:writefile(path, new_content)
if write_err then
return "Error writing file: " .. tostring(write_err)
end
return string.format(
"Successfully inserted %d line%s at %d location%s in '%s'",
total_inserted, total_inserted == 1 and "" or "s",
#insertions, #insertions == 1 and "" or "s",
path
)
end
return { call = call }