| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| local IDE = {} |
| IDE.__index = IDE |
|
|
| function IDE.new() |
| local self = setmetatable({}, IDE) |
| self.vfs = {} |
| self.buffers = {} |
| self.diagnostics = {} |
| self.symbols = {} |
| self.active_file = nil |
| return self |
| end |
|
|
| |
|
|
| function IDE:open_file(filepath, content) |
| self.vfs[filepath] = content or "" |
| local lines = {} |
| for line in string.gmatch(content .. "\n", "(.-)\r?\n") do |
| table.insert(lines, line) |
| end |
| self.buffers[filepath] = lines |
| self.active_file = filepath |
| self:analyze_buffer(filepath) |
| return #lines |
| end |
|
|
| function IDE:get_buffer(filepath) |
| local target = filepath or self.active_file |
| return self.buffers[target] or {} |
| end |
|
|
| function IDE:get_text(filepath) |
| local lines = self:get_buffer(filepath) |
| return table.concat(lines, "\n") |
| end |
|
|
| function IDE:edit_line(filepath, line_no, new_text) |
| local target = filepath or self.active_file |
| if self.buffers[target] and line_no >= 1 and line_no <= #self.buffers[target] then |
| self.buffers[target][line_no] = new_text |
| self:analyze_buffer(target) |
| return true |
| end |
| return false |
| end |
|
|
| function IDE:insert_line(filepath, line_no, new_text) |
| local target = filepath or self.active_file |
| if not self.buffers[target] then self.buffers[target] = {} end |
| table.insert(self.buffers[target], line_no, new_text) |
| self:analyze_buffer(target) |
| return #self.buffers[target] |
| end |
|
|
| function IDE:delete_line(filepath, line_no) |
| local target = filepath or self.active_file |
| if self.buffers[target] and line_no >= 1 and line_no <= #self.buffers[target] then |
| table.remove(self.buffers[target], line_no) |
| self:analyze_buffer(target) |
| return true |
| end |
| return false |
| end |
|
|
| |
|
|
| function IDE:analyze_buffer(filepath) |
| local lines = self:get_buffer(filepath) |
| local diags = {} |
| local syms = {} |
|
|
| for i, line in ipairs(lines) do |
| |
| local fn_name = string.match(line, "^%s*def%s+([a-zA-Z0-9_]+)%s*%(") |
| if fn_name then |
| table.insert(syms, {name = fn_name, kind = "function", line = i}) |
| end |
|
|
| |
| local cls_name = string.match(line, "^%s*class%s+([a-zA-Z0-9_]+)") |
| if cls_name then |
| table.insert(syms, {name = cls_name, kind = "class", line = i}) |
| end |
|
|
| |
| if string.match(line, "%s+$") then |
| table.insert(diags, {line = i, col = #line, msg = "Trailing whitespace detected", severity = "info"}) |
| end |
|
|
| |
| if string.match(line, "^%s*\t") and string.match(line, "^%s* ") then |
| table.insert(diags, {line = i, col = 1, msg = "Mixed tabs and spaces in indentation", severity = "warning"}) |
| end |
|
|
| |
| local _, q_single = string.gsub(line, "'", "") |
| local _, q_double = string.gsub(line, '"', "") |
| if (q_single % 2 ~= 0) and not string.match(line, '["\']') then |
| table.insert(diags, {line = i, col = 1, msg = "Unbalanced quotes detected", severity = "error"}) |
| end |
| end |
|
|
| self.diagnostics[filepath] = diags |
| self.symbols[filepath] = syms |
| return #diags |
| end |
|
|
| |
|
|
| function IDE:generate_diff(filepath) |
| local orig_text = self.vfs[filepath] or "" |
| local curr_lines = self.buffers[filepath] or {} |
|
|
| local orig_lines = {} |
| for line in string.gmatch(orig_text .. "\n", "(.-)\r?\n") do |
| table.insert(orig_lines, line) |
| end |
|
|
| local clean_path = string.gsub(filepath, "^/+", "") |
| local header = string.format("diff --git a/%s b/%s\n--- a/%s\n+++ b/%s\n", clean_path, clean_path, clean_path, clean_path) |
|
|
| local diff_lines = {} |
| local start_orig = 1 |
| local count_orig = #orig_lines |
| local count_curr = #curr_lines |
|
|
| |
| table.insert(diff_lines, string.format("@@ -%d,%d +%d,%d @@", start_orig, math.max(1, count_orig), start_orig, math.max(1, count_curr))) |
| for _, line in ipairs(orig_lines) do |
| table.insert(diff_lines, "-" .. line) |
| end |
| for _, line in ipairs(curr_lines) do |
| table.insert(diff_lines, "+" .. line) |
| end |
|
|
| local full_diff = header .. table.concat(diff_lines, "\n") .. "\n" |
| return full_diff |
| end |
|
|
| |
|
|
| function IDE:get_summary() |
| local total_files = 0 |
| for _ in pairs(self.vfs) do total_files = total_files + 1 end |
| return { |
| total_open_files = total_files, |
| active_file = self.active_file or "none", |
| active_line_count = self.active_file and #self.buffers[self.active_file] or 0 |
| } |
| end |
|
|
| return IDE |
|
|