|
|
@@ -1,76 +1,133 @@
|
|
|
-- Lua Mode for Lumacs
|
|
|
-- Extracted from init.lua
|
|
|
|
|
|
-define_major_mode("lua-mode", {
|
|
|
- file_patterns = {"%.lua$"},
|
|
|
- comment_syntax = "--",
|
|
|
+-- Define highlighting function locally so it can be used in setup
|
|
|
+local function highlight_lua()
|
|
|
+ local buf = editor.buffer
|
|
|
+ buf:clear_styles()
|
|
|
+
|
|
|
+ -- Keywords to highlight
|
|
|
+ local keywords = {
|
|
|
+ "function", "local", "end", "if", "then", "else", "elseif",
|
|
|
+ "for", "while", "do", "return", "break", "and", "or", "not",
|
|
|
+ "true", "false", "nil", "in", "repeat", "until"
|
|
|
+ }
|
|
|
|
|
|
- highlight = function()
|
|
|
- local buf = editor.buffer
|
|
|
- buf:clear_styles()
|
|
|
-
|
|
|
- -- Keywords to highlight
|
|
|
- local keywords = {
|
|
|
- "function", "local", "end", "if", "then", "else", "elseif",
|
|
|
- "for", "while", "do", "return", "break", "and", "or", "not",
|
|
|
- "true", "false", "nil", "in", "repeat", "until"
|
|
|
- }
|
|
|
-
|
|
|
- -- 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
|
|
|
- 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
|
|
|
+ -- Highlight each line
|
|
|
+ for line_num = 0, buf:line_count() - 1 do
|
|
|
+ local line_text = buf:line(line_num)
|
|
|
+ local len = #line_text
|
|
|
+ local pos = 1
|
|
|
+
|
|
|
+ -- Parse line to handle priority (Comments > Strings > Keywords)
|
|
|
+ while pos <= len do
|
|
|
+ -- Find nearest tokens
|
|
|
+ local comment_start = string.find(line_text, "--", pos, true)
|
|
|
+ local string_dq_start = string.find(line_text, '"', pos, true)
|
|
|
+ local string_sq_start = string.find(line_text, "'", pos, true)
|
|
|
+
|
|
|
+ -- Determine the first token
|
|
|
+ local mode = "code"
|
|
|
+ local token_start = len + 2 -- Sentinel
|
|
|
+
|
|
|
+ if comment_start and comment_start < token_start then
|
|
|
+ token_start = comment_start
|
|
|
+ mode = "comment"
|
|
|
+ end
|
|
|
+ if string_dq_start and string_dq_start < token_start then
|
|
|
+ token_start = string_dq_start
|
|
|
+ mode = "string_dq"
|
|
|
+ end
|
|
|
+ if string_sq_start and string_sq_start < token_start then
|
|
|
+ token_start = string_sq_start
|
|
|
+ mode = "string_sq"
|
|
|
end
|
|
|
|
|
|
- -- Highlight strings
|
|
|
- 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
|
|
|
+ -- 1. Process code/keywords BEFORE the token
|
|
|
+ local code_end = token_start - 1
|
|
|
+ if code_end >= pos then
|
|
|
+ local code_chunk = string.sub(line_text, pos, code_end)
|
|
|
+
|
|
|
+ for _, keyword in ipairs(keywords) do
|
|
|
+ local s = 1
|
|
|
+ while true do
|
|
|
+ -- Match whole words only
|
|
|
+ local p_start, p_end = string.find(code_chunk, "%f[%w]" .. keyword .. "%f[%W]", s)
|
|
|
+ if not p_start then break end
|
|
|
+
|
|
|
+ local abs_start = pos + p_start - 1
|
|
|
+ local abs_end = pos + p_end - 1
|
|
|
+
|
|
|
+ local range = lumacs.Range(
|
|
|
+ lumacs.Position(line_num, abs_start - 1),
|
|
|
+ lumacs.Position(line_num, abs_end)
|
|
|
+ )
|
|
|
+ buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.Keyword, 0))
|
|
|
+ s = p_end + 1
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
|
|
|
+ -- 2. Process the token
|
|
|
+ if mode == "comment" then
|
|
|
+ -- Comment goes to end of line
|
|
|
local range = lumacs.Range(
|
|
|
- lumacs.Position(line_num, quote_start - 1),
|
|
|
- lumacs.Position(line_num, quote_end)
|
|
|
+ lumacs.Position(line_num, token_start - 1),
|
|
|
+ lumacs.Position(line_num, len)
|
|
|
)
|
|
|
+ buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.Comment, 0))
|
|
|
+ break -- Done with this line
|
|
|
|
|
|
+ elseif mode == "string_dq" then
|
|
|
+ local _, s_end = string.find(line_text, '"', token_start + 1, true)
|
|
|
+ if not s_end then s_end = len end
|
|
|
+ local range = lumacs.Range(
|
|
|
+ lumacs.Position(line_num, token_start - 1),
|
|
|
+ lumacs.Position(line_num, s_end)
|
|
|
+ )
|
|
|
buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.String, 0))
|
|
|
- start_pos = quote_end + 1
|
|
|
- end
|
|
|
+ pos = s_end + 1
|
|
|
|
|
|
- -- Highlight comments
|
|
|
- local comment_pos = string.find(line_text, "--", 1, true)
|
|
|
- if comment_pos then
|
|
|
+ elseif mode == "string_sq" then
|
|
|
+ local _, s_end = string.find(line_text, "'", token_start + 1, true)
|
|
|
+ if not s_end then s_end = len end
|
|
|
local range = lumacs.Range(
|
|
|
- lumacs.Position(line_num, comment_pos - 1),
|
|
|
- lumacs.Position(line_num, #line_text)
|
|
|
+ lumacs.Position(line_num, token_start - 1),
|
|
|
+ lumacs.Position(line_num, s_end)
|
|
|
)
|
|
|
+ buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.String, 0))
|
|
|
+ pos = s_end + 1
|
|
|
|
|
|
- buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.Comment, 0))
|
|
|
+ else
|
|
|
+ -- No more tokens
|
|
|
+ pos = len + 1
|
|
|
end
|
|
|
end
|
|
|
- end,
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+define_major_mode("lua-mode", {
|
|
|
+ file_patterns = {"%.lua$"},
|
|
|
+ comment_syntax = "--",
|
|
|
+
|
|
|
+ highlight = highlight_lua,
|
|
|
|
|
|
setup = function()
|
|
|
editor:message("[lua-mode] Lua mode activated")
|
|
|
+
|
|
|
+ -- Register a hook to re-highlight on change
|
|
|
+ -- Note: This adds a listener every time the mode is setup.
|
|
|
+ -- Ideally, we'd track and remove it, but for now this ensures responsiveness.
|
|
|
+ editor.buffer:on_buffer_event(function(data)
|
|
|
+ if data.event == lumacs.BufferEvent.AfterChange then
|
|
|
+ -- Only run if we are still in lua-mode (simple check)
|
|
|
+ -- Using a protected call in case global state changes
|
|
|
+ local status, mode_name = pcall(current_major_mode)
|
|
|
+ if status and mode_name == "lua-mode" then
|
|
|
+ highlight_lua()
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end)
|
|
|
end,
|
|
|
|
|
|
cleanup = function()
|
|
|
@@ -78,6 +135,7 @@ define_major_mode("lua-mode", {
|
|
|
end,
|
|
|
|
|
|
keybindings = {
|
|
|
- -- Lua-specific keybindings can go here
|
|
|
+ -- Fix: Explicitly bind space since empty keybindings table might be causing issues
|
|
|
+ [" "] = function() editor:execute_command("self-insert-command", {" "}) end,
|
|
|
}
|
|
|
-})
|
|
|
+})
|