aboutsummaryrefslogtreecommitdiff
path: root/modules/textadept/snippets.lua
diff options
context:
space:
mode:
authormitchell <70453897+667e-11@users.noreply.github.com>2011-03-23 18:50:51 -0400
committermitchell <70453897+667e-11@users.noreply.github.com>2011-03-23 18:50:51 -0400
commitdf3c07f9708affb1313bb528e684d73ec18c3bbd (patch)
tree72959fce50dc384531c35ee633bfcc0fbfcad8b9 /modules/textadept/snippets.lua
parentce617fad92178e4293e010fc5b427262f5976912 (diff)
downloadtextadept-df3c07f9708affb1313bb528e684d73ec18c3bbd.tar.gz
textadept-df3c07f9708affb1313bb528e684d73ec18c3bbd.zip
Code cleanup and fixed bugs introduced; modules/textadept/snippets.lua
Diffstat (limited to 'modules/textadept/snippets.lua')
-rw-r--r--modules/textadept/snippets.lua187
1 files changed, 81 insertions, 106 deletions
diff --git a/modules/textadept/snippets.lua b/modules/textadept/snippets.lua
index f85d8341..a0da19f2 100644
--- a/modules/textadept/snippets.lua
+++ b/modules/textadept/snippets.lua
@@ -22,9 +22,9 @@ module('_m.textadept.snippets', package.seeall)
-- Language names are the names of the lexer files in `lexers/` such as `cpp`
-- and `lua`.
--
--- By default, the `Tab` key expands a snippet and tabs through placeholders and
--- tab stops while `Shift+Tab` tabs backwards through them. Snippets can also be
--- expanded inside one another.
+-- By default, the `Tab` key expands a snippet and tabs through placeholders
+-- while `Shift+Tab` tabs backwards through them. Snippets can also be expanded
+-- inside one another.
--
-- ## Settings
--
@@ -139,19 +139,21 @@ local newlines = { [0] = '\r\n', '\r', '\n' }
-- Inserts a new snippet.
-- @param text The new snippet to insert.
--- @param replace_word Flag indicating whether or not a trigger word was used.
--- If true, removes it. Defaults to false.
-local function new_snippet(text, replace_word)
+-- @param trigger The trigger text used to expand the snippet, if any.
+local function new_snippet(text, trigger)
local buffer = buffer
- local start_position = buffer.current_pos
- local original_sel_text = buffer:get_sel_text()
- local newline = newlines[buffer.eol_mode]
+ local snippet = setmetatable({
+ trigger = trigger,
+ original_sel_text = buffer:get_sel_text(),
+ snapshots = {}
+ }, { __index = _snippet_mt })
+ snippet_stack[#snippet_stack + 1] = snippet
-- Convert and match indentation.
local lines = {}
local indent = { [true] = '\t', [false] = (' '):rep(buffer.tab_width) }
local use_tabs = buffer.use_tabs
- for line in (text..newline):gmatch('([^\r\n]*)'..newline) do
+ for line in (text..'\n'):gmatch('([^\r\n]*)\r?\n') do
lines[#lines + 1] = line:gsub('^(%s*)', function(indentation)
return indentation:gsub(indent[not use_tabs], indent[use_tabs])
end)
@@ -163,29 +165,17 @@ local function new_snippet(text, replace_word)
local additional_indent = indent[use_tabs]:rep(indent_size)
for i = 2, #lines do lines[i] = additional_indent..lines[i] end
end
- text = table.concat(lines, newline)
+ text = table.concat(lines, newlines[buffer.eol_mode])
-- Insert the snippet and its mark into the buffer.
- buffer:begin_undo_action()
- if replace_word then
- buffer.target_start = buffer:word_start_position(start_position)
- buffer.target_end = start_position
- buffer:replace_target('')
- end
- buffer:replace_sel(text..newline)
- local line = buffer:line_from_position(buffer.current_pos)
- local end_marker = buffer:marker_add(line, MARK_SNIPPET)
- buffer:end_undo_action()
-
- -- Set the snippet object metatable, add it to the snippet stack, and return
- -- the snippet object.
- local snippet = setmetatable({
- start_position = start_position,
- end_marker = end_marker,
- original_sel_text = original_sel_text,
- snapshots = {}
- }, { __index = _snippet_mt })
- snippet_stack[#snippet_stack + 1] = snippet
+ buffer:target_from_selection()
+ if trigger then buffer.target_start = buffer.current_pos - #trigger end
+ snippet.start_position = buffer.target_start
+ buffer:replace_target(text..newlines[buffer.eol_mode])
+ local line = buffer:line_from_position(buffer.target_end)
+ snippet.end_marker = buffer:marker_add(line, MARK_SNIPPET)
+
+ snippet:execute_code('')
return snippet
end
@@ -196,40 +186,36 @@ end
-- @return false if no snippet was expanded; true otherwise.
function _insert(text)
local buffer = buffer
- local from_trigger = text == nil
+ local trigger
if not text then
- local current_pos = buffer.current_pos
local lexer = buffer:get_lexer()
- local trigger = buffer:text_range(buffer:word_start_position(current_pos),
- current_pos)
+ trigger = buffer:text_range(buffer:word_start_position(buffer.current_pos),
+ buffer.current_pos)
local snip = _G.snippets
text = snip[trigger]
if type(snip) == 'table' and snip[lexer] then snip = snip[lexer] end
text = snip[trigger] or text
end
local snippet = snippet_stack[#snippet_stack]
- if text and type(text) == 'string' then
- snippet = new_snippet(text, from_trigger)
- snippet:execute_code('') -- execute shell and Lua code
- end
+ if type(text) == 'string' then snippet = new_snippet(text, trigger) end
if not snippet then return false end
snippet:next()
end
---
--- Goes back to the previous placeholder or tab stop, reverting any changes from
--- the current placeholder or tab stop.
+-- Goes back to the previous placeholder, reverting any changes from the current
+-- one.
-- @return false if no snippet is active; nil otherwise.
function _previous()
if #snippet_stack == 0 then return false end
- snippet_stack[#snippet_stack]:prev()
+ snippet_stack[#snippet_stack]:previous()
end
---
-- Cancels the active snippet, reverting to the state before its activation, and
-- restores the previously running snippet (if any).
function _cancel_current()
- if #snippet_stack == 0 then snippet_stack[#snippet_stack]:cancel() end
+ if #snippet_stack > 0 then snippet_stack[#snippet_stack]:cancel() end
end
---
@@ -247,18 +233,18 @@ function _select()
local lexer = buffer:get_lexer()
for trigger, text in pairs(_G.snippets[lexer] or {}) do
if type(text) == 'string' then
- list[#list + 1] = concat({trigger, lexer, text }, '\0')
+ list[#list + 1] = table_concat({trigger, lexer, text }, '\0')
end
end
table.sort(list)
- local s = {}
+ local t = {}
for i = 1, #list do
- s[#s + 1], s[#s + 2], s[#s + 3] = list[i]:match('^(%Z+)%z(%Z+)%z(%Z+)$')
+ t[#t + 1], t[#t + 2], t[#t + 3] = list[i]:match('^(%Z+)%z(%Z+)%z(%Z+)$')
end
local i = gui.filteredlist(L('Select Snippet'),
- { ('Trigger'), L('Scope'), L('Snippet Text') },
- s, true, '--output-column', '2')
- if i then _insert(s[(i + 1) * 3]) end
+ { L('Trigger'), L('Scope'), L('Snippet Text') },
+ t, true, '--output-column', '2')
+ if i then _insert(t[(i + 1) * 3]) end
end
-- Table of escape sequences.
@@ -278,9 +264,12 @@ local escapes = {
_snippet_mt = {
-- Gets a snippet's end position in the Scintilla buffer.
-- @param snippet The snippet returned by new_snippet().
- get_end_position = function(snippet)
- return buffer:position_from_line(
- buffer:marker_line_from_handle(snippet.end_marker)) - 1
+ -- @param include_mark Flag indicating whether or not to include the snippet's
+ -- mark. Defaults to false.
+ get_end_position = function(snippet, include_mark)
+ local line = buffer:marker_line_from_handle(snippet.end_marker)
+ local offset = include_mark and 0 or #newlines[buffer.eol_mode]
+ return buffer:position_from_line(line) - offset
end,
-- Gets the text for a snippet.
@@ -327,9 +316,8 @@ _snippet_mt = {
escaped_text = escaped_text:gsub('%%'..index..'<([^>]*)>', function(code)
local env = setmetatable({ selected_text = snippet.original_sel_text },
{ __index = _G })
- local f, errmsg = loadstring('return '..snippet.unescape_text(code, true))
- if not f then return errmsg end
- local _, result = pcall(setfenv(f, env))
+ local f, result = loadstring('return '..snippet.unescape_text(code, true))
+ if f then f, result = pcall(setfenv(f, env)) end
return result or ''
end)
-- Shell code.
@@ -342,74 +330,62 @@ _snippet_mt = {
snippet:set_text(snippet.unescape_text(escaped_text))
end,
- -- Goes to the next placeholder or tab stop in a snippet.
+ -- Goes to the next placeholder in a snippet.
-- @param snippet The snippet returned by new_snippet().
next = function(snippet)
local buffer = buffer
-
- -- If the snippet was just initialized, determine how many tab stops it has.
+ -- If the snippet was just initialized, determine how many placeholders it
+ -- has.
if not snippet.index then
- snippet.index, snippet.max_index = 0, 0
+ snippet.index, snippet.max_index = 1, 0
for i in snippet:get_escaped_text():gmatch('%%(%d+)') do
i = tonumber(i)
if i > snippet.max_index then snippet.max_index = i end
end
end
-
- local index, start_position = snippet.index, snippet.start_position
+ local index = snippet.index
snippet.snapshots[index] = snippet:get_text()
- index = index + 1
if index <= snippet.max_index then
-- Execute shell and Lua code.
snippet:execute_code(index)
local escaped_text = snippet:get_escaped_text()..' '
- -- Find the next tab stop or placeholder that is not a replacement mirror.
- local s, e, placeholder, _
- repeat
- s, _, placeholder, e = escaped_text:find('%%'..index..'(%b())()', e)
- until not s or placeholder
- if placeholder then placeholder = placeholder:sub(2, -2) end
- if not placeholder then
- -- Tab stop.
- s, _, e = escaped_text:find('%%'..index..'()[^(]')
- if not s then
- snippet.index = index
- snippet:next()
- return
+ -- Find the next placeholder.
+ local s, _, placeholder, e = escaped_text:find('%%'..index..'(%b())()')
+ if not s then s, _, e = escaped_text:find('%%'..index..'()[^(]') end
+ if s then
+ local start = snippet.start_position
+ placeholder = (placeholder or ''):sub(2, -2)
+
+ -- Place the caret at the placeholder.
+ buffer.target_start, buffer.target_end = start + s - 1, start + e - 1
+ buffer:replace_target(snippet.unescape_text(placeholder))
+ buffer:set_sel(buffer.target_start, buffer.target_end)
+
+ -- Add additional carets at mirrors.
+ escaped_text = snippet:get_escaped_text()..' '
+ offset = 0
+ for s, e in escaped_text:gmatch('()%%'..index..'()[^(]') do
+ buffer.target_start = start + s - 1 + offset
+ buffer.target_end = start + e - 1 + offset
+ buffer:replace_target(placeholder)
+ buffer:add_selection(buffer.target_start, buffer.target_end)
+ offset = offset + (#placeholder - (e - s))
end
- placeholder = ''
- end
- s, e = start_position + s - 1, start_position + e - 1
- buffer:set_sel(s, e)
- buffer:replace_sel(snippet.unescape_text(placeholder))
- if placeholder ~= '' then buffer:set_sel(s, s + #placeholder) end
-
- -- Add additional carets at mirrors.
- escaped_text = snippet:get_escaped_text()..' '
- offset = 0
- for s, e in escaped_text:gmatch('()%%'..index..'()[^(]') do
- buffer.target_start = start_position + s - 1 + offset
- buffer.target_end = start_position + e - 1 + offset
- buffer:replace_target(placeholder)
- offset = offset + (#placeholder - (e - s))
- buffer:add_selection(buffer.target_start, buffer.target_end)
+ buffer.main_selection = 0
end
- buffer.main_selection = 0
-
- -- Done.
- snippet.index = index
+ snippet.index = index + 1
+ if not s then snippet:next() end
else
- -- Finished.
snippet:finish()
end
end,
- -- Goes to the previous placeholder or tab stop in a snippet.
+ -- Goes to the previous placeholder in a snippet.
-- @param snippet The snippet returned by new_snippet().
- prev = function(snippet)
- if snippet.index > 1 then
+ previous = function(snippet)
+ if snippet.index > 2 then
snippet:set_text(snippet.snapshots[snippet.index - 2])
snippet.index = snippet.index - 2
snippet:next()
@@ -422,27 +398,26 @@ _snippet_mt = {
-- @param snippet The snippet returned by new_snippet().
cancel = function(snippet)
local buffer = buffer
- buffer:set_sel(snippet.start_position, snippet:get_end_position() + 1)
- buffer:replace_sel(snippet.original_sel_text or '')
+ buffer:set_sel(snippet.start_position, snippet:get_end_position(true))
+ buffer:replace_sel(snippet.trigger or snippet.original_sel_text)
buffer:marker_delete_handle(snippet.end_marker)
snippet_stack[#snippet_stack] = nil
end,
- -- Finishes a snippet by going to its '%0' tab stop and cleaning up.
+ -- Finishes a snippet by going to its '%0' placeholder and cleaning up.
-- @param snippet The snippet returned by new_snippet().
finish = function(snippet)
local buffer = buffer
snippet:set_text(snippet.unescape_text(snippet:get_text(), true))
local s, e = snippet:get_text():find('%%0')
if s and e then
- s, e = snippet.start_position + s - 1, snippet.start_position + e
- buffer:set_sel(s, e)
+ buffer:set_sel(snippet.start_position + s - 1, snippet.start_position + e)
buffer:replace_sel('')
else
buffer:goto_pos(snippet:get_end_position())
end
- e = snippet:get_end_position()
- buffer.target_start, buffer.target_end = e, e + 1
+ s, e = snippet:get_end_position(), snippet:get_end_position(true)
+ buffer.target_start, buffer.target_end = s, e
buffer:replace_target('')
buffer:marker_delete_handle(snippet.end_marker)
snippet_stack[#snippet_stack] = nil