| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- -- 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")
|