-- Lumacs Configuration File -- This file is executed on startup and allows you to customize keybindings, -- create commands, and extend the editor with Lua. print("Loading init.lua...") -- Example: Custom keybindings -- Syntax: bind_key("key", function() ... end) -- Emacs-style navigation (Ctrl+N/P for next/previous line) bind_key("C-n", function() editor:move_down() message("Moved down") end) bind_key("C-p", function() editor:move_up() message("Moved up") end) bind_key("C-f", function() editor:move_right() end) bind_key("C-b", function() editor:move_left() end) -- Emacs-style line navigation bind_key("C-a", function() editor:move_to_line_start() end) bind_key("C-e", function() editor:move_to_line_end() end) -- Custom command: Save buffer bind_key("C-s", function() local buf = editor.buffer if buf:save() then message("Buffer saved: " .. buf:name()) else message("Failed to save buffer") end end) -- Custom command: Insert timestamp bind_key("C-t", function() local cursor_pos = editor.cursor local timestamp = os.date("%Y-%m-%d %H:%M:%S") editor.buffer:insert(cursor_pos, timestamp) message("Inserted timestamp") end) -- Example: Helper functions you can define function goto_line(line_num) local pos = lumacs.Position(line_num - 1, 0) editor:set_cursor(pos) message("Jumped to line " .. line_num) end -- Example: Buffer inspection function buffer_info() local buf = editor.buffer local cursor = editor.cursor message(string.format( "Buffer: %s | Lines: %d | Cursor: %d,%d | Modified: %s", buf:name(), buf:line_count(), cursor.line + 1, cursor.column + 1, buf:is_modified() and "yes" or "no" )) end -- Bind to show buffer info bind_key("C-i", buffer_info) -- Search helper function function find_next(query) local buf = editor.buffer local cursor = editor.cursor -- Start searching AFTER the current cursor position to find the next occurrence -- Otherwise we might find the same one if we are sitting on it. -- A simple way is to advance column by 1 for the search start. local search_start = lumacs.Position(cursor.line, cursor.column + 1) -- If at end of line, search from start of next line is handled by find() implementation? -- Buffer::find currently implements simple linear search from a position. -- If column is beyond end, it should handle it. Let's trust the C++ impl or adjust. local res = buf:find(query, search_start) if res then editor.cursor = res.start message("Found '" .. query .. "' at " .. res.start.line .. ":" .. res.start.column) -- Optional: Highlight the found range? else message("'" .. query .. "' not found") end end -- Example binding: Find "TODO" bind_key("C-o", function() find_next("TODO") end) -- Line swapping functions (like Emacs M-up/down or VS Code Alt+arrows) function swap_line_up() local buf = editor.buffer local cursor = editor.cursor -- Can't move first line up if cursor.line == 0 then message("Already at first line") return end message("DEBUG: Starting swap_line_up, cursor at line " .. cursor.line) -- Get the current line and above line text local current_line = buf:line(cursor.line) local above_line = buf:line(cursor.line - 1) -- Strategy: Replace both lines with them swapped -- Delete from start of line above to end of current line (not including next line) local delete_start = lumacs.Position(cursor.line - 1, 0) local delete_end = lumacs.Position(cursor.line, string.len(current_line)) local range = lumacs.Range(delete_start, delete_end) buf:erase(range) -- Insert them back in swapped order -- Add extra newline if above_line is empty to preserve it local insert_pos = lumacs.Position(cursor.line - 1, 0) local text = current_line .. "\n" .. above_line if above_line == "" then text = text .. "\n" end buf:insert(insert_pos, text) -- Move cursor up to follow the line editor.cursor = lumacs.Position(cursor.line - 1, cursor.column) message("Swapped line up") end function swap_line_down() local buf = editor.buffer local cursor = editor.cursor -- Can't move last line down if cursor.line >= buf:line_count() - 1 then message("Already at last line") return end -- Get the current line and the line below local current_line = buf:line(cursor.line) local below_line = buf:line(cursor.line + 1) -- Strategy: Replace both lines with them swapped -- Delete from start of current line to end of line below (not including line after) local delete_start = lumacs.Position(cursor.line, 0) local delete_end = lumacs.Position(cursor.line + 1, string.len(below_line)) local range = lumacs.Range(delete_start, delete_end) buf:erase(range) -- Insert them back in swapped order -- Add extra newline if current_line is empty to preserve it local insert_pos = lumacs.Position(cursor.line, 0) local text = below_line .. "\n" .. current_line if current_line == "" then text = text .. "\n" end buf:insert(insert_pos, text) -- Move cursor down to follow the line editor.cursor = lumacs.Position(cursor.line + 1, cursor.column) message("Swapped line down") end -- Bind to M-ArrowUp and M-ArrowDown (Meta/Alt + arrows) bind_key("M-ArrowUp", swap_line_up) bind_key("M-ArrowDown", swap_line_down) -- Window Management Bindings bind_key("C-w", function() editor:next_window() -- message("Switched window") end) -- Split horizontal (like Emacs C-x 2, simplified to M-2) bind_key("M-2", function() editor:split_horizontally() message("Split horizontally") end) -- Split vertical (like Emacs C-x 3, simplified to M-3) bind_key("M-3", function() editor:split_vertically() message("Split vertically") end) -- Close window (like Emacs C-x 0, simplified to M-0) bind_key("M-0", function() editor:close_window() message("Closed window") end) -- Command Mode (Minibuffer) bind_key("M-x", function() editor:command_mode() end) -- Undo/Redo bind_key("C-z", function() if editor:undo() then message("Undid change") else message("Nothing to undo") end end) bind_key("C-y", function() if editor:redo() then message("Redid change") else message("Nothing to redo") end end) -- Simple syntax highlighter for demonstration function highlight_buffer() local buf = editor.buffer buf:clear_styles() -- Clear existing styles -- Keywords to highlight local keywords = { "function", "local", "end", "if", "then", "else", "elseif", "for", "while", "do", "return", "break", "and", "or", "not" } -- Highlight each line for line_num = 0, buf:line_count() - 1 do local line_text = buf:line(line_num) -- Highlight keywords for _, keyword in ipairs(keywords) do local start_pos = 1 while true do -- Find keyword with word boundaries local pattern = "%f[%w]" .. keyword .. "%f[%W]" local pos = string.find(line_text, pattern, start_pos) if not pos then break end local range = lumacs.Range( lumacs.Position(line_num, pos - 1), lumacs.Position(line_num, pos + #keyword - 1) ) buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.Keyword, 0)) start_pos = pos + #keyword end end -- Highlight strings (simple version - just finds quoted text) local start_pos = 1 while true do local quote_start = string.find(line_text, '"', start_pos, true) if not quote_start then break end local quote_end = string.find(line_text, '"', quote_start + 1, true) if not quote_end then break end local range = lumacs.Range( lumacs.Position(line_num, quote_start - 1), lumacs.Position(line_num, quote_end) ) buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.String, 0)) start_pos = quote_end + 1 end -- Highlight comments local comment_pos = string.find(line_text, "%-%-", 1, true) if comment_pos then local range = lumacs.Range( lumacs.Position(line_num, comment_pos - 1), lumacs.Position(line_num, #line_text) ) buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.Comment, 0)) end end end -- Auto-highlighting using events! -- Register event handler to automatically highlight when buffer loads or changes editor.buffer:on_buffer_event(function(event_data) local buf = editor.buffer -- Auto-highlight on these events if event_data.event == lumacs.BufferEvent.Loaded or event_data.event == lumacs.BufferEvent.LanguageChanged then -- Only highlight Lua files automatically if buf.language == "lua" then highlight_buffer() print(string.format("[Auto-highlight] Applied to %s buffer", buf.language)) end end end) -- Manual highlight key (C-l) for any language bind_key("C-l", function() highlight_buffer() -- Debug: Count applied styles local buf = editor.buffer local styles_count = 0 for line = 0, buf:line_count() - 1 do local styles = buf:get_line_styles(line) styles_count = styles_count + #styles end message(string.format("Highlighted! Applied %d styled ranges", styles_count)) end) -- Welcome message message("Lumacs ready! C-s=save, C-l=highlight, M-arrows=swap lines, C-i=info, Esc/Q=quit")