aboutsummaryrefslogtreecommitdiff
path: root/modules/textadept
diff options
context:
space:
mode:
Diffstat (limited to 'modules/textadept')
-rw-r--r--modules/textadept/keys.lua14
-rw-r--r--modules/textadept/menu.lua4
-rw-r--r--modules/textadept/snippets.lua113
3 files changed, 82 insertions, 49 deletions
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.