lua_mode.lua 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. -- Lua Mode for Lumacs
  2. -- Extracted from init.lua
  3. -- Define highlighting function locally so it can be used in setup
  4. local function highlight_lua()
  5. local buf = editor.buffer
  6. buf:clear_styles()
  7. -- Keywords to highlight
  8. local keywords = {
  9. "function", "local", "end", "if", "then", "else", "elseif",
  10. "for", "while", "do", "return", "break", "and", "or", "not",
  11. "true", "false", "nil", "in", "repeat", "until"
  12. }
  13. -- Highlight each line
  14. for line_num = 0, buf:line_count() - 1 do
  15. local line_text = buf:line(line_num)
  16. local len = #line_text
  17. local pos = 1
  18. -- Parse line to handle priority (Comments > Strings > Keywords)
  19. while pos <= len do
  20. -- Find nearest tokens
  21. local comment_start = string.find(line_text, "--", pos, true)
  22. local string_dq_start = string.find(line_text, '"', pos, true)
  23. local string_sq_start = string.find(line_text, "'", pos, true)
  24. -- Determine the first token
  25. local mode = "code"
  26. local token_start = len + 2 -- Sentinel
  27. if comment_start and comment_start < token_start then
  28. token_start = comment_start
  29. mode = "comment"
  30. end
  31. if string_dq_start and string_dq_start < token_start then
  32. token_start = string_dq_start
  33. mode = "string_dq"
  34. end
  35. if string_sq_start and string_sq_start < token_start then
  36. token_start = string_sq_start
  37. mode = "string_sq"
  38. end
  39. -- 1. Process code/keywords BEFORE the token
  40. local code_end = token_start - 1
  41. if code_end >= pos then
  42. local code_chunk = string.sub(line_text, pos, code_end)
  43. for _, keyword in ipairs(keywords) do
  44. local s = 1
  45. while true do
  46. -- Match whole words only
  47. local p_start, p_end = string.find(code_chunk, "%f[%w]" .. keyword .. "%f[%W]", s)
  48. if not p_start then break end
  49. local abs_start = pos + p_start - 1
  50. local abs_end = pos + p_end - 1
  51. local range = lumacs.Range(
  52. lumacs.Position(line_num, abs_start - 1),
  53. lumacs.Position(line_num, abs_end)
  54. )
  55. buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.Keyword, 0))
  56. s = p_end + 1
  57. end
  58. end
  59. end
  60. -- 2. Process the token
  61. if mode == "comment" then
  62. -- Comment goes to end of line
  63. local range = lumacs.Range(
  64. lumacs.Position(line_num, token_start - 1),
  65. lumacs.Position(line_num, len)
  66. )
  67. buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.Comment, 0))
  68. break -- Done with this line
  69. elseif mode == "string_dq" then
  70. local _, s_end = string.find(line_text, '"', token_start + 1, true)
  71. if not s_end then s_end = len end
  72. local range = lumacs.Range(
  73. lumacs.Position(line_num, token_start - 1),
  74. lumacs.Position(line_num, s_end)
  75. )
  76. buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.String, 0))
  77. pos = s_end + 1
  78. elseif mode == "string_sq" then
  79. local _, s_end = string.find(line_text, "'", token_start + 1, true)
  80. if not s_end then s_end = len end
  81. local range = lumacs.Range(
  82. lumacs.Position(line_num, token_start - 1),
  83. lumacs.Position(line_num, s_end)
  84. )
  85. buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.String, 0))
  86. pos = s_end + 1
  87. else
  88. -- No more tokens
  89. pos = len + 1
  90. end
  91. end
  92. end
  93. end
  94. define_major_mode("lua-mode", {
  95. file_patterns = {"%.lua$"},
  96. comment_syntax = "--",
  97. highlight = highlight_lua,
  98. setup = function()
  99. editor:message("[lua-mode] Lua mode activated")
  100. -- Register a hook to re-highlight on change
  101. -- Note: This adds a listener every time the mode is setup.
  102. -- Ideally, we'd track and remove it, but for now this ensures responsiveness.
  103. editor.buffer:on_buffer_event(function(data)
  104. if data.event == lumacs.BufferEvent.AfterChange then
  105. -- Only run if we are still in lua-mode (simple check)
  106. -- Using a protected call in case global state changes
  107. local status, mode_name = pcall(current_major_mode)
  108. if status and mode_name == "lua-mode" then
  109. highlight_lua()
  110. end
  111. end
  112. end)
  113. end,
  114. cleanup = function()
  115. editor:message("[lua-mode] Lua mode deactivated")
  116. end,
  117. keybindings = {
  118. -- Fix: Explicitly bind space since empty keybindings table might be causing issues
  119. [" "] = function() editor:execute_command("self-insert-command", {" "}) end,
  120. }
  121. })