aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/ansi_c/init.lua11
-rw-r--r--modules/lua/init.lua9
-rw-r--r--modules/textadept/keys.lua14
-rw-r--r--modules/textadept/menu.lua4
-rw-r--r--modules/textadept/snippets.lua113
5 files changed, 101 insertions, 50 deletions
diff --git a/modules/ansi_c/init.lua b/modules/ansi_c/init.lua
index 5d2f85ce..d4f9bf7d 100644
--- a/modules/ansi_c/init.lua
+++ b/modules/ansi_c/init.lua
@@ -6,6 +6,9 @@ local M = {}
---
-- The ansi_c module.
-- It provides utilities for editing C code.
+-- @field autocomplete_snippets (boolean)
+-- Whether or not to include snippets in autocompletion lists.
+-- The default value is `true`.
module('_M.ansi_c')]]
-- Autocompletion and documentation.
@@ -20,6 +23,8 @@ M.tags = {
_USERHOME..'/modules/ansi_c/tags'
}
+M.autocomplete_snippets = true
+
local XPM = textadept.editing.XPM_IMAGES
local xpms = setmetatable({
c = XPM.CLASS, d = XPM.SLOT, e = XPM.VARIABLE, f = XPM.METHOD,
@@ -36,7 +41,7 @@ textadept.editing.autocompleters.ansi_c = function()
-- Attempt to identify the symbol type.
if symbol ~= '' then
local buffer = buffer
- local decl = '([%w_]+)[%s%*&]+'..symbol:gsub('(%p)', '%%%1')..'[^%w_]'
+ local decl = '([%w_]+)[%s%*&]+'..symbol:gsub('%p', '%%%0')..'[^%w_]'
for i = buffer:line_from_position(buffer.current_pos) - 1, 0, -1 do
local class = buffer:get_line(i):match(decl)
if class then symbol = class break end
@@ -73,6 +78,10 @@ textadept.editing.autocompleters.ansi_c = function()
end
end
end
+ if symbol == '' and M.autocomplete_snippets then
+ local _, snippets = textadept.editing.autocompleters.snippet()
+ for i = 1, #snippets do list[#list + 1] = snippets[i] end
+ end
return #part, list
end
diff --git a/modules/lua/init.lua b/modules/lua/init.lua
index ac6b824b..c199e4e8 100644
--- a/modules/lua/init.lua
+++ b/modules/lua/init.lua
@@ -6,6 +6,9 @@ local M = {}
---
-- The lua module.
-- It provides utilities for editing Lua code.
+-- @field autocomplete_snippets (boolean)
+-- Whether or not to include snippets in autocompletion lists.
+-- The default value is `false`.
module('_M.lua')]]
-- Autocompletion and documentation.
@@ -49,6 +52,8 @@ M.tags = {
-- @usage _M.lua.expr_types['^spawn%b()%s*$'] = 'proc'
M.expr_types = {['^[\'"]'] = 'string', ['^io%.p?open%s*%b()%s*$'] = 'file'}
+M.autocomplete_snippets = true
+
local XPM = textadept.editing.XPM_IMAGES
local xpms = {m = XPM.CLASS, f = XPM.METHOD, F = XPM.VARIABLE, t = XPM.TYPEDEF}
@@ -58,6 +63,10 @@ textadept.editing.autocompleters.lua = function()
local line, pos = buffer:get_cur_line()
local symbol, op, part = line:sub(1, pos):match('([%w_%.]-)([%.:]?)([%w_]*)$')
if symbol == '' and part == '' then return nil end -- nothing to complete
+ if symbol == '' and M.autocomplete_snippets then
+ local _, snippets = textadept.editing.autocompleters.snippet()
+ for i = 1, #snippets do list[#list + 1] = snippets[i] end
+ end
symbol, part = symbol:gsub('^_G%.?', ''), part ~= '_G' and part or ''
-- Attempt to identify string type and file type symbols.
local buffer = buffer
diff --git a/modules/textadept/keys.lua b/modules/textadept/keys.lua
index 2ed43ed3..fe3ab785 100644
--- a/modules/textadept/keys.lua
+++ b/modules/textadept/keys.lua
@@ -83,9 +83,10 @@ local M = {}
-- Ctrl+Space |⌥Esc |^Space |Complete symbol
-- Ctrl+H |^H |M-H<br/>M-S-H|Show documentation
-- Tab |⇥ |Tab |Expand snippet or next placeholder
--- Ctrl+K |⌥⇥ |M-K |Insert snippet...
+-- Ctrl+Shift+K |⌥⇧⇥ |M-S-K |Insert snippet...
-- Shift+Tab |⇧⇥ |S-Tab |Previous snippet placeholder
-- Esc |Esc |Esc |Cancel snippet
+-- Ctrl+K |⌥⇥ |M-K |Complete trigger word
-- Ctrl+F2 |⌘F2 |F1 |Toggle bookmark
-- Ctrl+Shift+F2 |⌘⇧F2 |F6 |Clear bookmarks
-- F2 |F2 |F2 |Next bookmark
@@ -219,7 +220,7 @@ module('textadept.keys')]]
-- Windows and Linux key bindings.
--
-- Unassigned keys (~ denotes keys reserved by the operating system):
--- c: C H I K p Q T ~ V Y _ ) ] } +
+-- c: C H I p Q T ~ V Y _ ) ] } +
-- a: aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ_ ) ] } *+-/=\n\s
-- ca: aAbBcCdD F jJkKlLmM N qQ t xXy zZ_"'()[]{}<>* / \s
--
@@ -256,14 +257,14 @@ module('textadept.keys')]]
-- * Control+Shift and Control+Meta+Shift keys are not recognized.
-- * Modifiers for function keys F1-F12 are not recognized.
-- For pdcurses (Win32):
--- * Many Control+Symbol keys are not recognized, but most
+-- * Many Control+Symbol keys are not recognized, but most
-- Control+Shift+Symbol keys are.
-- * Ctrl+Meta+Symbol keys are not recognized.
--
-- Unassigned keys (~ denotes keys reserved by the operating system):
-- c: g~~ ~ ~
-- cm: cd g~~ k ~ q t yz
--- m: e J K qQ sS vVw yY _ +
+-- m: e J qQ sS vVw yY _ +
-- Note: m[befhstv] may be used by Linux/BSD GUI terminals for menu access.
--
-- CTRL = 'c' (Control ^)
@@ -408,10 +409,13 @@ keys[not OSX and (GUI and 'caO' or 'mO')
or 'cmO'] = m_quick_open[_L['Quickly Open _Current Directory']][2]
keys[not OSX and (GUI and 'caP' or 'cmp') or 'cmP'] = io.quick_open
-- Snippets.
-keys[not OSX and (GUI and 'ck' or 'mk') or 'a\t'] = textadept.snippets._select
+local m_snippets = m_tools[_L['_Snippets']]
+keys[not OSX and (GUI and 'cK' or 'mK') or 'sa\t'] = textadept.snippets._select
keys['\t'] = textadept.snippets._insert
keys['s\t'] = textadept.snippets._previous
keys.esc = textadept.snippets._cancel_current
+keys[not OSX and (GUI and 'ck' or 'mk')
+ or 'a\t'] = m_snippets[_L['Complete Trigger _Word']][2]
-- Other.
keys[not OSX and 'c ' or 'aesc'] = m_tools[_L['_Complete Symbol']][2]
keys[GUI and 'ch' or 'mh'] = textadept.editing.show_documentation
diff --git a/modules/textadept/menu.lua b/modules/textadept/menu.lua
index 3806e14b..5edc1683 100644
--- a/modules/textadept/menu.lua
+++ b/modules/textadept/menu.lua
@@ -239,6 +239,10 @@ local default_menubar = {
{_L['_Expand Snippet/Next Placeholder'], textadept.snippets._insert},
{_L['_Previous Snippet Placeholder'], textadept.snippets._previous},
{_L['_Cancel Snippet'], textadept.snippets._cancel_current},
+ SEPARATOR,
+ {_L['Complete Trigger _Word'], function()
+ textadept.editing.autocomplete('snippets')
+ end}
},
SEPARATOR,
{_L['_Complete Symbol'], function()
diff --git a/modules/textadept/snippets.lua b/modules/textadept/snippets.lua
index 7fcfe55e..46a97dd6 100644
--- a/modules/textadept/snippets.lua
+++ b/modules/textadept/snippets.lua
@@ -123,6 +123,57 @@ M._paths = {}
local INDIC_SNIPPET = _SCINTILLA.next_indic_number()
local INDIC_CURRENTPLACEHOLDER = _SCINTILLA.next_indic_number()
+-- Finds the snippet assigned to the trigger word behind the caret and returns
+-- the trigger word and snippet text. If *grep* is `true`, returns a table of
+-- snippets (trigger-text key-value pairs) that match the trigger word
+-- instead of snippet text.
+-- Snippets are searched for in the global snippets table followed by snippet
+-- directories. Lexer-specific snippets are preferred.
+-- @param grep Flag that indicates whether or not to return a table of snippets
+-- that match the trigger word.
+-- @param no_trigger Flag that indicates whether or not to ignore the trigger
+-- word and return all snippets.
+-- @return trigger word, snippet text or table of matching snippets
+local function find_snippet(grep, no_trigger)
+ local snippets = {}
+ local pos = buffer.current_pos
+ local trigger = buffer:text_range(buffer:word_start_position(pos), pos)
+ if no_trigger then grep, trigger = true, '' end
+ local lexer = buffer:get_lexer(true)
+ local name_patt = '^'..trigger
+ -- Search in the snippet tables, ignoring this module's non-string members.
+ for _, v in ipairs{type(M[lexer]) == 'table' and M[lexer] or {}, M} do
+ if not grep and v[trigger] then
+ return trigger, v[trigger]
+ elseif grep then
+ for name, text in pairs(v) do
+ if name:find(name_patt) and (v ~= M or type(text) == 'string') then
+ snippets[name] = text
+ end
+ end
+ end
+ end
+ -- Search in snippet files.
+ for i = 1, #M._paths do
+ for basename in lfs.dir(M._paths[i]) do
+ -- Snippet files are either of the form "lexer.trigger.ext" or
+ -- "trigger.ext". Prefer "lexer."-prefixed snippets.
+ local p1, p2, p3 = basename:match('^([^.]+)%.?([^.]*)%.?([^.]*)$')
+ if not grep and (p1 == lexer and p2 == trigger or
+ p1 == trigger and p3 == '') or
+ grep and (p1 == lexer and p2 and p2:find(name_patt) or
+ p1 and p1:find(name_patt) and p3 == '') then
+ local f = io.open(M._paths[i]..'/'..basename)
+ text = f:read('a')
+ f:close()
+ if not grep then return trigger, text end
+ snippets[p1 == lexer and p2 or p1] = text
+ end
+ end
+ end
+ if not grep then return nil, nil else return trigger, snippets end
+end
+
-- The stack of currently running snippets.
local snippet_stack = {}
@@ -325,27 +376,7 @@ end
-- @name _insert
function M._insert(text)
local trigger
- if not text then
- local lexer = buffer:get_lexer(true)
- trigger = buffer:text_range(buffer:word_start_position(buffer.current_pos),
- buffer.current_pos)
- text = type(M[lexer]) == 'table' and M[lexer][trigger] or M[trigger]
- if not text then
- for i = 1, #M._paths do
- for basename in lfs.dir(M._paths[i]) do
- -- Snippet files are either of the form "lexer.trigger.ext" or
- -- "trigger.ext". Prefer "lexer."-prefixed snippets.
- local first, second = basename:match('^([^.]+)%.?([^.]*)')
- if first == lexer and second == trigger or
- first == trigger and second == '' and not text then
- local f = io.open(M._paths[i]..'/'..basename)
- text = f:read('a')
- f:close()
- end
- end
- end
- end
- end
+ if not text then trigger, text = find_snippet(trigger) end
if type(text) == 'function' and not trigger:find('^_') then text = text() end
local snippet = type(text) == 'string' and new_snippet(text, trigger) or
snippet_stack[#snippet_stack]
@@ -378,29 +409,12 @@ end
-- language-specific snippets.
-- @name _select
function M._select()
- local list, items = {}, {}
- for trigger, text in pairs(snippets) do
- if type(text) == 'string' then list[#list + 1] = trigger..'|'..text end
- end
- local lexer = buffer:get_lexer(true)
- if snippets[lexer] then
- for trigger, text in pairs(snippets[lexer]) do
- if type(text) == 'string' then list[#list + 1] = trigger..'|'..text end
- end
- end
- for i = 1, #M._paths do
- for basename in lfs.dir(M._paths[i]) do
- local first, second = basename:match('^([^.]+)%.?([^.]*)')
- if second == '' or first == lexer then
- local f = io.open(M._paths[i]..'/'..basename)
- list[#list + 1] = (second ~= '' and second or first)..'|'..f:read('a')
- f:close()
- end
- end
- end
- table.sort(list)
- for i = 1, #list do
- items[#items + 1], items[#items + 2] = list[i]:match('^([^|]+)|(.+)$')
+ local snippets = select(2, find_snippet(true, true))
+ local triggers, items = {}, {}
+ for trigger in pairs(snippets) do triggers[#triggers + 1] = trigger end
+ table.sort(triggers)
+ for i = 1, #triggers do
+ items[#items + 1], items[#items + 2] = triggers[i], snippets[triggers[i]]
end
local button, i = ui.dialogs.filteredlist{
title = _L['Select Snippet'], columns = {_L['Trigger'], _L['Snippet Text']},
@@ -626,6 +640,17 @@ events.connect(events.VIEW_NEW, function()
buffer.indic_style[INDIC_CURRENTPLACEHOLDER] = buffer.INDIC_HIDDEN
end)
+textadept.editing.autocompleters.snippet = function()
+ local list = {}
+ local trigger, snippets = find_snippet(true)
+ local sep = string.char(buffer.auto_c_type_separator)
+ local xpm = textadept.editing.XPM_IMAGES.NAMESPACE
+ for name in pairs(snippets) do
+ list[#list + 1] = string.format('%s%s%d', name, sep, xpm)
+ end
+ return #trigger, list
+end
+
---
-- Map of snippet triggers with their snippet text or functions that return such
-- text, with language-specific snippets tables assigned to a lexer name key.