<commit_before>-- Copyright 2007-2009 Mitchell mitchell<att><EMAIL>. See LICENSE.

local textadept = _G.textadept
local locale = _G.locale

---
-- Provides Lua-style snippets for Textadept.
module('_m.textadept.lsnippets', package.seeall)

-- Markdown:
-- ## Settings
--
-- * `MARK_SNIPPET`: The unique integer mark used to identify the line that
--    marks the end of a snippet.
-- * `MARK_SNIPPET_COLOR`: The [Scintilla color][scintilla_color] used for the
--   line that marks the end of the snippet.
--
-- [scintilla_color]: http://scintilla.org/ScintillaDoc.html#colour
--
-- ## Overview
--
-- Snippets are basically pieces of text inserted into a document, but can
-- execute code, contain placeholders you can enter dynamic text for, and
-- perform transformations on that text. This is much more powerful than
-- standard text templating.
--
-- Snippets are defined in the global table `snippets`. Each key-value pair in
-- `snippets` consist of either:
--
-- * A string snippet trigger word and its expanded text.
-- * A string language name and its associated `snippets`-like table.
-- * A string style name and its associated `snippets`-like table.
--
-- Language names are the names of the lexer files in `lexers/` such as `cpp`
-- and `lua`. Style names are different lexer styles, most of which are in
-- `lexers/lexer.lua`; examples are `whitespace`, `comment`, and `string`.
--
-- ## Snippet Precedence
--
-- When searching for a snippet to expand in the `snippets` table, snippets in
-- the current style have priority, followed by the ones in the current lexer,
-- and finally the ones in the global table.
--
-- ## Snippet Syntax
--
-- A snippet to insert may contain any of the following:
--
-- #### Plain Text
--
-- Any plain text characters may be used with the exception of `%` and &#96;.
-- These are special characters and must be "escaped" by prefixing one with a
-- `%`. As an example, `%%` inserts a single `%` in the snippet.
--
-- #### Lua and Shell Code
--
--     %(lua_code)
--     `shell_code`
--
-- The code is executed the moment the snippet is inserted.
--
-- For Lua code, the global Lua state is available as well as a `selected_text`
-- variable (containing the current selection in the buffer) for convenience.
-- Only the return value of the code execution is inserted, not standard out.
-- Therefore any `print()` statements are meaningless.
--
-- Shell code is run via Lua's [`io.popen()`][io_popen].
--
-- [io_popen]: http://www.lua.org/manual/5.1/manual.html#pdf-io.popen
--
-- #### Tab Stops and Mirrors
--
--     %num
--
-- These are visited in numeric order (1, 2, 3, etc.) with %0 being the final
-- position of the caret, or the end of the snippet if %0 is not specified. If
-- there is a placeholder (described below) with the specified `num`, its text
-- is mirrored here.
--
-- #### Placeholders
--
--     %num(text)
--
-- These are also visited in numeric order, but have precedence over tab stops,
-- and insert the specified `text` at the current position upon entry. `text`
-- can contain Lua code executed at run-time:
--
--     %num(#(lua_code))
--
-- The global Lua state is available as well as a `selected_text` variable
-- (containing the current selection in the buffer) for convenience.
--
-- `#`'s will have to be escaped with `%` for plain text. Any mis-matched `)`'s
-- must also be escaped, but balanced `()`'s need not be.
--
-- #### Transformations
--
--     %num(pattern|replacement)
--
-- These act like mirrors, but transform the text that would be inserted using
-- a given [Lua pattern][lua_pattern] and replacement. Like in placeholders,
-- `replacement` can contain Lua code executed at run-time as well as the
-- standard Lua capture sequences: `%n` where 1 <= `n` <= 9.
--
-- [lua_pattern]: http://www.lua.org/manual/5.1/manual.html#5.4.1
--
-- Any `|`'s after the first one do not need to be escaped.
--
-- ## Example
--
--     snippets = {
--       file = '%(buffer.filename)',
--       lua = {
--         f = 'function %1(name)(%2(args))\n  %0\nend',
--         string = { [string-specific snippets here] }
--       }
--     }
--
-- The first snippet is global and runs the Lua code to determine the current
-- buffer's filename and inserts it. The other snippets apply only in the `lua`
-- lexer. Any snippets in the `string` table are available only when the current
-- style is `string` in the `lua` lexer.

-- settings
MARK_SNIPPET = 4
MARK_SNIPPET_COLOR = 0x4D9999
-- end settings

---
-- Global container that holds all snippet definitions.
-- @class table
-- @name _G.snippets
_G.snippets = {}

_G.snippets.file = "%(buffer.filename)"
_G.snippets.path = "%((buffer.filename or ''):match('^.+/'))"
_G.snippets.tab  = "%%%1(1)(%2(default))"
_G.snippets.key  = "['%1'] = { %2(func)%3(, %4(arg)) }"

-- The current snippet.
local snippet = {}

-- The stack of currently running snippets.
local snippet_stack = {}

-- Replaces escaped characters with their octal equivalents in a given string.
-- @param s The string to handle escapes in.
-- @return string with escapes handled.
local function handle_escapes(s)
  local byte = string.byte
  return s:gsub('%%([%%`%)|#])',
    function(char) ("\\%03d"):format(byte(char)) end)
end

-- Replaces octal characters with their escaped equivalents in a given string.
-- @param s The string to unhandle escapes in.
-- @return string with escapes unhandled.
local function unhandle_escapes(s)
  local char = string.char
  return s:gsub('\\(%d%d%d)', function(byte) return '%'..char(byte) end)
end

-- Replaces escaped characters with the actual characters in a given string.
-- This is used when escape sequences are no longer needed.
-- @param s The string to unescape escapes in.
-- @return string with escapes unescaped.
local function unescape(s) return s:gsub('%%([%%`%)|#])', '%1') end

-- Gets the start position, end position, and text of the currently running
-- snippet.
-- @return start pos, end pos, and snippet text.
local function snippet_info()
  local buffer = buffer
  local s = snippet.start_pos
  local e =
    buffer:position_from_line(
      buffer:marker_line_from_handle(snippet.end_marker)) - 1
  if e >= s then return s, e, buffer:text_range(s, e) end
end

-- Runs the given Lua code.
-- @param code The Lua code to run.
-- @return string result from the code run.
local function run_lua_code(code)
  code = unhandle_escapes(code)
  local env =
    setmetatable({ selected_text = buffer:get_sel_text() }, { __index = _G })
  local _, val = pcall(setfenv(loadstring('return '..code), env))
  return val or ''
end

-- If previously at a placeholder or tab stop, attempts to mirror and/or
-- transform the entered text at all appropriate mirrors before moving on to
-- the next placeholder or tab stop.
-- @return false if no snippet was expanded; nil otherwise
local function next_tab_stop()
  local buffer = buffer
  local s_start, s_end, s_text = snippet_info()
  if not s_text then
    cancel_current()<commit_msg>Fixed bug introduced during refactoring; modules/textadept/lsnippets.lua<commit_after>-- Copyright 2007-2009 Mitchell mitchell<att>caladbolg.net. See LICENSE.

local textadept = _G.textadept
local locale = _G.locale

---
-- Provides Lua-style snippets for Textadept.
module('_m.textadept.lsnippets', package.seeall)

-- Markdown:
-- ## Settings
--
-- * `MARK_SNIPPET`: The unique integer mark used to identify the line that
--    marks the end of a snippet.
-- * `MARK_SNIPPET_COLOR`: The [Scintilla color][scintilla_color] used for the
--   line that marks the end of the snippet.
--
-- [scintilla_color]: http://scintilla.org/ScintillaDoc.html#colour
--
-- ## Overview
--
-- Snippets are basically pieces of text inserted into a document, but can
-- execute code, contain placeholders you can enter dynamic text for, and
-- perform transformations on that text. This is much more powerful than
-- standard text templating.
--
-- Snippets are defined in the global table `snippets`. Each key-value pair in
-- `snippets` consist of either:
--
-- * A string snippet trigger word and its expanded text.
-- * A string language name and its associated `snippets`-like table.
-- * A string style name and its associated `snippets`-like table.
--
-- Language names are the names of the lexer files in `lexers/` such as `cpp`
-- and `lua`. Style names are different lexer styles, most of which are in
-- `lexers/lexer.lua`; examples are `whitespace`, `comment`, and `string`.
--
-- ## Snippet Precedence
--
-- When searching for a snippet to expand in the `snippets` table, snippets in
-- the current style have priority, followed by the ones in the current lexer,
-- and finally the ones in the global table.
--
-- ## Snippet Syntax
--
-- A snippet to insert may contain any of the following:
--
-- #### Plain Text
--
-- Any plain text characters may be used with the exception of `%` and &#96;.
-- These are special characters and must be "escaped" by prefixing one with a
-- `%`. As an example, `%%` inserts a single `%` in the snippet.
--
-- #### Lua and Shell Code
--
--     %(lua_code)
--     `shell_code`
--
-- The code is executed the moment the snippet is inserted.
--
-- For Lua code, the global Lua state is available as well as a `selected_text`
-- variable (containing the current selection in the buffer) for convenience.
-- Only the return value of the code execution is inserted, not standard out.
-- Therefore any `print()` statements are meaningless.
--
-- Shell code is run via Lua's [`io.popen()`][io_popen].
--
-- [io_popen]: http://www.lua.org/manual/5.1/manual.html#pdf-io.popen
--
-- #### Tab Stops and Mirrors
--
--     %num
--
-- These are visited in numeric order (1, 2, 3, etc.) with %0 being the final
-- position of the caret, or the end of the snippet if %0 is not specified. If
-- there is a placeholder (described below) with the specified `num`, its text
-- is mirrored here.
--
-- #### Placeholders
--
--     %num(text)
--
-- These are also visited in numeric order, but have precedence over tab stops,
-- and insert the specified `text` at the current position upon entry. `text`
-- can contain Lua code executed at run-time:
--
--     %num(#(lua_code))
--
-- The global Lua state is available as well as a `selected_text` variable
-- (containing the current selection in the buffer) for convenience.
--
-- `#`'s will have to be escaped with `%` for plain text. Any mis-matched `)`'s
-- must also be escaped, but balanced `()`'s need not be.
--
-- #### Transformations
--
--     %num(pattern|replacement)
--
-- These act like mirrors, but transform the text that would be inserted using
-- a given [Lua pattern][lua_pattern] and replacement. Like in placeholders,
-- `replacement` can contain Lua code executed at run-time as well as the
-- standard Lua capture sequences: `%n` where 1 <= `n` <= 9.
--
-- [lua_pattern]: http://www.lua.org/manual/5.1/manual.html#5.4.1
--
-- Any `|`'s after the first one do not need to be escaped.
--
-- ## Example
--
--     snippets = {
--       file = '%(buffer.filename)',
--       lua = {
--         f = 'function %1(name)(%2(args))\n  %0\nend',
--         string = { [string-specific snippets here] }
--       }
--     }
--
-- The first snippet is global and runs the Lua code to determine the current
-- buffer's filename and inserts it. The other snippets apply only in the `lua`
-- lexer. Any snippets in the `string` table are available only when the current
-- style is `string` in the `lua` lexer.

-- settings
MARK_SNIPPET = 4
MARK_SNIPPET_COLOR = 0x4D9999
-- end settings

---
-- Global container that holds all snippet definitions.
-- @class table
-- @name _G.snippets
_G.snippets = {}

_G.snippets.file = "%(buffer.filename)"
_G.snippets.path = "%((buffer.filename or ''):match('^.+/'))"
_G.snippets.tab  = "%%%1(1)(%2(default))"
_G.snippets.key  = "['%1'] = { %2(func)%3(, %4(arg)) }"

-- The current snippet.
local snippet = {}

-- The stack of currently running snippets.
local snippet_stack = {}

-- Replaces escaped characters with their octal equivalents in a given string.
-- @param s The string to handle escapes in.
-- @return string with escapes handled.
local function handle_escapes(s)
  local byte = string.byte
  return s:gsub('%%([%%`%)|#])',
    function(char) ("\\%03d"):format(byte(char)) end)
end

-- Replaces octal characters with their escaped equivalents in a given string.
-- @param s The string to unhandle escapes in.
-- @return string with escapes unhandled.
local function unhandle_escapes(s)
  local char = string.char
  return s:gsub('\\(%d%d%d)', function(byte) return '%'..char(byte) end)
end

-- Replaces escaped characters with the actual characters in a given string.
-- This is used when escape sequences are no longer needed.
-- @param s The string to unescape escapes in.
-- @return string with escapes unescaped.
local function unescape(s) return s:gsub('%%([%%`%)|#])', '%1') end

-- Gets the start position, end position, and text of the currently running
-- snippet.
-- @return start pos, end pos, and snippet text.
local function snippet_info()
  local buffer = buffer
  local s = snippet.start_pos
  local e =
    buffer:position_from_line(
      buffer:marker_line_from_handle(snippet.end_marker)) - 1
  if e >= s then return s, e, buffer:text_range(s, e) end
end

-- Runs the given Lua code.
-- @param code The Lua code to run.
-- @return string result from the code run.
local function run_lua_code(code)
  code = unhandle_escapes(code)
  local env =
    setmetatable({ selected_text = buffer:get_sel_text() }, { __index = _G })
  local _, val = pcall(setfenv(loadstring('return '..code), env))
  return val or ''
end

-- If previously at a placeholder or tab stop, attempts to mirror and/or
-- transform the entered text at all appropriate mirrors before moving on to
-- the next placeholder or tab stop.
-- @return false if no snippet was expanded; nil otherwise
local function next_tab_stop()
  if not snippet.index then return false end -- no snippet active
  local buffer = buffer
  local s_start, s_end, s_text = snippet_info()
  if not s_text then
    cancel_current()
{'fraction_non_alphanumeric': 0.1303945965161749, 'fraction_numerical': 0.006398862424457874, 'mean_word_length': 3.2546884452510585, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3374282', 'n_tokens_mistral': 4455, 'n_tokens_neox': 4227, 'n_words': 1758}