init.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. -- Lumacs Configuration File
  2. -- This file is executed on startup and allows you to customize keybindings,
  3. -- create commands, and extend the editor with Lua.
  4. print("Loading init.lua...")
  5. -- Example: Custom keybindings
  6. -- Syntax: bind_key("key", function() ... end)
  7. -- Emacs-style navigation (Ctrl+N/P for next/previous line)
  8. bind_key("C-n", function()
  9. editor:move_down()
  10. message("Moved down")
  11. end)
  12. bind_key("C-p", function()
  13. editor:move_up()
  14. message("Moved up")
  15. end)
  16. bind_key("C-f", function()
  17. editor:move_right()
  18. end)
  19. bind_key("C-b", function()
  20. editor:move_left()
  21. end)
  22. -- Emacs-style line navigation
  23. bind_key("C-a", function()
  24. editor:move_to_line_start()
  25. end)
  26. bind_key("C-e", function()
  27. editor:move_to_line_end()
  28. end)
  29. -- Custom command: Save buffer
  30. bind_key("C-s", function()
  31. local buf = editor.buffer
  32. if buf:save() then
  33. message("Buffer saved: " .. buf:name())
  34. else
  35. message("Failed to save buffer")
  36. end
  37. end)
  38. -- Custom command: Insert timestamp
  39. bind_key("C-t", function()
  40. local cursor_pos = editor.cursor
  41. local timestamp = os.date("%Y-%m-%d %H:%M:%S")
  42. editor.buffer:insert(cursor_pos, timestamp)
  43. message("Inserted timestamp")
  44. end)
  45. -- Example: Helper functions you can define
  46. function goto_line(line_num)
  47. local pos = lumacs.Position(line_num - 1, 0)
  48. editor:set_cursor(pos)
  49. message("Jumped to line " .. line_num)
  50. end
  51. -- Example: Buffer inspection
  52. function buffer_info()
  53. local buf = editor.buffer
  54. local cursor = editor.cursor
  55. message(string.format(
  56. "Buffer: %s | Lines: %d | Cursor: %d,%d | Modified: %s",
  57. buf:name(),
  58. buf:line_count(),
  59. cursor.line + 1,
  60. cursor.column + 1,
  61. buf:is_modified() and "yes" or "no"
  62. ))
  63. end
  64. -- Bind to show buffer info
  65. bind_key("C-i", buffer_info)
  66. -- Search helper function
  67. function find_next(query)
  68. local buf = editor.buffer
  69. local cursor = editor.cursor
  70. -- Start searching AFTER the current cursor position to find the next occurrence
  71. -- Otherwise we might find the same one if we are sitting on it.
  72. -- A simple way is to advance column by 1 for the search start.
  73. local search_start = lumacs.Position(cursor.line, cursor.column + 1)
  74. -- If at end of line, search from start of next line is handled by find() implementation?
  75. -- Buffer::find currently implements simple linear search from a position.
  76. -- If column is beyond end, it should handle it. Let's trust the C++ impl or adjust.
  77. local res = buf:find(query, search_start)
  78. if res then
  79. editor.cursor = res.start
  80. message("Found '" .. query .. "' at " .. res.start.line .. ":" .. res.start.column)
  81. -- Optional: Highlight the found range?
  82. else
  83. message("'" .. query .. "' not found")
  84. end
  85. end
  86. -- Example binding: Find "TODO"
  87. bind_key("C-o", function() find_next("TODO") end)
  88. -- Line swapping functions (like Emacs M-up/down or VS Code Alt+arrows)
  89. function swap_line_up()
  90. local buf = editor.buffer
  91. local cursor = editor.cursor
  92. -- Can't move first line up
  93. if cursor.line == 0 then
  94. message("Already at first line")
  95. return
  96. end
  97. message("DEBUG: Starting swap_line_up, cursor at line " .. cursor.line)
  98. -- Get the current line and above line text
  99. local current_line = buf:line(cursor.line)
  100. local above_line = buf:line(cursor.line - 1)
  101. -- Strategy: Replace both lines with them swapped
  102. -- Delete from start of line above to end of current line (not including next line)
  103. local delete_start = lumacs.Position(cursor.line - 1, 0)
  104. local delete_end = lumacs.Position(cursor.line, string.len(current_line))
  105. local range = lumacs.Range(delete_start, delete_end)
  106. buf:erase(range)
  107. -- Insert them back in swapped order
  108. -- Add extra newline if above_line is empty to preserve it
  109. local insert_pos = lumacs.Position(cursor.line - 1, 0)
  110. local text = current_line .. "\n" .. above_line
  111. if above_line == "" then
  112. text = text .. "\n"
  113. end
  114. buf:insert(insert_pos, text)
  115. -- Move cursor up to follow the line
  116. editor.cursor = lumacs.Position(cursor.line - 1, cursor.column)
  117. message("Swapped line up")
  118. end
  119. function swap_line_down()
  120. local buf = editor.buffer
  121. local cursor = editor.cursor
  122. -- Can't move last line down
  123. if cursor.line >= buf:line_count() - 1 then
  124. message("Already at last line")
  125. return
  126. end
  127. -- Get the current line and the line below
  128. local current_line = buf:line(cursor.line)
  129. local below_line = buf:line(cursor.line + 1)
  130. -- Strategy: Replace both lines with them swapped
  131. -- Delete from start of current line to end of line below (not including line after)
  132. local delete_start = lumacs.Position(cursor.line, 0)
  133. local delete_end = lumacs.Position(cursor.line + 1, string.len(below_line))
  134. local range = lumacs.Range(delete_start, delete_end)
  135. buf:erase(range)
  136. -- Insert them back in swapped order
  137. -- Add extra newline if current_line is empty to preserve it
  138. local insert_pos = lumacs.Position(cursor.line, 0)
  139. local text = below_line .. "\n" .. current_line
  140. if current_line == "" then
  141. text = text .. "\n"
  142. end
  143. buf:insert(insert_pos, text)
  144. -- Move cursor down to follow the line
  145. editor.cursor = lumacs.Position(cursor.line + 1, cursor.column)
  146. message("Swapped line down")
  147. end
  148. -- Bind to M-ArrowUp and M-ArrowDown (Meta/Alt + arrows)
  149. bind_key("M-ArrowUp", swap_line_up)
  150. bind_key("M-ArrowDown", swap_line_down)
  151. -- Window Management Bindings
  152. bind_key("C-w", function()
  153. editor:next_window()
  154. -- message("Switched window")
  155. end)
  156. -- Split horizontal (like Emacs C-x 2, simplified to M-2)
  157. bind_key("M-2", function()
  158. editor:split_horizontally()
  159. message("Split horizontally")
  160. end)
  161. -- Split vertical (like Emacs C-x 3, simplified to M-3)
  162. bind_key("M-3", function()
  163. editor:split_vertically()
  164. message("Split vertically")
  165. end)
  166. -- Close window (like Emacs C-x 0, simplified to M-0)
  167. bind_key("M-0", function()
  168. editor:close_window()
  169. message("Closed window")
  170. end)
  171. -- Command Mode (Minibuffer)
  172. bind_key("M-x", function()
  173. editor:command_mode()
  174. end)
  175. -- Undo/Redo
  176. bind_key("C-z", function()
  177. if editor:undo() then
  178. message("Undid change")
  179. else
  180. message("Nothing to undo")
  181. end
  182. end)
  183. bind_key("C-y", function()
  184. if editor:redo() then
  185. message("Redid change")
  186. else
  187. message("Nothing to redo")
  188. end
  189. end)
  190. -- Simple syntax highlighter for demonstration
  191. function highlight_buffer()
  192. local buf = editor.buffer
  193. buf:clear_styles() -- Clear existing styles
  194. -- Keywords to highlight
  195. local keywords = {
  196. "function", "local", "end", "if", "then", "else", "elseif",
  197. "for", "while", "do", "return", "break", "and", "or", "not"
  198. }
  199. -- Highlight each line
  200. for line_num = 0, buf:line_count() - 1 do
  201. local line_text = buf:line(line_num)
  202. -- Highlight keywords
  203. for _, keyword in ipairs(keywords) do
  204. local start_pos = 1
  205. while true do
  206. -- Find keyword with word boundaries
  207. local pattern = "%f[%w]" .. keyword .. "%f[%W]"
  208. local pos = string.find(line_text, pattern, start_pos)
  209. if not pos then break end
  210. local range = lumacs.Range(
  211. lumacs.Position(line_num, pos - 1),
  212. lumacs.Position(line_num, pos + #keyword - 1)
  213. )
  214. buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.Keyword, 0))
  215. start_pos = pos + #keyword
  216. end
  217. end
  218. -- Highlight strings (simple version - just finds quoted text)
  219. local start_pos = 1
  220. while true do
  221. local quote_start = string.find(line_text, '"', start_pos, true)
  222. if not quote_start then break end
  223. local quote_end = string.find(line_text, '"', quote_start + 1, true)
  224. if not quote_end then break end
  225. local range = lumacs.Range(
  226. lumacs.Position(line_num, quote_start - 1),
  227. lumacs.Position(line_num, quote_end)
  228. )
  229. buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.String, 0))
  230. start_pos = quote_end + 1
  231. end
  232. -- Highlight comments
  233. local comment_pos = string.find(line_text, "%-%-", 1, true)
  234. if comment_pos then
  235. local range = lumacs.Range(
  236. lumacs.Position(line_num, comment_pos - 1),
  237. lumacs.Position(line_num, #line_text)
  238. )
  239. buf:set_style(range, lumacs.TextAttribute(lumacs.ColorType.Comment, 0))
  240. end
  241. end
  242. end
  243. -- Auto-highlighting using events!
  244. -- Register event handler to automatically highlight when buffer loads or changes
  245. editor.buffer:on_buffer_event(function(event_data)
  246. local buf = editor.buffer
  247. -- Auto-highlight on these events
  248. if event_data.event == lumacs.BufferEvent.Loaded or
  249. event_data.event == lumacs.BufferEvent.LanguageChanged then
  250. -- Only highlight Lua files automatically
  251. if buf.language == "lua" then
  252. highlight_buffer()
  253. print(string.format("[Auto-highlight] Applied to %s buffer", buf.language))
  254. end
  255. end
  256. end)
  257. -- Manual highlight key (original C-l for syntax highlighting)
  258. bind_key("C-l", function()
  259. highlight_buffer()
  260. -- Debug: Count applied styles
  261. local buf = editor.buffer
  262. local styles_count = 0
  263. for line = 0, buf:line_count() - 1 do
  264. local styles = buf:get_line_styles(line)
  265. styles_count = styles_count + #styles
  266. end
  267. message(string.format("Highlighted! Applied %d styled ranges", styles_count))
  268. end)
  269. -- Test Escape key binding
  270. bind_key("Escape", function()
  271. message("Escape pressed! (Direct binding works)")
  272. end)
  273. -- C-x sequence bindings (Emacs style)
  274. bind_key("C-x o", function()
  275. editor:next_window()
  276. message("Switched window with C-x o")
  277. end)
  278. bind_key("C-x 2", function()
  279. editor:split_horizontally()
  280. message("Split horizontally with C-x 2")
  281. end)
  282. bind_key("C-x 3", function()
  283. editor:split_vertically()
  284. message("Split vertically with C-x 3")
  285. end)
  286. bind_key("C-x 0", function()
  287. editor:close_window()
  288. message("Closed window with C-x 0")
  289. end)
  290. -- Test control keys (ncurses versions)
  291. bind_key("C-k", function()
  292. message("C-k pressed! (Control key working with ncurses)")
  293. end)
  294. bind_key("C-s", function()
  295. local buf = editor.buffer
  296. if buf:save() then
  297. message("Buffer saved with C-s (ncurses)!")
  298. else
  299. message("Failed to save buffer")
  300. end
  301. end)
  302. -- Welcome message for ncurses version
  303. message("Lumacs (ncurses) ready! C-l=highlight, C-k=test, C-s=save, M-arrows=swap, C-x sequences, Esc=test")