aboutsummaryrefslogtreecommitdiff
path: root/modules/lua/init.lua
diff options
context:
space:
mode:
Diffstat (limited to 'modules/lua/init.lua')
-rw-r--r--modules/lua/init.lua193
1 files changed, 180 insertions, 13 deletions
diff --git a/modules/lua/init.lua b/modules/lua/init.lua
index eb633a95..5ec8d005 100644
--- a/modules/lua/init.lua
+++ b/modules/lua/init.lua
@@ -3,28 +3,195 @@
---
-- The lua module.
-- It provides utilities for editing Lua code.
+-- User tags are loaded from _USERHOME/modules/lua/tags and user apis are loaded
+-- from _USERHOME/modules/lua/api.
module('_m.lua', package.seeall)
-if type(_G.snippets) == 'table' then
+-- Markdown:
+-- ## Key Commands
+--
+-- + `Alt+L, M`: Open this module for editing.
+-- + `Alt+L, G`: Goto file being 'require'd on the current line.
+-- + `Shift+Return`: Try to autocomplete an `if`, `for`, etc. statement with
+-- `end`.
+-- + `.`: When to the right of a known symbol, show an autocompletion list of
+-- fields and functions.
+-- + `:`: When to the right of a known symbol, show an autocompletion list of
+-- functions only.
+-- + `Ctrl+I`: (Windows and Linux) Autocomplete symbol.
+-- + `~`: (Mac OSX) Autocomplete symbol.
+-- + `Ctrl+H`: Show documentation for the selected symbol or the symbol under
+-- the caret.
+--
+-- ## Fields
+--
+-- * `sense`: The Lua [Adeptsense](_m.textadept.adeptsense.html).
+
+local m_editing, m_run = _m.textadept.editing, _m.textadept.run
+-- Comment string tables use lexer names.
+m_editing.comment_string.lua = '--'
+-- Compile and Run command tables use file extensions.
+m_run.run_command.lua = 'lua %(filename)'
+m_run.error_detail.lua = {
+ pattern = '^lua: (.-):(%d+): (.+)$',
+ filename = 1, line = 2, message = 3
+}
+
---
--- Container for Lua-specific snippets.
--- @class table
--- @name snippets.lua
- _G.snippets.lua = {}
+-- Sets default buffer properties for Lua files.
+function set_buffer_properties()
+
end
-if type(_G.keys) == 'table' then
+-- Adeptsense.
+
+sense = _m.textadept.adeptsense.new('lua')
+sense.syntax.class_definition = 'module%s*%(?%s*[\'"]([%w_%.]+)'
+sense.syntax.symbol_chars = '[%w_%.:]'
+sense.syntax.type_declarations = {}
+sense.syntax.type_assignments = {
+ ['^[\'"]'] = 'string', -- foo = 'bar' or foo = "bar"
+ ['^([%w_%.]+)%s*$'] = '%1', -- foo = _m.textadept.adeptsense
+ ['^(_m%.textadept%.adeptsense)%.new'] = '%1'
+}
+sense.api_files = { _HOME..'/modules/lua/api' }
+sense:add_trigger('.')
+sense:add_trigger(':', false, true)
+
+-- script/update_doc generates a fake set of ctags used for autocompletion.
+sense.ctags_kinds = {
+ f = 'functions',
+ F = 'fields',
+ m = 'classes',
+ t = 'fields',
+}
+sense:load_ctags(_HOME..'/modules/lua/tags', true)
+
---
--- Container for Lua-specific key commands.
+-- Shows an autocompletion list for the symbol behind the caret.
+-- If the symbol contains a ':', only display functions. Otherwise, display
+-- both functions and fields.
+function sense:complete(only_fields, only_functions)
+ local line, pos = buffer:get_cur_line()
+ local symbol = line:sub(1, pos):match(self.syntax.symbol_chars..'*$')
+ return self.super.complete(self, false, symbol:find(':'))
+end
+
+-- Load user tags and apidoc.
+if lfs.attributes(_USERHOME..'/modules/lua/tags') then
+ sense:load_ctags(_USERHOME..'/modules/lua/tags')
+end
+if lfs.attributes(_USERHOME..'/modules/lua/api') then
+ sense.api_files[#sense.api_files + 1] = _USERHOME..'/modules/lua/api'
+end
+
+-- Commands.
+
+---
+-- Patterns for auto 'end' completion for control structures.
-- @class table
--- @name keys.lua
- _G.keys.lua = {}
+-- @name control_structure_patterns
+-- @see try_to_autocomplete_end
+local control_structure_patterns = {
+ '^%s*for', '^%s*function', '^%s*if', '^%s*repeat', '^%s*while',
+ 'function%s*%b()%s*$', '^%s*local%s*function'
+}
+
+---
+-- Tries to autocomplete Lua's 'end' keyword for control structures like 'if',
+-- 'while', 'for', etc.
+-- @see control_structure_patterns
+function try_to_autocomplete_end()
+ local buffer = buffer
+ local line_num = buffer:line_from_position(buffer.current_pos)
+ local line = buffer:get_line(line_num)
+ for _, patt in ipairs(control_structure_patterns) do
+ if line:find(patt) then
+ local indent = buffer.line_indentation[line_num]
+ buffer:begin_undo_action()
+ buffer:new_line()
+ buffer:new_line()
+ buffer:add_text(patt:find('repeat') and 'until' or 'end')
+ buffer.line_indentation[line_num + 1] = indent + buffer.indent
+ buffer:line_up()
+ buffer:line_end()
+ buffer:end_undo_action()
+ return true
+ end
+ end
+ return false
end
-require 'lua.adeptsense'
-require 'lua.commands'
-require 'lua.snippets'
+---
+-- Determines the Lua file being 'require'd, searches through package.path for
+-- that file, and opens it in Textadept.
+function goto_required()
+ local line = buffer:get_cur_line()
+ local patterns = { 'require%s*(%b())', 'require%s*(([\'"])[^%2]+%2)' }
+ local file
+ for _, patt in ipairs(patterns) do
+ file = line:match(patt)
+ if file then break end
+ end
+ if not file then return end
+ file = file:sub(2, -2):gsub('%.', '/')
+ for path in package.path:gmatch('[^;]+') do
+ path = path:gsub('?', file)
+ if lfs.attributes(path) then
+ io.open_file(path:iconv('UTF-8', _CHARSET))
+ break
+ end
+ end
+end
-function set_buffer_properties()
+events.connect('file_after_save',
+ function() -- show syntax errors as annotations
+ if buffer:get_lexer() == 'lua' then
+ local buffer = buffer
+ buffer:annotation_clear_all()
+ local text = buffer:get_text()
+ text = text:gsub('^#![^\n]+', '') -- ignore shebang line
+ local _, err = loadstring(text)
+ if err then
+ local line, msg = err:match('^.-:(%d+):%s*(.+)$')
+ if line then
+ buffer.annotation_visible = 2
+ buffer:annotation_set_text(line - 1, msg)
+ buffer.annotation_style[line - 1] = 8 -- error style number
+ buffer:goto_line(line - 1)
+ end
+ end
+ end
+ end)
+
+---
+-- Container for Lua-specific key commands.
+-- @class table
+-- @name _G.keys.lua
+_G.keys.lua = {
+ al = {
+ m = { io.open_file,
+ (_HOME..'/modules/lua/init.lua'):iconv('UTF-8', _CHARSET) },
+ g = { goto_required },
+ },
+ ['s\n'] = { try_to_autocomplete_end },
+ [not OSX and 'ci' or '~'] = { sense.complete, sense },
+ ch = { sense.show_apidoc, sense },
+}
+
+-- Snippets.
+if type(_G.snippets) == 'table' then
+---
+-- Container for Lua-specific snippets.
+-- @class table
+-- @name _G.snippets.lua
+ _G.snippets.lua = {
+ l = "local %1(expr)%2( = %3(value))",
+ p = "print(%0)",
+ f = "function %1(name)(%2(args))\n\t%0\nend",
+ ['for'] = "for i=%1(1), %2(10)%3(, -1) do\n\t%0\nend",
+ fori = "for %1(i), %2(val) in ipairs(%3(table)) do\n\t%0\nend",
+ forp = "for %1(k), %2(v) in pairs(%3(table)) do\n\t%0\nend",
+ }
end