diff options
author | mitchell <70453897+orbitalquark@users.noreply.github.com> | 2021-04-11 09:34:17 -0400 |
---|---|---|
committer | mitchell <70453897+orbitalquark@users.noreply.github.com> | 2021-04-11 09:34:17 -0400 |
commit | de3a745e1af2e441de868c2aa4849102d376acb5 (patch) | |
tree | c2d7767600dc519b2613ddecaf7e53fb5e8867a2 /modules/textadept | |
parent | 03fab17277fee7387fd93a9c2774b1ebf3f80fe4 (diff) |
Initial pass reformatting all code.
Use clang-format, LuaFormatter, and 100 character limit on lines.
Diffstat (limited to 'modules/textadept')
-rw-r--r-- | modules/textadept/bookmarks.lua | 27 | ||||
-rw-r--r-- | modules/textadept/command_entry.lua | 144 | ||||
-rw-r--r-- | modules/textadept/editing.lua | 255 | ||||
-rw-r--r-- | modules/textadept/file_types.lua | 34 | ||||
-rw-r--r-- | modules/textadept/find.lua | 225 | ||||
-rw-r--r-- | modules/textadept/history.lua | 87 | ||||
-rw-r--r-- | modules/textadept/init.lua | 4 | ||||
-rw-r--r-- | modules/textadept/keys.lua | 499 | ||||
-rw-r--r-- | modules/textadept/macros.lua | 40 | ||||
-rw-r--r-- | modules/textadept/menu.lua | 162 | ||||
-rw-r--r-- | modules/textadept/run.lua | 348 | ||||
-rw-r--r-- | modules/textadept/session.lua | 71 | ||||
-rw-r--r-- | modules/textadept/snippets.lua | 334 |
13 files changed, 1040 insertions, 1190 deletions
diff --git a/modules/textadept/bookmarks.lua b/modules/textadept/bookmarks.lua index b790fd09..532d1427 100644 --- a/modules/textadept/bookmarks.lua +++ b/modules/textadept/bookmarks.lua @@ -35,13 +35,13 @@ local function bookmarks(buffer) end --- --- Prompts the user to select a bookmarked line to move the caret to the --- beginning of unless *next* is given. --- If *next* is `true` or `false`, moves the caret to the beginning of the next --- or previously bookmarked line, respectively. --- @param next Optional flag indicating whether to go to the next or previous --- bookmarked line relative to the current line. The default value is `nil`, --- prompting the user for a bookmarked line to go to. +-- Prompts the user to select a bookmarked line to move the caret to the beginning of unless +-- *next* is given. +-- If *next* is `true` or `false`, moves the caret to the beginning of the next or previously +-- bookmarked line, respectively. +-- @param next Optional flag indicating whether to go to the next or previous bookmarked +-- line relative to the current line. The default value is `nil`, prompting the user for a +-- bookmarked line to go to. -- @name goto_mark function M.goto_mark(next) if next ~= nil then @@ -49,9 +49,7 @@ function M.goto_mark(next) local line = buffer:line_from_position(buffer.current_pos) local BOOKMARK_BIT = 1 << M.MARK_BOOKMARK - 1 line = f(buffer, line + (next and 1 or -1), BOOKMARK_BIT) - if line == -1 then - line = f(buffer, (next and 1 or buffer.line_count), BOOKMARK_BIT) - end + if line == -1 then line = f(buffer, (next and 1 or buffer.line_count), BOOKMARK_BIT) end if line >= 1 then textadept.editing.goto_line(line) end return end @@ -64,8 +62,8 @@ function M.goto_mark(next) if buffer.filename then filename = filename:iconv('UTF-8', _CHARSET) end local basename = buffer.filename and filename:match('[^/\\]+$') or filename for line in bookmarks(buffer) do - utf8_list[#utf8_list + 1] = string.format( - '%s:%d: %s', basename, line, buffer:get_line(line):match('^[^\r\n]*')) + utf8_list[#utf8_list + 1] = string.format('%s:%d: %s', basename, line, + buffer:get_line(line):match('^[^\r\n]*')) buffers[#buffers + 1] = buffer end ::continue:: @@ -83,9 +81,8 @@ end local lines = {} -- Save and restore bookmarks on buffer:reload(). -events.connect(events.FILE_BEFORE_RELOAD, function() - for line in bookmarks(buffer) do lines[#lines + 1] = line end -end) +events.connect(events.FILE_BEFORE_RELOAD, + function() for line in bookmarks(buffer) do lines[#lines + 1] = line end end) events.connect(events.FILE_AFTER_RELOAD, function() for _, line in ipairs(lines) do buffer:marker_add(line, M.MARK_BOOKMARK) end lines = {} -- clear diff --git a/modules/textadept/command_entry.lua b/modules/textadept/command_entry.lua index 14e66a07..cecad02c 100644 --- a/modules/textadept/command_entry.lua +++ b/modules/textadept/command_entry.lua @@ -6,8 +6,8 @@ local M = ui.command_entry --[[ This comment is for LuaDoc. --- -- Textadept's Command Entry. --- It supports multiple modes that each have their own functionality (such as --- running Lua code and filtering text through shell commands) and history. +-- It supports multiple modes that each have their own functionality (such as running Lua code +-- and filtering text through shell commands) and history. -- @field height (number) -- The height in pixels of the command entry. -- @field active (boolean) @@ -18,16 +18,21 @@ module('ui.command_entry')]] -- The current mode is in the `mode` field. -- @class table -- @name history -local history = setmetatable({}, {__index = function(t, k) - if type(k) == 'function' then t[k] = {pos = 0} else return nil end - return t[k] -end}) +local history = setmetatable({}, { + __index = function(t, k) + if type(k) ~= 'function' then return nil end + t[k] = {pos = 0} + return t[k] + end +}) -- Cycles through command history for the current mode. --- @param prev Flag that indicates whether to cycle to the previous command or --- the next one. +-- @param prev Flag that indicates whether to cycle to the previous command or the next one. local function cycle_history(prev) - if M:auto_c_active() then M[prev and 'line_up' or 'line_down'](M) return end + if M:auto_c_active() then + M[prev and 'line_up' or 'line_down'](M) + return + end local mode_history = history[history.mode] if not mode_history or prev and mode_history.pos <= 1 then return end if not prev and mode_history.pos >= #mode_history then return end @@ -38,14 +43,12 @@ local function cycle_history(prev) end --- --- Appends string *text* to the history for command entry mode *f* or the --- current or most recent mode. --- This should only be called if `ui.command_entry.run()` is called with a keys --- table that has a custom binding for the Enter key ('\n'). --- Otherwise, history is automatically appended as needed. --- @param f Optional command entry mode to append history to. This is a function --- passed to `ui.command_entry_run()`. If omitted, uses the current or most --- recent mode. +-- Appends string *text* to the history for command entry mode *f* or the current or most +-- recent mode. +-- This should only be called if `ui.command_entry.run()` is called with a keys table that has a +-- custom binding for the Enter key ('\n'). Otherwise, history is automatically appended as needed. +-- @param f Optional command entry mode to append history to. This is a function passed to +-- `ui.command_entry_run()`. If omitted, uses the current or most recent mode. -- @param text String text to append to history. -- @name append_history function M.append_history(f, text) @@ -59,9 +62,8 @@ end --- -- A metatable with typical platform-specific key bindings for text entries. --- This metatable may be used to add basic editing and movement keys to command --- entry modes. It is automatically added to command entry modes unless a --- metatable was previously set. +-- This metatable may be used to add basic editing and movement keys to command entry modes. It +-- is automatically added to command entry modes unless a metatable was previously set. -- @usage setmetatable(mode_keys, ui.command_entry.editing_keys) -- @class table -- @name editing_keys @@ -69,8 +71,7 @@ M.editing_keys = {__index = {}} -- Fill in default key bindings for Linux/Win32, macOS, Terminal. local bindings = { - -- Note: cannot use `M.cut`, `M.copy`, etc. since M is never considered the - -- global buffer. + -- Note: cannot use `M.cut`, `M.copy`, etc. since M is never considered the global buffer. [function() M:undo() end] = {'ctrl+z', 'cmd+z', 'ctrl+z'}, [function() M:undo() end] = {nil, nil, 'meta+z'}, [function() M:redo() end] = {'ctrl+y', 'cmd+Z', 'ctrl+y'}, @@ -80,7 +81,7 @@ local bindings = { [function() M:paste() end] = {'ctrl+v', 'cmd+v', 'ctrl+v'}, [function() M:select_all() end] = {'ctrl+a', 'cmd+a', 'meta+a'}, [function() cycle_history(true) end] = {'up', 'up', 'up'}, - [cycle_history] = {'down', 'down', 'down'}, + [cycle_history] = {'down', 'down', 'down'}, -- LuaFormatter -- Movement keys. [function() M:char_right() end] = {nil, 'ctrl+f', 'ctrl+f'}, [function() M:char_left() end] = {nil, 'ctrl+b', 'ctrl+b'}, @@ -104,25 +105,26 @@ local env = setmetatable({}, { return function(...) view[k](view, ...) end -- do not return a value end return buffer[k] or view[k] or ui[k] or _G[k] or textadept[k] - end, + end, -- LuaFormatter __newindex = function(self, k, v) local ok, value = pcall(function() return buffer[k] end) if ok and value ~= nil or not ok and value:find('write-only property') then buffer[k] = v -- buffer and view are interchangeable in this case - return + elseif view[k] ~= nil then + view[k] = v + elseif ui[k] ~= nil then + ui[k] = v + else + rawset(self, k, v) end - if view[k] ~= nil then view[k] = v return end - if ui[k] ~= nil then ui[k] = v return end - rawset(self, k, v) end }) --- Executes string *code* as Lua code that is subject to an "abbreviated" --- environment. --- In this environment, the contents of the `buffer`, `view`, `ui`, and --- `textadept` tables are also considered as global functions and fields. --- Prints the results of expressions like in the Lua prompt. Also invokes bare --- functions as commands. +-- Executes string *code* as Lua code that is subject to an "abbreviated" environment. +-- In this environment, the contents of the `buffer`, `view`, `ui`, and `textadept` tables are +-- also considered as global functions and fields. +-- Prints the results of expressions like in the Lua prompt. Also invokes bare functions as +-- commands. -- @param code The Lua code to execute. local function run_lua(code) local f, errmsg = load('return ' .. code, nil, 't', env) @@ -131,15 +133,12 @@ local function run_lua(code) if type(result) == 'function' then result = result() end if type(result) == 'table' then local items = {} - for k, v in pairs(result) do - items[#items + 1] = string.format('%s = %s', k, v) - end + for k, v in pairs(result) do items[#items + 1] = string.format('%s = %s', k, v) end table.sort(items) result = string.format('{%s}', table.concat(items, ', ')) if view.edge_column > 0 and #result > view.edge_column then local indent = string.rep(' ', buffer.tab_width) - result = string.format( - '{\n%s%s\n}', indent, table.concat(items, ',\n' .. indent)) + result = string.format('{\n%s%s\n}', indent, table.concat(items, ',\n' .. indent)) end end if result ~= nil or code:find('^return ') then ui.print(result) end @@ -147,15 +146,13 @@ local function run_lua(code) end args.register('-e', '--execute', 1, run_lua, 'Execute Lua code') --- Shows a set of Lua code completions for the entry's text, subject to an --- "abbreviated" environment where the contents of the `buffer`, `view`, and --- `ui` tables are also considered as globals. +-- Shows a set of Lua code completions for the entry's text, subject to an "abbreviated" +-- environment where the contents of the `buffer`, `view`, and `ui` tables are also considered +-- as globals. local function complete_lua() local line, pos = M:get_cur_line() - local symbol, op, part = line:sub(1, pos - 1):match( - '([%w_.]-)([%.:]?)([%w_]*)$') - local ok, result = pcall( - (load(string.format('return (%s)', symbol), nil, 't', env))) + local symbol, op, part = line:sub(1, pos - 1):match('([%w_.]-)([%.:]?)([%w_]*)$') + local ok, result = pcall((load(string.format('return (%s)', symbol), nil, 't', env))) if (not ok or type(result) ~= 'table') and symbol ~= '' then return end local cmpls = {} part = '^' .. part @@ -163,23 +160,20 @@ local function complete_lua() local sep = string.char(M.auto_c_type_separator) if not ok or symbol == 'buffer' or symbol == 'view' then local sci = _SCINTILLA - local global_envs = not ok and { - buffer, view, ui, _G, textadept, sci.functions, sci.properties, - sci.constants - } or op == ':' and {sci.functions} or {sci.properties, sci.constants} + local global_envs = not ok and + {buffer, view, ui, _G, textadept, sci.functions, sci.properties, sci.constants} or op == ':' and + {sci.functions} or {sci.properties, sci.constants} for _, env in ipairs(global_envs) do for k, v in pairs(env) do if type(k) ~= 'string' or not k:find(part) then goto continue end - local xpm = (type(v) == 'function' or env == sci.functions) and - XPM.METHOD or XPM.VARIABLE + local xpm = (type(v) == 'function' or env == sci.functions) and XPM.METHOD or XPM.VARIABLE cmpls[#cmpls + 1] = k .. sep .. xpm ::continue:: end end else for k, v in pairs(result) do - if type(k) == 'string' and k:find(part) and - (op == '.' or type(v) == 'function') then + if type(k) == 'string' and k:find(part) and (op == '.' or type(v) == 'function') then local xpm = type(v) == 'function' and XPM.METHOD or XPM.VARIABLE cmpls[#cmpls + 1] = k .. sep .. xpm end @@ -198,28 +192,22 @@ local lua_keys = {['\t'] = complete_lua} local prev_key_mode --- --- Opens the command entry, subjecting it to any key bindings defined in table --- *keys*, highlighting text with lexer name *lang*, and displaying --- *height* number of lines at a time, and then when the `Enter` key is pressed, --- closes the command entry and calls function *f* (if non-`nil`) with the --- command entry's text as an argument. +-- Opens the command entry, subjecting it to any key bindings defined in table *keys*, +-- highlighting text with lexer name *lang*, and displaying *height* number of lines at a time, +-- and then when the `Enter` key is pressed, closes the command entry and calls function *f* +-- (if non-`nil`) with the command entry's text as an argument. -- By default with no arguments given, opens a Lua command entry. --- The command entry does not respond to Textadept's default key bindings, but --- instead to the key bindings defined in *keys* and in --- `ui.command_entry.editing_keys`. --- @param f Optional function to call upon pressing `Enter` in the command --- entry, ending the mode. It should accept the command entry text as an --- argument. --- @param keys Optional table of key bindings to respond to. This is in --- addition to the basic editing and movement keys defined in --- `ui.command_entry.editing_keys`. --- `Esc` and `Enter` are automatically defined to cancel and finish the --- command entry, respectively. +-- The command entry does not respond to Textadept's default key bindings, but instead to the +-- key bindings defined in *keys* and in `ui.command_entry.editing_keys`. +-- @param f Optional function to call upon pressing `Enter` in the command entry, ending the mode. +-- It should accept the command entry text as an argument. +-- @param keys Optional table of key bindings to respond to. This is in addition to the +-- basic editing and movement keys defined in `ui.command_entry.editing_keys`. `Esc` and +-- `Enter` are automatically defined to cancel and finish the command entry, respectively. -- This parameter may be omitted completely. --- @param lang Optional string lexer name to use for command entry text. The --- default value is `'text'`. --- @param height Optional number of lines to display in the command entry. The --- default value is `1`. +-- @param lang Optional string lexer name to use for command entry text. The default value is +-- `'text'`. +-- @param height Optional number of lines to display in the command entry. The default value is `1`. -- @see editing_keys -- @usage ui.command_entry.run(ui.print) -- @name run @@ -262,8 +250,8 @@ M.focus = function() end -- Configure the command entry's default properties. --- Also find the key binding for `textadept.editing.show_documentation` and use --- it to show Lua documentation in the Lua command entry. +-- Also find the key binding for `textadept.editing.show_documentation` and use it to show Lua +-- documentation in the Lua command entry. events.connect(events.INITIALIZED, function() M.h_scroll_bar, M.v_scroll_bar = false, false for i = 1, M.margins do M.margin_width_n[i] = 0 end @@ -271,8 +259,8 @@ events.connect(events.INITIALIZED, function() for key, f in pairs(keys) do if f ~= textadept.editing.show_documentation then goto continue end lua_keys[key] = function() - -- Temporarily change _G.buffer and _G.view since ui.command_entry is - -- the "active" buffer and view. + -- Temporarily change _G.buffer and _G.view since ui.command_entry is the "active" buffer + -- and view. local orig_buffer, orig_view = _G.buffer, _G.view _G.buffer, _G.view = ui.command_entry, ui.command_entry textadept.editing.show_documentation() diff --git a/modules/textadept/editing.lua b/modules/textadept/editing.lua index 7ff771a2..1b4a51ba 100644 --- a/modules/textadept/editing.lua +++ b/modules/textadept/editing.lua @@ -9,8 +9,7 @@ local M = {} -- Match the previous line's indentation level after inserting a new line. -- The default value is `true`. -- @field strip_trailing_spaces (bool) --- Strip trailing whitespace before saving files. (Does not apply to binary --- files.) +-- Strip trailing whitespace before saving files. (Does not apply to binary files.) -- The default value is `false`. -- @field autocomplete_all_words (bool) -- Autocomplete the current word using words from all open buffers. @@ -28,8 +27,8 @@ local M = {} -- -- The default value is `textadept.editing.HIGHLIGHT_NONE`. -- @field auto_enclose (bool) --- Whether or not to auto-enclose selected text when typing a punctuation --- character, taking [`textadept.editing.auto_pairs`]() into account. +-- Whether or not to auto-enclose selected text when typing a punctuation character, taking +-- [`textadept.editing.auto_pairs`]() into account. -- The default value is `false`. -- @field INDIC_BRACEMATCH (number) -- The matching brace highlight indicator number. @@ -46,6 +45,7 @@ M.auto_enclose = false M.INDIC_BRACEMATCH = _SCINTILLA.next_indic_number() M.INDIC_HIGHLIGHT = _SCINTILLA.next_indic_number() +-- LuaFormatter off --- -- Map of image names to registered image numbers. -- @field CLASS The image number for classes. @@ -59,6 +59,7 @@ M.INDIC_HIGHLIGHT = _SCINTILLA.next_indic_number() -- @class table -- @name XPM_IMAGES M.XPM_IMAGES = {not CURSES and '/* XPM */static char *class[] = {/* columns rows colors chars-per-pixel */"16 16 10 1 "," c #000000",". c #001CD0","X c #008080","o c #0080E8","O c #00C0C0","+ c #24D0FC","@ c #00FFFF","# c #A4E8FC","$ c #C0FFFF","% c None",/* pixels */"%%%%% %%%%%%%%%","%%%% ## %%%%%%%","%%% ###++ %%%%%%","%% +++++. %%%%","%% oo++.. $$ %%","%% ooo.. $$$@@ %","%% ooo. @@@@@X %","%%% . OO@@XX %","%%% ## OOOXXX %","%% ###++ OOXX %%","% +++++. OX %%%","% oo++.. % %%%%","% ooo... %%%%%%%","% ooo.. %%%%%%%%","%% o. %%%%%%%%%","%%%% %%%%%%%%%%"};' or '*',not CURSES and '/* XPM */static char *namespace[] = {/* columns rows colors chars-per-pixel */"16 16 7 1 "," c #000000",". c #1D1D1D","X c #393939","o c #555555","O c #A8A8A8","+ c #AAAAAA","@ c None",/* pixels */"@@@@@@@@@@@@@@@@","@@@@+@@@@@@@@@@@","@@@.o@@@@@@@@@@@","@@@ +@@@@@@@@@@@","@@@ +@@@@@@@@@@@","@@+.@@@@@@@+@@@@","@@+ @@@@@@@o.@@@","@@@ +@@@@@@+ @@@","@@@ +@@@@@@+ @@@","@@@.X@@@@@@@.+@@","@@@@+@@@@@@@ @@@","@@@@@@@@@@@+ @@@","@@@@@@@@@@@+ @@@","@@@@@@@@@@@X.@@@","@@@@@@@@@@@+@@@@","@@@@@@@@@@@@@@@@"};' or '@',not CURSES and '/* XPM */static char *method[] = {/* columns rows colors chars-per-pixel */"16 16 5 1 "," c #000000",". c #E0BC38","X c #F0DC5C","o c #FCFC80","O c None",/* pixels */"OOOOOOOOOOOOOOOO","OOOOOOOOOOOOOOOO","OOOOOOOOOOOOOOOO","OOOOOOOOOO OOOO","OOOOOOOOO oo OO","OOOOOOOO ooooo O","OOOOOOO ooooo. O","OOOO O XXoo.. O","OOO oo XXX... O","OO ooooo XX.. OO","O ooooo. X. OOO","O XXoo.. O OOOO","O XXX... OOOOOOO","O XXX.. OOOOOOOO","OO X. OOOOOOOOO","OOOO OOOOOOOOOO"};' or '+',not CURSES and '/* XPM */static char *signal[] = {/* columns rows colors chars-per-pixel */"16 16 6 1 "," c #000000",". c #FF0000","X c #E0BC38","o c #F0DC5C","O c #FCFC80","+ c None",/* pixels */"++++++++++++++++","++++++++++++++++","++++++++++++++++","++++++++++ ++++","+++++++++ OO ++","++++++++ OOOOO +","+++++++ OOOOOX +","++++ + ooOOXX +","+++ OO oooXXX +","++ OOOOO ooXX ++","+ OOOOOX oX +++","+ ooOOXX + ++++","+ oooXXX +++++++","+ oooXX +++++..+","++ oX ++++++..+","++++ ++++++++++"};' or '~',not CURSES and '/* XPM */static char *slot[] = {/* columns rows colors chars-per-pixel */"16 16 5 1 "," c #000000",". c #E0BC38","X c #F0DC5C","o c #FCFC80","O c None",/* pixels */"OOOOOOOOOOOOOOOO","OOOOOOOOOOOOOOOO","OOOOOOOOOOOOOOOO","OOOOOOOOOO OOOO","OOOOOOOOO oo OO","OOOOOOOO ooooo O","OOOOOOO ooooo. O","OOOO O XXoo.. O","OOO oo XXX... O","OO ooooo XX.. OO","O ooooo. X. OOO","O XXoo.. O OOOO","O XXX... OOOOOOO","O XXX.. OOOOO ","OO X. OOOOOO O ","OOOO OOOOOOO "};' or '-',not CURSES and '/* XPM */static char *variable[] = {/* columns rows colors chars-per-pixel */"16 16 5 1 "," c #000000",". c #8C748C","X c #9C94A4","o c #ACB4C0","O c None",/* pixels */"OOOOOOOOOOOOOOOO","OOOOOOOOOOOOOOOO","OOOOOOOOOOOOOOOO","OOOOOOOOOOOOOOOO","OOOOOOOOOOOOOOOO","OOOOOOOOOOOOOOOO","OOOOOOOOO OOOOO","OOOOOOOO oo OOO","OOOOOOO ooooo OO","OOOOOO ooooo. OO","OOOOOO XXoo.. OO","OOOOOO XXX... OO","OOOOOO XXX.. OOO","OOOOOOO X. OOOO","OOOOOOOOO OOOOO","OOOOOOOOOOOOOOOO"};' or '.',not CURSES and '/* XPM */static char *struct[] = {/* columns rows colors chars-per-pixel */"16 16 14 1 "," c #000000",". c #008000","X c #00C000","o c #00FF00","O c #808000","+ c #C0C000","@ c #FFFF00","# c #008080","$ c #00C0C0","% c #00FFFF","& c #C0FFC0","* c #FFFFC0","= c #C0FFFF","- c None",/* pixels */"----- ---------","---- && -------","--- &&&oo ------","-- ooooo. ----","-- XXoo.. == --","-- XXX.. ===%% -","-- XXX. %%%%%# -","--- . $$%%## -","--- ** $$$### -","-- ***@@ $$## --","- @@@@@O $# ---","- ++@@OO - ----","- +++OOO -------","- +++OO --------","-- +O ---------","---- ----------"};' or '}',not CURSES and '/* XPM */static char *typedef[] = {/* columns rows colors chars-per-pixel */"16 16 10 1 "," c #000000",". c #404040","X c #6D6D6D","o c #777777","O c #949494","+ c #ACACAC","@ c #BBBBBB","# c #DBDBDB","$ c #EEEEEE","% c None",/* pixels */"%%%%% %%%%%%%%%","%%%% ## %%%%%%%","%%% ###++ %%%%%%","%% +++++. %%%%","%% oo++.. $$ %%","%% ooo.. $$$@@ %","%% ooo. @@@@@X %","%%% . OO@@XX %","%%% ## OOOXXX %","%% ###++ OOXX %%","% +++++. OX %%%","% oo++.. % %%%%","% ooo... %%%%%%%","% ooo.. %%%%%%%%","%% o. %%%%%%%%%","%%%% %%%%%%%%%%"};' or ':',CLASS=1,NAMESPACE=2,METHOD=3,SIGNAL=4,SLOT=5,VARIABLE=6,STRUCT=7,TYPEDEF=8} +-- LuaFormatter on events.connect(events.VIEW_NEW, function() local view = buffer ~= ui.command_entry and view or ui.command_entry for name, i in pairs(M.XPM_IMAGES) do @@ -67,21 +68,23 @@ events.connect(events.VIEW_NEW, function() end) for _ = 1, #M.XPM_IMAGES do _SCINTILLA.next_image_type() end -- sync +-- LuaFormatter off --- --- Map of lexer names to line comment strings for programming languages, used by --- the `toggle_comment()` function. --- Keys are lexer names and values are either the language's line comment --- prefixes or block comment delimiters separated by a '|' character. +-- Map of lexer names to line comment strings for programming languages, used by the +-- `toggle_comment()` function. +-- Keys are lexer names and values are either the language's line comment prefixes or block +-- comment delimiters separated by a '|' character. -- @class table -- @name comment_string -- @see toggle_comment M.comment_string = {actionscript='//',ada='--',apdl='!',ansi_c='/*|*/',antlr='//',apl='#',applescript='--',asp='\'',autoit=';',awk='#',b_lang='//',bash='#',batch=':',bibtex='%',boo='#',chuck='//',clojure=';',cmake='#',coffeescript='#',context='%',cpp='//',crystal='#',csharp='//',css='/*|*/',cuda='//',desktop='#',django='{#|#}',dmd='//',dockerfile='#',dot='//',eiffel='--',elixir='#',elm='--',erlang='%',fantom='//',faust='//',fennel=';',fish='#',forth='|\\',fortran='!',fsharp='//',fstab='#',gap='#',gettext='#',gherkin='#',glsl='//',gnuplot='#',go='//',groovy='//',gtkrc='#',haskell='--',html='<!--|-->',icon='#',idl='//',inform='!',ini='#',Io='#',java='//',javascript='//',jq='#',json='/*|*/',jsp='//',julia='#',latex='%',ledger='#',less='//',lilypond='%',lisp=';',logtalk='%',lua='--',makefile='#',matlab='#',meson='#',moonscript='--',myrddin='//',nemerle='//',networkd='#',nim='#',nsis='#',objective_c='//',pascal='//',perl='#',php='//',pico8='//',pike='//',pkgbuild='#',pony='//',prolog='%',props='#',protobuf='//',ps='%',pure='//',python='#',rails='#',rc='#',reason='//',rebol=';',rest='.. ',rexx='--',rhtml='<!--|-->',routeros='#',rstats='#',ruby='#',rust='//',sass='//',scala='//',scheme=';',smalltalk='"|"',sml='(*)',snobol4='#',spin="'",sql='--',systemd='#',tcl='#',tex='%',text='',toml='#',typescript='//',vala='//',vb='\'',vbscript='\'',verilog='//',vhdl='--',wsf='<!--|-->',xml='<!--|-->',xs='#',xtend='//',yaml='#',zig='//'} +-- LuaFormatter on --- -- Map of auto-paired characters like parentheses, brackets, braces, and quotes. --- The ASCII values of opening characters are assigned to strings that contain --- complement characters. The default auto-paired characters are "()", "[]", --- "{}", "''", and """". +-- The ASCII values of opening characters are assigned to strings that contain complement +-- characters. The default auto-paired characters are "()", "[]", "{}", "''", and +-- """". -- @class table -- @name auto_pairs -- @usage textadept.editing.auto_pairs[60] = '>' -- pair '<' and '>' @@ -90,8 +93,8 @@ M.auto_pairs = {[40] = ')', [91] = ']', [123] = '}', [39] = "'", [34] = '"'} --- -- Table of brace characters to highlight. --- The ASCII values of brace characters are keys and are assigned non-`nil` --- values. The default brace characters are '(', ')', '[', ']', '{', and '}'. +-- The ASCII values of brace characters are keys and are assigned non-`nil` values. The default +-- brace characters are '(', ')', '[', ']', '{', and '}'. -- @class table -- @name brace_matches -- @usage textadept.editing.brace_matches[60] = true -- '<' @@ -100,8 +103,8 @@ M.brace_matches = {[40] = 1, [41] = 1, [91] = 1, [93] = 1, [123] = 1, [125] = 1} --- -- Table of characters to move over when typed. --- The ASCII values of characters are keys and are assigned non-`nil` values. --- The default characters are ')', ']', '}', ''', and '"'. +-- The ASCII values of characters are keys and are assigned non-`nil` values. The default +-- characters are ')', ']', '}', ''', and '"'. -- @class table -- @name typeover_chars -- @usage textadept.editing.typeover_chars[62] = true -- '>' @@ -109,12 +112,10 @@ M.typeover_chars = {[41] = 1, [93] = 1, [125] = 1, [39] = 1, [34] = 1} --- -- Map of autocompleter names to autocompletion functions. --- Names are typically lexer names and autocompletion functions typically --- autocomplete symbols. --- Autocompletion functions must return two values: the number of characters --- behind the caret that are used as the prefix of the entity to be --- autocompleted, and a list of completions to be shown. Autocompletion lists --- are sorted automatically. +-- Names are typically lexer names and autocompletion functions typically autocomplete symbols. +-- Autocompletion functions must return two values: the number of characters behind the caret +-- that are used as the prefix of the entity to be autocompleted, and a list of completions to +-- be shown. Autocompletion lists are sorted automatically. -- @class table -- @name autocompleters -- @see autocomplete @@ -122,20 +123,20 @@ M.autocompleters = {} --- -- Map of lexer names to API documentation file tables. --- File tables contain API file paths or functions that return such paths. --- Each line in an API file consists of a symbol name (not a fully qualified --- symbol name), a space character, and that symbol's documentation. "\n" --- represents a newline character. +-- File tables contain API file paths or functions that return such paths. Each line in an +-- API file consists of a symbol name (not a fully qualified symbol name), a space character, +-- and that symbol's documentation. "\n" represents a newline character. -- @class table -- @name api_files -- @see show_documentation -M.api_files = setmetatable({}, {__index = function(t, k) - t[k] = {} - return t[k] -end}) +M.api_files = setmetatable({}, { + __index = function(t, k) + t[k] = {} + return t[k] + end +}) --- Matches characters specified in auto_pairs, taking multiple selections into --- account. +-- Matches characters specified in auto_pairs, taking multiple selections into account. events.connect(events.CHAR_ADDED, function(code) if not M.auto_pairs or not M.auto_pairs[code] then return end buffer:begin_undo_action() @@ -149,8 +150,7 @@ end) -- Removes matched chars on backspace, taking multiple selections into account. events.connect(events.KEYPRESS, function(code) - if M.auto_pairs and keys.KEYSYMS[code] == '\b' and - not ui.command_entry.active then + if M.auto_pairs and keys.KEYSYMS[code] == '\b' and not ui.command_entry.active then buffer:begin_undo_action() for i = 1, buffer.selections do local pos = buffer.selection_n_caret[i] @@ -206,17 +206,14 @@ events.connect(events.UPDATE_UI, function(updated) buffer.search_flags = buffer.FIND_MATCHCASE | buffer.FIND_WHOLEWORD buffer:target_whole_document() while buffer:search_in_target(word) ~= -1 do - buffer:indicator_fill_range( - buffer.target_start, buffer.target_end - buffer.target_start) + buffer:indicator_fill_range(buffer.target_start, buffer.target_end - buffer.target_start) buffer:set_target_range(buffer.target_end, buffer.length + 1) end end) --- Moves over typeover characters when typed, taking multiple selections into --- account. +-- Moves over typeover characters when typed, taking multiple selections into account. events.connect(events.KEYPRESS, function(code) - if M.typeover_chars and M.typeover_chars[code] and - not ui.command_entry.active then + if M.typeover_chars and M.typeover_chars[code] and not ui.command_entry.active then local handled = false for i = 1, buffer.selections do local s, e = buffer.selection_n_start[i], buffer.selection_n_end[i] @@ -234,7 +231,7 @@ events.connect(events.CHAR_ADDED, function(code) if not M.auto_indent or code ~= string.byte('\n') then return end local line = buffer:line_from_position(buffer.current_pos) if line > 1 and buffer:get_line(line - 1):find('^[\r\n]+$') and - buffer:get_line(line):find('^[^\r\n]') then + buffer:get_line(line):find('^[^\r\n]') then return -- do not auto-indent when pressing enter from start of previous line end local i = line - 1 @@ -245,8 +242,8 @@ events.connect(events.CHAR_ADDED, function(code) end end) --- Enables and disables bracketed paste mode in curses and disables auto-pair --- and auto-indent while pasting. +-- Enables and disables bracketed paste mode in curses and disables auto-pair and auto-indent +-- while pasting. if CURSES and not WIN32 then local function enable_br_paste() io.stdout:write('\x1b[?2004h'):flush() end local function disable_br_paste() io.stdout:write('\x1b[?2004l'):flush() end @@ -267,8 +264,8 @@ if CURSES and not WIN32 then end) end --- Prepares the buffer for saving to a file by stripping trailing whitespace, --- ensuring a final newline, and normalizing line endings. +-- Prepares the buffer for saving to a file by stripping trailing whitespace, ensuring a final +-- newline, and normalizing line endings. events.connect(events.FILE_BEFORE_SAVE, function() if not M.strip_trailing_spaces or not buffer.encoding then return end buffer:begin_undo_action() @@ -289,8 +286,8 @@ events.connect(events.FILE_BEFORE_SAVE, function() end) --- --- Pastes the text from the clipboard, taking into account the buffer's --- indentation settings and the indentation of the current and preceding lines. +-- Pastes the text from the clipboard, taking into account the buffer's indentation settings +-- and the indentation of the current and preceding lines. -- @name paste_reindent function M.paste_reindent() local line = buffer:line_from_position(buffer.selection_start) @@ -307,31 +304,25 @@ function M.paste_reindent() text = text:gsub('\n([ \t]+)', function(indentation) if indentation:find('^\t') then return buffer.use_tabs and '\n' .. indentation or - '\n' .. indentation:gsub('\t', string.rep(' ', buffer.tab_width)) + ('\n' .. indentation:gsub('\t', string.rep(' ', buffer.tab_width))) else tab_width = math.min(tab_width, #indentation) local indent = math.floor(#indentation / tab_width) local spaces = string.rep(' ', math.fmod(#indentation, tab_width)) - return string.format( - '\n%s%s', buffer.use_tabs and string.rep('\t', indent) or + return string.format('\n%s%s', buffer.use_tabs and string.rep('\t', indent) or string.rep(' ', buffer.tab_width):rep(indent), spaces) end end) - -- Re-indent according to whichever of the current and preceding lines has the - -- higher indentation amount. However, if the preceding line is a fold header, - -- indent by an extra level. + -- Re-indent according to whichever of the current and preceding lines has the higher indentation + -- amount. However, if the preceding line is a fold header, indent by an extra level. local i = line - 1 while i >= 1 and buffer:get_line(i):find('^[\r\n]+$') do i = i - 1 end - if i < 1 or buffer.line_indentation[i] < buffer.line_indentation[line] then - i = line - end - local indentation = buffer:text_range( - buffer:position_from_line(i), buffer.line_indent_position[i]) - local fold_header = - i ~= line and buffer.fold_level[i] & buffer.FOLDLEVELHEADERFLAG > 0 + if i < 1 or buffer.line_indentation[i] < buffer.line_indentation[line] then i = line end + local indentation = + buffer:text_range(buffer:position_from_line(i), buffer.line_indent_position[i]) + local fold_header = i ~= line and buffer.fold_level[i] & buffer.FOLDLEVELHEADERFLAG > 0 if fold_header then - indentation = indentation .. - (buffer.use_tabs and '\t' or string.rep(' ', buffer.tab_width)) + indentation = indentation .. (buffer.use_tabs and '\t' or string.rep(' ', buffer.tab_width)) end text = text:gsub('\n', '\n' .. indentation) -- Paste the text and adjust first and last line indentation accordingly. @@ -374,9 +365,7 @@ function M.toggle_comment() local uncomment = buffer:text_range(p, p + #prefix) == prefix if not uncomment then buffer:insert_text(p, prefix) - if suffix ~= '' then - buffer:insert_text(buffer.line_end_position[line], suffix) - end + if suffix ~= '' then buffer:insert_text(buffer.line_end_position[line], suffix) end else buffer:delete_range(p, #prefix) if suffix ~= '' then @@ -392,20 +381,23 @@ function M.toggle_comment() -- Keep the anchor and caret on the first line as necessary. local start_pos = buffer:position_from_line(s) anchor, pos = math.max(anchor, start_pos), math.max(pos, start_pos) - if s ~= e then buffer:set_sel(anchor, pos) else buffer:goto_pos(pos) end + if s ~= e then + buffer:set_sel(anchor, pos) + else + buffer:goto_pos(pos) + end end --- --- Moves the caret to the beginning of line number *line* or the user-specified --- line, ensuring *line* is visible. --- @param line Optional line number to go to. If `nil`, the user is prompted for --- one. +-- Moves the caret to the beginning of line number *line* or the user-specified line, ensuring +-- *line* is visible. +-- @param line Optional line number to go to. If `nil`, the user is prompted for one. -- @name goto_line function M.goto_line(line) if not assert_type(line, 'number/nil', 1) then local button, value = ui.dialogs.inputbox{ - title = _L['Go To'], informative_text = _L['Line Number:'], - button1 = _L['OK'], button2 = _L['Cancel'] + title = _L['Go To'], informative_text = _L['Line Number:'], button1 = _L['OK'], + button2 = _L['Cancel'] } line = tonumber(value) if button ~= 1 or not line then return end @@ -413,14 +405,13 @@ function M.goto_line(line) view:ensure_visible_enforce_policy(line) buffer:goto_line(line) end -args.register('-l', '--line', 1, function(line) - M.goto_line(tonumber(line) or line) -end, 'Go to line') +args.register('-l', '--line', 1, function(line) M.goto_line(tonumber(line) or line) end, + 'Go to line') --- -- Transposes characters intelligently. --- If the caret is at the end of a line, transposes the two characters before --- the caret. Otherwise, the characters to the left and right are. +-- If the caret is at the end of a line, transposes the two characters before the caret. Otherwise, +-- the characters to the left and right are. -- @name transpose_chars function M.transpose_chars() local pos = buffer.current_pos @@ -434,10 +425,8 @@ function M.transpose_chars() end --- --- Joins the currently selected lines or the current line with the line below --- it. --- As long as any part of a line is selected, the entire line is eligible for --- joining. +-- Joins the currently selected lines or the current line with the line below it. +-- As long as any part of a line is selected, the entire line is eligible for joining. -- @name join_lines function M.join_lines() buffer:target_from_selection() @@ -450,8 +439,8 @@ function M.join_lines() end --- --- Encloses the selected text or the current word within strings *left* and --- *right*, taking multiple selections into account. +-- Encloses the selected text or the current word within strings *left* and *right*, taking +-- multiple selections into account. -- @param left The left part of the enclosure. -- @param right The right part of the enclosure. -- @name enclose @@ -475,8 +464,8 @@ end -- Enclose selected text in punctuation or auto-paired characters. events.connect(events.KEYPRESS, function(code, shift, ctrl, alt, cmd) - if M.auto_enclose and not buffer.selection_empty and code < 256 and - not ctrl and not alt and not cmd and not ui.command_entry.active then + if M.auto_enclose and not buffer.selection_empty and code < 256 and not ctrl and not alt and + not cmd and not ui.command_entry.active then local char = string.char(code) if char:find('^%P') then return end -- not punctuation M.enclose(char, M.auto_pairs[code] or char) @@ -486,11 +475,9 @@ end, 1) --- -- Selects the text between strings *left* and *right* that enclose the caret. --- If that range is already selected, toggles between selecting *left* and --- *right* as well. --- If *left* and *right* are not provided, they are assumed to be one of the --- delimiter pairs specified in `auto_pairs` and are inferred from the current --- position or selection. +-- If that range is already selected, toggles between selecting *left* and *right* as well. +-- If *left* and *right* are not provided, they are assumed to be one of the delimiter pairs +-- specified in `auto_pairs` and are inferred from the current position or selection. -- @param left Optional left part of the enclosure. -- @param right Optional right part of the enclosure. -- @see auto_pairs @@ -511,7 +498,7 @@ function M.select_enclosed(left, right) e = buffer:brace_match(s, 0) break elseif M.brace_matches[buffer.char_at[s]] or - buffer.style_at[s] == buffer.style_at[buffer.selection_start] then + (buffer.style_at[s] == buffer.style_at[buffer.selection_start]) then buffer.search_flags = 0 buffer:set_target_range(s + 1, buffer.length + 1) if buffer:search_in_target(match) >= buffer.selection_end - 1 then @@ -529,19 +516,16 @@ function M.select_enclosed(left, right) end --- --- Selects the current word or, if *all* is `true`, all occurrences of the --- current word. --- If a word is already selected, selects the next occurrence as a multiple --- selection. --- @param all Whether or not to select all occurrences of the current word. --- The default value is `false`. +-- Selects the current word or, if *all* is `true`, all occurrences of the current word. +-- If a word is already selected, selects the next occurrence as a multiple selection. +-- @param all Whether or not to select all occurrences of the current word. The default value is +-- `false`. -- @see buffer.word_chars -- @name select_word function M.select_word(all) buffer:target_whole_document() buffer.search_flags = buffer.FIND_MATCHCASE - if buffer.selection_empty or - buffer:is_range_word(buffer.selection_start, buffer.selection_end) then + if buffer.selection_empty or buffer:is_range_word(buffer.selection_start, buffer.selection_end) then buffer.search_flags = buffer.search_flags | buffer.FIND_WHOLEWORD if all then buffer:multiple_select_add_next() end -- select word first end @@ -568,9 +552,8 @@ end --- -- Converts indentation between tabs and spaces according to `buffer.use_tabs`. --- If `buffer.use_tabs` is `true`, `buffer.tab_width` indenting spaces are --- converted to tabs. Otherwise, all indenting tabs are converted to --- `buffer.tab_width` spaces. +-- If `buffer.use_tabs` is `true`, `buffer.tab_width` indenting spaces are converted to tabs. +-- Otherwise, all indenting tabs are converted to `buffer.tab_width` spaces. -- @see buffer.use_tabs -- @name convert_indentation function M.convert_indentation() @@ -596,20 +579,19 @@ function M.convert_indentation() end --- --- Passes the selected text or all buffer text to string shell command *command* --- as standard input (stdin) and replaces the input text with the command's --- standard output (stdout). *command* may contain shell pipes ('|'). +-- Passes the selected text or all buffer text to string shell command *command* as standard input +-- (stdin) and replaces the input text with the command's standard output (stdout). *command* +-- may contain shell pipes ('|'). -- Standard input is as follows: -- -- 1. If no text is selected, the entire buffer is used. --- 2. If text is selected and spans a single line, only the selected text is --- used. --- 3. If text is selected and spans multiple lines, all text on the lines that --- have text selected is passed as stdin. However, if the end of the selection --- is at the beginning of a line, only the line ending delimiters from the --- previous line are included. The rest of the line is excluded. --- @param command The Linux, BSD, macOS, or Windows shell command to filter text --- through. May contain pipes. +-- 2. If text is selected and spans a single line, only the selected text is used. +-- 3. If text is selected and spans multiple lines, all text on the lines that have text selected +-- is passed as stdin. However, if the end of the selection is at the beginning of a line, +-- only the line ending delimiters from the previous line are included. The rest of the line +-- is excluded. +-- @param command The Linux, BSD, macOS, or Windows shell command to filter text through. May +-- contain pipes. -- @name filter_through function M.filter_through(command) assert(not (WIN32 and CURSES), 'not implemented in this environment') @@ -627,12 +609,14 @@ function M.filter_through(command) end buffer:set_target_range(s, e) end + -- LuaFormatter off local commands = lpeg.match(lpeg.Ct(lpeg.P{ lpeg.C(lpeg.V('command')) * ('|' * lpeg.C(lpeg.V('command')))^0, command = (1 - lpeg.S('"\'|') + lpeg.V('str'))^1, str = '"' * (1 - lpeg.S('"\\') + lpeg.P('\\') * 1)^0 * lpeg.P('"')^-1 + - "'" * (1 - lpeg.S("'\\") + lpeg.P('\\') * 1)^0 * lpeg.P("'")^-1, + "'" * (1 - lpeg.S("'\\") + lpeg.P('\\') * 1)^0 * lpeg.P("'")^-1 }), command) + -- LuaFormatter on local output = buffer.target_text for i = 1, #commands do local p = assert(os.spawn(commands[i]:match('^%s*(.-)%s*$'))) @@ -640,21 +624,23 @@ function M.filter_through(command) p:close() output = p:read('a') or '' if p:wait() ~= 0 then - ui.statusbar_text = string.format( - '"%s" %s', commands[i], _L['returned non-zero status']) + ui.statusbar_text = string.format('"%s" %s', commands[i], _L['returned non-zero status']) return end end buffer:replace_target(output:iconv('UTF-8', _CHARSET)) - if s == e then buffer:goto_pos(s) return end + if s == e then + buffer:goto_pos(s) + return + end buffer:set_sel(buffer.target_start, buffer.target_end) end --- --- Displays an autocompletion list provided by the autocompleter function --- associated with string *name*, and returns `true` if completions were found. --- @param name The name of an autocompleter function in the `autocompleters` --- table to use for providing autocompletions. +-- Displays an autocompletion list provided by the autocompleter function associated with string +-- *name*, and returns `true` if completions were found. +-- @param name The name of an autocompleter function in the `autocompleters` table to use for +-- providing autocompletions. -- @name autocomplete -- @see autocompleters function M.autocomplete(name) @@ -662,14 +648,12 @@ function M.autocomplete(name) local len_entered, list = M.autocompleters[name]() if not len_entered or not list or #list == 0 then return end buffer.auto_c_order = buffer.ORDER_PERFORMSORT - buffer:auto_c_show( - len_entered, table.concat(list, string.char(buffer.auto_c_separator))) + buffer:auto_c_show(len_entered, table.concat(list, string.char(buffer.auto_c_separator))) return true end --- Returns for the word part behind the caret a list of whole word completions --- constructed from the current buffer or all open buffers (depending on --- `M.autocomplete_all_words`). +-- Returns for the word part behind the caret a list of whole word completions constructed from +-- the current buffer or all open buffers (depending on `M.autocomplete_all_words`). -- If `buffer.auto_c_ignore_case` is `true`, completions are not case-sensitive. -- @see buffer.word_chars -- @see autocomplete @@ -698,20 +682,23 @@ end local api_docs --- --- Displays a call tip with documentation for the symbol under or directly --- behind position *pos* or the caret position. +-- Displays a call tip with documentation for the symbol under or directly behind position *pos* +-- or the caret position. -- Documentation is read from API files in the `api_files` table. -- If a call tip is already shown, cycles to the next one if it exists. -- Symbols are determined by using `buffer.word_chars`. --- @param pos Optional position of the symbol to show documentation for. If --- omitted, the caret position is used. --- @param ignore_case Optional flag that indicates whether or not to search --- API files case-insensitively for symbols. The default value is `false`. +-- @param pos Optional position of the symbol to show documentation for. If omitted, the caret +-- position is used. +-- @param ignore_case Optional flag that indicates whether or not to search API files +-- case-insensitively for symbols. The default value is `false`. -- @name show_documentation -- @see api_files -- @see buffer.word_chars function M.show_documentation(pos, ignore_case) - if view:call_tip_active() then events.emit(events.CALL_TIP_CLICK) return end + if view:call_tip_active() then + events.emit(events.CALL_TIP_CLICK) + return + end local api_files = M.api_files[buffer:get_lexer(true)] if not api_files then return end if not assert_type(pos, 'number/nil', 1) then pos = buffer.current_pos end @@ -739,8 +726,8 @@ function M.show_documentation(pos, ignore_case) ::continue:: end end - -- Search backwards for an open function call and show API documentation for - -- that function as well. + -- Search backwards for an open function call and show API documentation for that function + -- as well. while s > 1 and buffer.char_at[s] ~= 40 do s = s - 1 end -- '(' e = buffer:brace_match(s, 0) if s > 1 and (e == -1 or e >= pos) then diff --git a/modules/textadept/file_types.lua b/modules/textadept/file_types.lua index bd5a8a04..ac9c88f9 100644 --- a/modules/textadept/file_types.lua +++ b/modules/textadept/file_types.lua @@ -7,8 +7,8 @@ local M = {} -- Handles file type detection for Textadept. -- @field _G.events.LEXER_LOADED (string) -- Emitted after loading a language lexer. --- This is useful for overriding a language module's key bindings or other --- properties since the module is not loaded when Textadept starts. +-- This is useful for overriding a language module's key bindings or other properties since +-- the module is not loaded when Textadept starts. -- Arguments: -- -- * _`name`_: The language lexer's name. @@ -17,10 +17,11 @@ module('textadept.file_types')]] -- Events. events.LEXER_LOADED = 'lexer_loaded' +-- LuaFormatter off --- -- Map of file extensions to their associated lexer names. --- If the file type is not recognized by its first-line, each file extension is --- matched against the file's extension. +-- If the file type is not recognized by its first-line, each file extension is matched against +-- the file's extension. -- @class table -- @name extensions M.extensions = {--[[Actionscript]]as='actionscript',asc='actionscript',--[[Ada]]adb='ada',ads='ada',--[[ANTLR]]g='antlr',g4='antlr',--[[APDL]]ans='apdl',inp='apdl',mac='apdl',--[[APL]]apl='apl',--[[Applescript]]applescript='applescript',--[[ASM]]asm='asm',ASM='asm',s='asm',S='asm',--[[ASP]]asa='asp',asp='asp',hta='asp',--[[AutoIt]]au3='autoit',a3x='autoit',--[[AWK]]awk='awk',--[[Batch]]bat='batch',cmd='batch',--[[BibTeX]]bib='bibtex',--[[Boo]]boo='boo',--[[C#]]cs='csharp',--[[C/C++]]c='ansi_c',cc='cpp',C='ansi_c',cpp='cpp',cxx='cpp',['c++']='cpp',h='cpp',hh='cpp',hpp='cpp',hxx='cpp',['h++']='cpp',--[[ChucK]]ck='chuck',--[[Clojure]]clj='clojure',cljs='clojure',cljc='clojure',edn='clojure',--[[CMake]]cmake='cmake',['cmake.in']='cmake',ctest='cmake',['ctest.in']='cmake',--[[CoffeeScript]]coffee='coffeescript',--[[Crystal]]cr='crystal',--[[CSS]]css='css',--[[CUDA]]cu='cuda',cuh='cuda',--[[D]]d='dmd',di='dmd',--[[Dart]]dart='dart',--[[Desktop]]desktop='desktop',--[[diff]]diff='diff',patch='diff',--[[Dockerfile]]Dockerfile='dockerfile',--[[dot]]dot='dot',--[[Eiffel]]e='eiffel',eif='eiffel',--[[Elixir]]ex='elixir',exs='elixir',--[[Elm]]elm='elm',--[[Erlang]]erl='erlang',hrl='erlang',--[[F#]]fs='fsharp',--[[Fantom]]fan='fantom',--[[Faust]]dsp='faust',--[[Fennel]]fnl='fennel',--[[Fish]]fish='fish',--[[Forth]]forth='forth',frt='forth',--[[Fortran]]f='fortran',['for']='fortran',ftn='fortran',fpp='fortran',f77='fortran',f90='fortran',f95='fortran',f03='fortran',f08='fortran',--[[fstab]]fstab='fstab',--[[Gap]]g='gap',gd='gap',gi='gap',gap='gap',--[[Gettext]]po='gettext',pot='gettext',--[[Gherkin]]feature='gherkin',--[[GLSL]]glslf='glsl',glslv='glsl',--[[GNUPlot]]dem='gnuplot',plt='gnuplot',--[[Go]]go='go',--[[Groovy]]groovy='groovy',gvy='groovy',--[[Gtkrc]]gtkrc='gtkrc',--[[Haskell]]hs='haskell',--[[HTML]]htm='html',html='html',shtm='html',shtml='html',xhtml='html',vue='html',--[[Icon]]icn='icon',--[[IDL]]idl='idl',odl='idl',--[[Inform]]inf='inform',ni='inform',--[[ini]]cfg='ini',cnf='ini',inf='ini',ini='ini',reg='ini',--[[Io]]io='io_lang',--[[Java]]bsh='java',java='java',--[[Javascript]]js='javascript',jsfl='javascript',--[[jq]]jq='jq',--[[JSON]]json='json',--[[JSP]]jsp='jsp',--[[Julia]]jl='julia',--[[LaTeX]]bbl='latex',dtx='latex',ins='latex',ltx='latex',tex='latex',sty='latex',--[[Ledger]]ledger='ledger',journal='ledger',--[[LESS]]less='less',--[[LilyPond]]lily='lilypond',ly='lilypond',--[[Lisp]]cl='lisp',el='lisp',lisp='lisp',lsp='lisp',--[[Literate Coffeescript]]litcoffee='litcoffee',--[[Logtalk]]lgt='logtalk',--[[Lua]]lua='lua',--[[Makefile]]GNUmakefile='makefile',iface='makefile',mak='makefile',makefile='makefile',Makefile='makefile',--[[Man]]['1']='man',['2']='man',['3']='man',['4']='man',['5']='man',['6']='man',['7']='man',['8']='man',['9']='man',['1x']='man',['2x']='man',['3x']='man',['4x']='man',['5x']='man',['6x']='man',['7x']='man',['8x']='man',['9x']='man',--[[Markdown]]md='markdown',--[[Meson]]['meson.build']='meson',--[[MoonScript]]moon='moonscript',--[[Myrddin]]myr='myrddin',--[[Nemerle]]n='nemerle',--[[Networkd]]link='networkd',network='networkd',netdev='networkd',--[[Nim]]nim='nim',--[[NSIS]]nsh='nsis',nsi='nsis',nsis='nsis',--[[Objective C]]m='objective_c',mm='objective_c',objc='objective_c',--[[OCaml]]caml='caml',ml='caml',mli='caml',mll='caml',mly='caml',--[[Pascal]]dpk='pascal',dpr='pascal',p='pascal',pas='pascal',--[[Perl]]al='perl',perl='perl',pl='perl',pm='perl',pod='perl',--[[PHP]]inc='php',php='php',php3='php',php4='php',phtml='php',--[[PICO-8]]p8='pico8',--[[Pike]]pike='pike',pmod='pike',--[[PKGBUILD]]PKGBUILD='pkgbuild',--[[Pony]]pony='pony',--[[Postscript]]eps='ps',ps='ps',--[[PowerShell]]ps1='powershell',--[[Prolog]]prolog='prolog',--[[Properties]]props='props',properties='props',--[[Protobuf]]proto='protobuf',--[[Pure]]pure='pure',--[[Python]]sc='python',py='python',pyw='python',--[[R]]R='rstats',Rout='rstats',Rhistory='rstats',Rt='rstats',['Rout.save']='rstats',['Rout.fail']='rstats',S='rstats',--[[Reason]]re='reason',--[[REBOL]]r='rebol',reb='rebol',--[[reST]]rst='rest',--[[Rexx]]orx='rexx',rex='rexx',--[[RHTML]]erb='rhtml',rhtml='rhtml',--[[RouterOS]]rsc='routeros',--[[Ruby]]Rakefile='ruby',rake='ruby',rb='ruby',rbw='ruby',--[[Rust]]rs='rust',--[[Sass CSS]]sass='sass',scss='sass',--[[Scala]]scala='scala',--[[Scheme]]sch='scheme',scm='scheme',--[[Shell]]bash='bash',bashrc='bash',bash_profile='bash',configure='bash',csh='bash',ksh='bash',mksh='bash',sh='bash',zsh='bash',--[[Smalltalk]]changes='smalltalk',st='smalltalk',sources='smalltalk',--[[SML]]sml='sml',fun='sml',sig='sml',--[[SNOBOL4]]sno='snobol4',SNO='snobol4',--[[Spin]]spin='spin',--[[SQL]]ddl='sql',sql='sql',--[[Systemd]]automount='systemd',device='systemd',mount='systemd',path='systemd',scope='systemd',service='systemd',slice='systemd',socket='systemd',swap='systemd',target='systemd',timer='systemd',--[[TaskPaper]]taskpaper='taskpaper',--[[Tcl]]tcl='tcl',tk='tcl',--[[Texinfo]]texi='texinfo',--[[TOML]]toml='toml',--[[Txt2tags]]t2t='txt2tags',--[[TypeScript]]ts='typescript',--[[Vala]]vala='vala',--[[vCard]]vcf='vcard',vcard='vcard',--[[Verilog]]v='verilog',ver='verilog',--[[VHDL]]vh='vhdl',vhd='vhdl',vhdl='vhdl',--[[Visual Basic]]asa='vb',bas='vb',cls='vb',ctl='vb',dob='vb',dsm='vb',dsr='vb',frm='vb',pag='vb',vb='vb',vba='vb',vbs='vb',--[[WSF]]wsf='wsf',--[[XML]]dtd='xml',svg='xml',xml='xml',xsd='xml',xsl='xml',xslt='xml',xul='xml',--[[Xs]]xs='xs',xsin='xs',xsrc='xs',--[[Xtend]]xtend='xtend',--[[YAML]]yaml='yaml',yml='yaml',--[[Zig]]zig='zig'} @@ -31,6 +32,7 @@ M.extensions = {--[[Actionscript]]as='actionscript',asc='actionscript',--[[Ada]] -- @class table -- @name patterns M.patterns = {['^#!.+[/ ][gm]?awk']='awk',['^#!.+[/ ]lua']='lua',['^#!.+[/ ]octave']='matlab',['^#!.+[/ ]perl']='perl',['^#!.+[/ ]php']='php',['^#!.+[/ ]python']='python',['^#!.+[/ ]ruby']='ruby',['^#!.+[/ ]bash']='bash',['^#!.+/m?ksh']='bash',['^#!.+/sh']='bash',['^%s*class%s+%S+%s*<%s*ApplicationController']='rails',['^%s*class%s+%S+%s*<%s*ActionController::Base']='rails',['^%s*class%s+%S+%s*<%s*ActiveRecord::Base']='rails',['^%s*class%s+%S+%s*<%s*ActiveRecord::Migration']='rails',['^%s*<%?xml%s']='xml',['^#cloud%-config']='yaml'} +-- LuaFormatter on local GETLEXERLANGUAGE = _SCINTILLA.properties.lexer_language[1] -- LuaDoc is in core/.buffer.luadoc. @@ -39,16 +41,13 @@ local function get_lexer(buffer, current) return current and name:match('[^/]+$') or name:match('^[^/]+') end --- Attempts to detect the language based on a buffer's first line of text or --- that buffer's filename. +-- Attempts to detect the language based on a buffer's first line of text or that buffer's filename. -- @param buffer The buffer to detect the language of. -- @return lexer name or nil local function detect_language(buffer) local line = buffer:get_line(1) -- Detect from first line. - for patt, lexer_name in pairs(M.patterns) do - if line:find(patt) then return lexer_name end - end + for patt, lexer_name in pairs(M.patterns) do if line:find(patt) then return lexer_name end end -- Detect from file extension. return buffer.filename and M.extensions[buffer.filename:match('[^/\\.]+$')] end @@ -75,18 +74,15 @@ local function set_lexer(buffer, name) end -- Gives new buffers lexer-specific functions. -events.connect(events.BUFFER_NEW, function() - buffer.get_lexer, buffer.set_lexer = get_lexer, set_lexer -end, 1) +events.connect(events.BUFFER_NEW, + function() buffer.get_lexer, buffer.set_lexer = get_lexer, set_lexer end, 1) -- Auto-detect lexer on file open or save as. events.connect(events.FILE_OPENED, function() buffer:set_lexer() end) -events.connect(events.FILE_AFTER_SAVE, function(_, saved_as) - if saved_as then buffer:set_lexer() end -end) +events.connect(events.FILE_AFTER_SAVE, + function(_, saved_as) if saved_as then buffer:set_lexer() end end) --- Restores the buffer's lexer, primarily for the side-effect of emitting --- `events.LEXER_LOADED`. +-- Restores the buffer's lexer, primarily for the side-effect of emitting `events.LEXER_LOADED`. local function restore_lexer() buffer:set_lexer(buffer._lexer) end events.connect(events.BUFFER_AFTER_SWITCH, restore_lexer, 1) events.connect(events.VIEW_AFTER_SWITCH, restore_lexer) @@ -100,9 +96,7 @@ local LEXERNAMES = _SCINTILLA.functions.property_names[1] -- @name select_lexer function M.select_lexer() local lexers = {} - for name in buffer:private_lexer_call(LEXERNAMES):gmatch('[^\n]+') do - lexers[#lexers + 1] = name - end + for name in buffer:private_lexer_call(LEXERNAMES):gmatch('[^\n]+') do lexers[#lexers + 1] = name end local button, i = ui.dialogs.filteredlist{ title = _L['Select Lexer'], columns = _L['Name'], items = lexers } diff --git a/modules/textadept/find.lua b/modules/textadept/find.lua index 31624503..0d90885f 100644 --- a/modules/textadept/find.lua +++ b/modules/textadept/find.lua @@ -9,14 +9,12 @@ local M = ui.find -- The text in the "Find" entry. -- @field replace_entry_text (string) -- The text in the "Replace" entry. --- When searching for text in a directory of files, this is the current file --- and directory filter. +-- When searching for text in a directory of files, this is the current file and directory filter. -- @field match_case (bool) -- Match search text case sensitively. -- The default value is `false`. -- @field whole_word (bool) --- Match search text only when it is surrounded by non-word characters in --- searches. +-- Match search text only when it is surrounded by non-word characters in searches. -- The default value is `false`. -- @field regex (bool) -- Interpret search text as a Regular Expression. @@ -60,23 +58,21 @@ local M = ui.find -- @field active (boolean) -- Whether or not the Find & Replace pane is active. -- @field highlight_all_matches (boolean) --- Whether or not to highlight all occurrences of found text in the current --- buffer. +-- Whether or not to highlight all occurrences of found text in the current buffer. -- The default value is `false`. -- @field INDIC_FIND (number) -- The find results highlight indicator number. -- @field _G.events.FIND_RESULT_FOUND (string) --- Emitted when a result is found. It is selected and has been scrolled into --- view. +-- Emitted when a result is found. It is selected and has been scrolled into view. -- Arguments: -- -- * _`find_text`_: The text originally searched for. -- @field _G.events.FIND_WRAPPED (string) --- Emitted when a text search wraps (passes through the beginning of the --- buffer), either from bottom to top (when searching for a next occurrence), --- or from top to bottom (when searching for a previous occurrence). --- This is useful for implementing a more visual or audible notice when a --- search wraps in addition to the statusbar message. +-- Emitted when a text search wraps (passes through the beginning of the buffer), either +-- from bottom to top (when searching for a next occurrence), or from top to bottom (when +-- searching for a previous occurrence). +-- This is useful for implementing a more visual or audible notice when a search wraps in +-- addition to the statusbar message. module('ui.find')]] local _L = _L @@ -97,31 +93,29 @@ M.INDIC_FIND = _SCINTILLA.next_indic_number() local find_events = {'find_result_found', 'find_wrapped'} for _, v in ipairs(find_events) do events[v:upper()] = v end --- When finding in files, note the current view since results are shown in a --- split view. Jumping between results should be done in the original view. +-- When finding in files, note the current view since results are shown in a split view. Jumping +-- between results should be done in the original view. local preferred_view --- -- Map of directory paths to filters used in `ui.find.find_in_files()`. --- This table is updated when the user manually specifies a filter in the --- "Filter" entry during an "In files" search. +-- This table is updated when the user manually specifies a filter in the "Filter" entry during +-- an "In files" search. -- @class table -- @name find_in_files_filters -- @see find_in_files M.find_in_files_filters = {} --- Keep track of find text and found text so that "replace all" works as --- expected during a find session ("replace all" with selected text normally --- does "replace in selection"). Also track find text for incremental find (if --- text has changed, the user is still typing; if text is the same, the user --- clicked "Find Next" or "Find Prev"). Keep track of repl_text for --- non-"In files" in order to restore it from filter text as necessary. +-- Keep track of find text and found text so that "replace all" works as expected during a find +-- session ("replace all" with selected text normally does "replace in selection"). Also track +-- find text for incremental find (if text has changed, the user is still typing; if text is +-- the same, the user clicked "Find Next" or "Find Prev"). Keep track of repl_text for non-"In +-- files" in order to restore it from filter text as necessary. local find_text, found_text, repl_text = nil, nil, ui.find.replace_entry_text -- Returns a reasonable initial directory for use with Find in Files. local function ff_dir() - return io.get_project_root() or (buffer.filename or ''):match('^.+[/\\]') or - lfs.currentdir() + return io.get_project_root() or (buffer.filename or ''):match('^.+[/\\]') or lfs.currentdir() end local orig_focus = M.focus @@ -139,22 +133,21 @@ function M.focus(options) if M.in_files then if not already_in_files then repl_text = M.replace_entry_text end -- save local filter = M.find_in_files_filters[ff_dir()] or lfs.default_filter - M.replace_entry_text = type(filter) == 'string' and filter or - table.concat(filter, ',') + M.replace_entry_text = type(filter) == 'string' and filter or table.concat(filter, ',') elseif M.replace_entry_text ~= repl_text then M.replace_entry_text = repl_text -- restore end orig_focus() end --- Returns a bit-mask of search flags to use in Scintilla search functions based --- on the checkboxes in the find box. +-- Returns a bit-mask of search flags to use in Scintilla search functions based on the checkboxes +-- in the find box. -- The "Find in Files" flag is unused by Scintilla, but used by Textadept. -- @return search flag bit-mask local function get_flags() return (M.match_case and buffer.FIND_MATCHCASE or 0) | - (M.whole_word and buffer.FIND_WHOLEWORD or 0) | - (M.regex and buffer.FIND_REGEXP or 0) | (M.in_files and 1 << 31 or 0) + (M.whole_word and buffer.FIND_WHOLEWORD or 0) | (M.regex and buffer.FIND_REGEXP or 0) | + (M.in_files and 1 << 31 or 0) end -- Returns whether or not the given buffer is a files found buffer. @@ -174,20 +167,22 @@ local incremental_orig_pos -- Finds and selects text in the current buffer. -- @param text The text to find. -- @param next Flag indicating whether or not the search direction is forward. --- @param flags Search flags. This is a bit-mask of 4 flags: --- `buffer.FIND_MATCHCASE`, `buffer.FIND_WHOLEWORD`, `buffer.FIND_REGEXP`, and --- 1 << 31 (in files), each joined with binary OR. --- If `nil`, this is determined based on the checkboxes in the find box. +-- @param flags Search flags. This is a bit-mask of 4 flags: `buffer.FIND_MATCHCASE`, +-- `buffer.FIND_WHOLEWORD`, `buffer.FIND_REGEXP`, and 1 << 31 (in files), each joined with +-- binary OR. If `nil`, this is determined based on the checkboxes in the find box. -- @param no_wrap Flag indicating whether or not the search will not wrap. --- @param wrapped Utility flag indicating whether or not the search has wrapped --- for displaying useful statusbar information. This flag is used and set --- internally, and should not be set otherwise. +-- @param wrapped Utility flag indicating whether or not the search has wrapped for displaying +-- useful statusbar information. This flag is used and set internally, and should not be +-- set otherwise. -- @return position of the found text or `-1` local function find(text, next, flags, no_wrap, wrapped) -- Note: cannot use assert_type(), as event errors are handled silently. if text == '' then return end if not flags then flags = get_flags() end - if flags >= 1 << 31 then M.find_in_files() return end -- not performed here + if flags >= 1 << 31 then + M.find_in_files() -- performed here + return + end local first_visible_line = view.first_visible_line -- for 'no results found' if not is_ff_buf(buffer) then clear_highlighted_matches() end @@ -205,8 +200,8 @@ local function find(text, next, flags, no_wrap, wrapped) incremental_orig_pos = nil end - -- If text is selected, assume it is from the current search and move the - -- caret appropriately for the next search. + -- If text is selected, assume it is from the current search and move the caret appropriately + -- for the next search. buffer:goto_pos(next and buffer.selection_end or buffer.selection_start) -- Scintilla search. @@ -256,45 +251,39 @@ events.connect(events.FIND_RESULT_FOUND, function(text) if s == buffer.current_pos then current = count end end ui.statusbar_text = string.format('%s %d/%d', _L['Match'], current, count) - -- For regex searches, `buffer.tag` was clobbered. It needs to be filled in - -- again for any subsequent replace operations that need it. + -- For regex searches, `buffer.tag` was clobbered. It needs to be filled in again for any + -- subsequent replace operations that need it. if ui.find.regex then buffer:set_target_range(buffer.selection_start, buffer.length + 1) buffer:search_in_target(text) end end) -events.connect( - events.FIND_WRAPPED, function() ui.statusbar_text = _L['Search wrapped'] end) +events.connect(events.FIND_WRAPPED, function() ui.statusbar_text = _L['Search wrapped'] end) --- --- Searches directory *dir* or the user-specified directory for files that match --- search text and search options (subject to optional filter *filter*), and --- prints the results to a buffer titled "Files Found", highlighting found text. --- Use the `find_entry_text`, `match_case`, `whole_word`, and `regex` fields to --- set the search text and option flags, respectively. +-- Searches directory *dir* or the user-specified directory for files that match search text +-- and search options (subject to optional filter *filter*), and prints the results to a buffer +-- titled "Files Found", highlighting found text. +-- Use the `find_entry_text`, `match_case`, `whole_word`, and `regex` fields to set the search +-- text and option flags, respectively. -- A filter determines which files to search in, with the default filter being --- `ui.find.find_in_files_filters[dir]` (if it exists) or `lfs.default_filter`. --- A filter consists of Lua patterns that match file and directory paths to --- include or exclude. Patterns are inclusive by default. Exclusive patterns --- begin with a '!'. If no inclusive patterns are given, any filename is --- initially considered. As a convenience, file extensions can be specified --- literally instead of as a Lua pattern (e.g. '.lua' vs. '%.lua$'), and '/' --- also matches the Windows directory separator ('[/\\]' is not needed). --- If *filter* is `nil`, the filter from the `ui.find.find_in_files_filters` --- table for *dir* is used. If that filter does not exist, `lfs.default_filter` --- is used. --- @param dir Optional directory path to search. If `nil`, the user is prompted --- for one. --- @param filter Optional filter for files and directories to exclude. The --- default value is `lfs.default_filter` unless a filter for *dir* is defined --- in `ui.find.find_in_files_filters`. +-- `ui.find.find_in_files_filters[dir]` (if it exists) or `lfs.default_filter`. A filter consists +-- of Lua patterns that match file and directory paths to include or exclude. Patterns are +-- inclusive by default. Exclusive patterns begin with a '!'. If no inclusive patterns are given, +-- any filename is initially considered. As a convenience, file extensions can be specified +-- literally instead of as a Lua pattern (e.g. '.lua' vs. '%.lua$'), and '/' also matches the +-- Windows directory separator ('[/\\]' is not needed). If *filter* is `nil`, the filter from +-- the `ui.find.find_in_files_filters` table for *dir* is used. If that filter does not exist, +-- `lfs.default_filter` is used. +-- @param dir Optional directory path to search. If `nil`, the user is prompted for one. +-- @param filter Optional filter for files and directories to exclude. The default value is +-- `lfs.default_filter` unless a filter for *dir* is defined in `ui.find.find_in_files_filters`. -- @see find_in_files_filters -- @name find_in_files function M.find_in_files(dir, filter) if not assert_type(dir, 'string/nil', 1) then dir = ui.dialogs.fileselect{ - title = _L['Select Directory'], select_only_directories = true, - with_directory = ff_dir() + title = _L['Select Directory'], select_only_directories = true, with_directory = ff_dir() } if not dir then return end end @@ -310,10 +299,10 @@ function M.find_in_files(dir, filter) if buffer._type ~= _L['[Files Found Buffer]'] then preferred_view = view end ui.silent_print = false - ui._print(_L['[Files Found Buffer]'], string.format( - '%s %s\n%s %s\n%s %s', _L['Find:']:gsub('_', ''), M.find_entry_text, - _L['Directory:'], dir, _L['Filter:']:gsub('_', ''), - type(filter) == 'string' and filter or table.concat(filter, ','))) + ui._print(_L['[Files Found Buffer]'], + string.format('%s %s\n%s %s\n%s %s', _L['Find:']:gsub('_', ''), M.find_entry_text, + _L['Directory:'], dir, _L['Filter:']:gsub('_', ''), + type(filter) == 'string' and filter or table.concat(filter, ','))) buffer.indicator_current = M.INDIC_FIND -- Determine which files to search. @@ -342,18 +331,15 @@ function M.find_in_files(dir, filter) found = true if binary == nil then binary = buffer:text_range(1, 65536):find('\0') end if binary then - _G.buffer:add_text(string.format( - '%s:1:%s\n', utf8_filenames[i], _L['Binary file matches.'])) + _G.buffer:add_text(string.format('%s:1:%s\n', utf8_filenames[i], _L['Binary file matches.'])) break end local line_num = buffer:line_from_position(buffer.target_start) local line = buffer:get_line(line_num) - _G.buffer:add_text( - string.format('%s:%d:%s', utf8_filenames[i], line_num, line)) - local pos = _G.buffer.current_pos - #line + - buffer.target_start - buffer:position_from_line(line_num) - _G.buffer:indicator_fill_range( - pos, buffer.target_end - buffer.target_start) + _G.buffer:add_text(string.format('%s:%d:%s', utf8_filenames[i], line_num, line)) + local pos = _G.buffer.current_pos - #line + buffer.target_start - + buffer:position_from_line(line_num) + _G.buffer:indicator_fill_range(pos, buffer.target_end - buffer.target_start) if not line:find('\n$') then _G.buffer:add_text('\n') end buffer:set_target_range(buffer.target_end, buffer.length + 1) end @@ -365,36 +351,33 @@ function M.find_in_files(dir, filter) return i * 100 / #filenames, utf8_filenames[i] end) buffer:close(true) -- temporary buffer - ui._print( - _L['[Files Found Buffer]'], - stopped and _L['Find in Files aborted'] .. '\n' or - not found and _L['No results found'] .. '\n' or '') + local status = stopped and _L['Find in Files aborted'] or not found and _L['No results found'] + ui._print(_L['[Files Found Buffer]'], status and status .. '\n' or '') end local P, V, C, upper, lower = lpeg.P, lpeg.V, lpeg.C, string.upper, string.lower local esc = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t', v = '\v'} local re_patt = lpeg.Cs(P{ (V('text') + V('u') + V('l') + V('U') + V('L') + V('esc'))^1, - text = (1 - '\\' * lpeg.S('uUlLEbfnrtv'))^1, + text = (1 - '\\' * lpeg.S('uUlLEbfnrtv'))^1, -- LuaFormatter u = '\\u' * C(1) / upper, l = '\\l' * C(1) / lower, U = P('\\U') / '' * (V('text') / upper + V('u') + V('l'))^0 * V('E')^-1, - L = P('\\L') / '' * (V('text') / lower + V('u') + V('l'))^0 * V('E')^-1, + L = P('\\L') / '' * (V('text') / lower + V('u') + V('l'))^0 * V('E')^-1, -- LuaFormatter E = P('\\E') / '', esc = '\\' * C(1) / esc }) -- Returns string *text* with the following sequences unescaped: -- * "\uXXXX" sequences replaced with the equivalent UTF-8 character. --- * "\d" sequences replaced with the text of capture number *d* from the --- regular expression (or the entire match for *d* = 0). --- * "\U" and "\L" sequences convert everything up to the next "\U", "\L", or --- "\E" to uppercase and lowercase, respectively. --- * "\u" and "\l" sequences convert the next character to uppercase and --- lowercase, respectively. They may appear within "\U" and "\L" constructs. +-- * "\d" sequences replaced with the text of capture number *d* from the regular expression +-- (or the entire match for *d* = 0). +-- * "\U" and "\L" sequences convert everything up to the next "\U", "\L", or "\E" to uppercase +-- and lowercase, respectively. +-- * "\u" and "\l" sequences convert the next character to uppercase and lowercase, respectively. +-- They may appear within "\U" and "\L" constructs. -- @param text String text to unescape. -- @return unescaped text local function unescape(text) - text = text:gsub('%f[\\]\\u(%x%x%x%x)', function(code) - return utf8.char(tonumber(code, 16)) - end):gsub('\\0', buffer.target_text):gsub('\\(%d)', buffer.tag) + text = text:gsub('%f[\\]\\u(%x%x%x%x)', function(code) return utf8.char(tonumber(code, 16)) end) + :gsub('\\0', buffer.target_text):gsub('\\(%d)', buffer.tag) return re_patt:match(text) or text end @@ -408,14 +391,13 @@ end) local INDIC_REPLACE = _SCINTILLA.next_indic_number() -- Replaces all found text in the current buffer (ignores "Find in Files"). --- If any text is selected (other than text just found), only found text in that --- selection is replaced. +-- If any text is selected (other than text just found), only found text in that selection +-- is replaced. events.connect(events.REPLACE_ALL, function(ftext, rtext) if ftext == '' then return end local count = 0 local s, e = buffer.selection_start, buffer.selection_end - local replace_in_sel = - s ~= e and (ftext ~= find_text or buffer:get_sel_text() ~= found_text) + local replace_in_sel = s ~= e and (ftext ~= find_text or buffer:get_sel_text() ~= found_text) if replace_in_sel then buffer.indicator_current = INDIC_REPLACE buffer:indicator_fill_range(e, 1) @@ -427,8 +409,8 @@ events.connect(events.REPLACE_ALL, function(ftext, rtext) buffer:begin_undo_action() buffer.search_flags = get_flags() buffer:set_target_range(not replace_in_sel and 1 or s, buffer.length + 1) - while buffer:search_in_target(ftext) ~= -1 and (not replace_in_sel or - buffer.target_end <= buffer:indicator_end(INDIC_REPLACE, s) or EOF) do + while buffer:search_in_target(ftext) ~= -1 and + (not replace_in_sel or buffer.target_end <= buffer:indicator_end(INDIC_REPLACE, s) or EOF) do if buffer.target_start == buffer.target_end then break end -- prevent loops buffer:replace_target(not M.regex and rtext or unescape(rtext)) count = count + 1 @@ -446,30 +428,39 @@ events.connect(events.REPLACE_ALL, function(ftext, rtext) end) --- --- Jumps to the source of the find in files search result on line number --- *line_num* in the buffer titled "Files Found" or, if *line_num* is `nil`, --- jumps to the next or previous search result, depending on boolean *next*. --- @param line_num Optional line number in the files found buffer that contains --- the search result to go to. This parameter may be omitted completely. --- @param next Optional flag indicating whether to go to the next search result --- or the previous one. Only applicable when *line_num* is `nil`. +-- Jumps to the source of the find in files search result on line number *line_num* in the buffer +-- titled "Files Found" or, if *line_num* is `nil`, jumps to the next or previous search result, +-- depending on boolean *next*. +-- @param line_num Optional line number in the files found buffer that contains the search +-- result to go to. This parameter may be omitted completely. +-- @param next Optional flag indicating whether to go to the next search result or the previous +-- one. Only applicable when *line_num* is `nil`. -- @name goto_file_found function M.goto_file_found(line_num, next) if type(line_num) == 'boolean' then line_num, next = nil, line_num end local ff_view, ff_buf = nil, nil for i = 1, #_VIEWS do - if is_ff_buf(_VIEWS[i].buffer) then ff_view = _VIEWS[i] break end + if is_ff_buf(_VIEWS[i].buffer) then + ff_view = _VIEWS[i] + break + end end for i = 1, #_BUFFERS do - if is_ff_buf(_BUFFERS[i]) then ff_buf = _BUFFERS[i] break end + if is_ff_buf(_BUFFERS[i]) then + ff_buf = _BUFFERS[i] + break + end end if not ff_view and not ff_buf then return end - if ff_view then ui.goto_view(ff_view) else view:goto_buffer(ff_buf) end + if ff_view then + ui.goto_view(ff_view) + else + view:goto_buffer(ff_buf) + end - -- If no line number was given, find the next search result, wrapping as - -- necessary. + -- If no line number was given, find the next search result, wrapping as necessary. if not assert_type(line_num, 'number/nil', 1) and next ~= nil then - if next then buffer:line_end() else buffer:home() end + buffer[next and 'line_end' or 'home'](buffer) buffer:search_anchor() local f = next and buffer.search_next or buffer.search_prev local pos = f(buffer, buffer.FIND_REGEXP, '^.+:\\d+:.+$') @@ -487,7 +478,8 @@ function M.goto_file_found(line_num, next) local line = buffer:get_cur_line() local utf8_filename, pos utf8_filename, line_num, pos = line:match('^(.+):(%d+):()') - if not utf8_filename then return else line_num = tonumber(line_num) end + if not utf8_filename then return end + line_num = tonumber(line_num) textadept.editing.select_line() pos = buffer.selection_start + pos - 1 -- absolute pos of result text on line local s = buffer:indicator_end(M.INDIC_FIND, buffer.selection_start) @@ -508,9 +500,8 @@ events.connect(events.KEYPRESS, function(code) M.goto_file_found(buffer:line_from_position(buffer.current_pos)) return true end) -events.connect(events.DOUBLE_CLICK, function(_, line) - if is_ff_buf(buffer) then M.goto_file_found(line) end -end) +events.connect(events.DOUBLE_CLICK, + function(_, line) if is_ff_buf(buffer) then M.goto_file_found(line) end end) --[[ The functions below are Lua C functions. diff --git a/modules/textadept/history.lua b/modules/textadept/history.lua index 0c6113e4..da9f5885 100644 --- a/modules/textadept/history.lua +++ b/modules/textadept/history.lua @@ -4,14 +4,13 @@ local M = {} --[[ This comment is for LuaDoc. --- --- Records buffer positions within Textadept views over time and allows for --- navigating through that history. +-- Records buffer positions within Textadept views over time and allows for navigating through +-- that history. -- --- This module listens for text edit events and buffer switch events. Each time --- an insertion or deletion occurs, its location is recorded in the current --- view's location history. If the edit is close enough to the previous record, --- the previous record is amended. Each time a buffer switch occurs, the before --- and after locations are also recorded. +-- This module listens for text edit events and buffer switch events. Each time an insertion +-- or deletion occurs, its location is recorded in the current view's location history. If the +-- edit is close enough to the previous record, the previous record is amended. Each time a +-- buffer switch occurs, the before and after locations are also recorded. -- @field minimum_line_distance (number) -- The minimum number of lines between distinct history records. -- The default value is `3`. @@ -24,14 +23,15 @@ M.minimum_line_distance = 3 M.maximum_history_size = 100 -- Map of views to their history records. --- Each record has a `pos` field that points to the current history position in --- the associated view. +-- Each record has a `pos` field that points to the current history position in the associated view. -- @class table -- @name view_history -local view_history = setmetatable({}, {__index = function(t, view) - t[view] = {pos = 0} - return t[view] -end}) +local view_history = setmetatable({}, { + __index = function(t, view) + t[view] = {pos = 0} + return t[view] + end +}) -- Listens for text insertion and deletion events and records their locations. events.connect(events.MODIFIED, function(position, mod, text, length) @@ -50,8 +50,7 @@ events.connect(events.MODIFIED, function(position, mod, text, length) M.record(nil, buffer:line_from_position(position), buffer.column[position]) end) --- Do not record positions during buffer switches when jumping backwards or --- forwards. +-- Do not record positions during buffer switches when jumping backwards or forwards. local jumping = false -- Jumps to the given record in the current view's history. @@ -64,8 +63,7 @@ local function jump(record) else for _, buffer in ipairs(_BUFFERS) do if buffer.filename == filename or buffer._type == filename or - not buffer.filename and not buffer._type and - filename == _L['Untitled'] then + (not buffer.filename and not buffer._type and filename == _L['Untitled']) then view:goto_buffer(buffer) break end @@ -84,12 +82,15 @@ function M.back() local record = history[history.pos] local line = buffer:line_from_position(buffer.current_pos) if buffer.filename ~= record.filename and buffer._type ~= record.filename or - math.abs(record.line - line) > M.minimum_line_distance then - -- When navigated away from the most recent record, and if that record is - -- not a soft record, jump back to it first, then navigate backwards. - if not record.soft then jump(record) return end - -- Otherwise, update the soft record with the current position and - -- immediately navigate backwards. + math.abs(record.line - line) > M.minimum_line_distance then + -- When navigated away from the most recent record, and if that record is not a soft record, + -- jump back to it first, then navigate backwards. + if not record.soft then + jump(record) + return + end + -- Otherwise, update the soft record with the current position and immediately navigate + -- backwards. M.record(record.filename, nil, nil, record.soft) end if history.pos > 1 then history.pos = history.pos - 1 end @@ -110,15 +111,14 @@ end --- -- Records the given location in the current view's history. --- @param filename Optional string filename, buffer type, or identifier of the --- buffer to store. If `nil`, uses the current buffer. --- @param line Optional Integer line number to store. If `nil`, uses the current --- line. --- @param column Optional integer column number on line *line* to store. If --- `nil`, uses the current column. --- @param soft Optional flag that indicates whether or not this record should be --- skipped when navigating backward towards it, and updated when navigating --- away from it. The default value is `false`. +-- @param filename Optional string filename, buffer type, or identifier of the buffer to store. If +-- `nil`, uses the current buffer. +-- @param line Optional Integer line number to store. If `nil`, uses the current line. +-- @param column Optional integer column number on line *line* to store. If `nil`, uses the +-- current column. +-- @param soft Optional flag that indicates whether or not this record should be skipped when +-- navigating backward towards it, and updated when navigating away from it. The default +-- value is `false`. -- @name record function M.record(filename, line, column, soft) if not assert_type(filename, 'string/nil', 1) then @@ -127,17 +127,14 @@ function M.record(filename, line, column, soft) if not assert_type(line, 'number/nil', 2) then line = buffer:line_from_position(buffer.current_pos) end - if not assert_type(column, 'number/nil', 3) then - column = buffer.column[buffer.current_pos] - end + if not assert_type(column, 'number/nil', 3) then column = buffer.column[buffer.current_pos] end local history = view_history[view] if #history > 0 then local record = history[history.pos] if filename == record.filename and - (math.abs(record.line - line) <= M.minimum_line_distance or - record.soft) then - -- If the most recent record is close enough (distance-wise), or if that - -- record is a soft record, update it instead of recording a new one. + (math.abs(record.line - line) <= M.minimum_line_distance or record.soft) then + -- If the most recent record is close enough (distance-wise), or if that record is a soft + -- record, update it instead of recording a new one. record.line, record.column = line, column record.soft = soft and record.soft return @@ -146,17 +143,13 @@ function M.record(filename, line, column, soft) if history.pos < #history then for i = history.pos + 1, #history do history[i] = nil end -- clear forward end - history[#history + 1] = { - filename = filename, line = line, column = column, soft = soft - } + history[#history + 1] = {filename = filename, line = line, column = column, soft = soft} if #history > M.maximum_history_size then table.remove(history, 1) end history.pos = #history end -- Softly record positions when switching between buffers. -local function record_switch() - if not jumping then M.record(nil, nil, nil, true) end -end +local function record_switch() if not jumping then M.record(nil, nil, nil, true) end end events.connect(events.BUFFER_BEFORE_SWITCH, record_switch) events.connect(events.BUFFER_AFTER_SWITCH, record_switch) events.connect(events.FILE_OPENED, record_switch) @@ -164,8 +157,6 @@ events.connect(events.FILE_OPENED, record_switch) --- -- Clears all view history. -- @name clear -function M.clear() - for view in pairs(view_history) do view_history[view] = {pos = 0} end -end +function M.clear() for view in pairs(view_history) do view_history[view] = {pos = 0} end end return M diff --git a/modules/textadept/init.lua b/modules/textadept/init.lua index 6ba747a0..d2bde80c 100644 --- a/modules/textadept/init.lua +++ b/modules/textadept/init.lua @@ -10,8 +10,8 @@ textadept = M -- forward declaration module('textadept')]] local modules = { - 'bookmarks', 'command_entry', 'editing', 'file_types', 'find', 'history', - 'macros', 'run', 'session', 'snippets', --[[need to be last]] 'menu', 'keys' + 'bookmarks', 'command_entry', 'editing', 'file_types', 'find', 'history', 'macros', 'run', + 'session', 'snippets', --[[need to be last]] 'menu', 'keys' } for _, name in ipairs(modules) do M[name] = require('textadept.' .. name) end M.command_entry, M.find = nil, nil -- ui.command_entry, ui.find diff --git a/modules/textadept/keys.lua b/modules/textadept/keys.lua index 5cae6988..b50503cb 100644 --- a/modules/textadept/keys.lua +++ b/modules/textadept/keys.lua @@ -5,214 +5,214 @@ local M = {} --[[ This comment is for LuaDoc. --- -- Defines key bindings for Textadept. --- This set of key bindings is pretty standard among other text editors, at --- least for basic editing commands and movements. +-- This set of key bindings is pretty standard among other text editors, at least for basic +-- editing commands and movements. -- -- ### Key Bindings -- --- Win32, Linux, BSD|macOS|Terminal|Command --- -----------------|-----|--------|-------- --- **File** | | | --- Ctrl+N |⌘N |M-^N |New file --- Ctrl+O |⌘O |^O |Open file --- Ctrl+Alt+O |^⌘O |M-^O |Open recent file... --- Ctrl+Shift+O |⌘⇧O |M-O |Reload file --- Ctrl+S |⌘S |^S |Save file --- Ctrl+Shift+S |⌘⇧S |M-^S |Save file as.. --- None |None |None |Save all files --- Ctrl+W |⌘W |^W |Close file --- Ctrl+Shift+W |⌘⇧W |M-^W |Close all files --- None |None |None |Load session... --- None |None |None |Save session... --- Ctrl+Q |⌘Q |^Q |Quit --- **Edit** | | | --- Ctrl+Z<br/>Alt+Bksp |⌘Z |^Z^(†)<br/>M-Z|Undo --- Ctrl+Y<br/>Ctrl+Shift+Z|⌘⇧Z |^Y<br/>M-S-Z |Redo --- Ctrl+X<br/>Shift+Del |⌘X<br/>⇧⌦|^X |Cut --- Ctrl+C<br/>Ctrl+Ins |⌘C |^C |Copy --- Ctrl+V<br/>Shift+Ins |⌘V |^V |Paste --- Ctrl+Shift+V |⌘⇧V |M-V |Paste Reindent --- Ctrl+D |⌘D |None |Duplicate line --- Del |⌦<br/>^D |Del<br/>^D |Delete --- Alt+Del |^⌦ |M-Del<br/>M-D |Delete word --- Ctrl+A |⌘A |M-A |Select all --- Ctrl+M |^M |M-M |Match brace --- Ctrl+Enter |^Esc |M-Enter^(‡) |Complete word --- Ctrl+/ |^/ |M-/ |Toggle block comment --- Ctrl+T |^T |^T |Transpose characters --- Ctrl+Shift+J |^J |M-J |Join lines --- Ctrl+| |⌘| |^\ |Filter text through --- Ctrl+Shift+M |^⇧M |M-S-M |Select between delimiters --- Ctrl+< |⌘< |M-< |Select between XML tags --- Ctrl+> |⌘> |None |Select in XML tag --- Ctrl+Shift+D |⌘⇧D |M-S-W |Select word --- Ctrl+Shift+N |⌘⇧N |M-S-N |Select line --- Ctrl+Shift+P |⌘⇧P |M-S-P |Select paragraph --- Ctrl+Alt+U |^U |M-^U |Upper case selection --- Ctrl+Alt+Shift+U |^⇧U |M-^L |Lower case selection --- Alt+< |^< |M-> |Enclose as XML tags --- Alt+> |^> |None |Enclose as single XML tag --- Alt+" |^" |None |Enclose in double quotes --- Alt+' |^' |None |Enclose in single quotes --- Alt+( |^( |M-) |Enclose in parentheses --- Alt+[ |^[ |M-] |Enclose in brackets --- Alt+{ |^{ |M-} |Enclose in braces --- Ctrl+Shift+Up |^⇧⇡ |S-^Up |Move selected lines up --- Ctrl+Shift+Down |^⇧⇣ |S-^Down |Move selected lines down --- Alt+, |^, |M-, |Navigate backward --- Alt+. |^. |M-. |Navigate forward --- None |None |None |Record location --- None |None |None |Clear navigation history --- Ctrl+P |⌘, |M-~ |Preferences --- **Search** | | | --- Ctrl+F |⌘F |M-F<br/>M-S-F|Find --- Ctrl+G<br/>F3 |⌘G |M-G |Find next --- Ctrl+Shift+G<br/>Shift+F3|⌘⇧G |M-S-G |Find previous --- Ctrl+Alt+R |^R |M-R |Replace --- Ctrl+Alt+Shift+R |^⇧R |M-S-R |Replace all --- Ctrl+Alt+F |^⌘F |M-^F |Find incremental --- Ctrl+Shift+F |⌘⇧F |None |Find in files --- Ctrl+Alt+G |^⌘G |None |Goto next file found --- Ctrl+Alt+Shift+G |^⌘⇧G|None |Goto previous file found --- Ctrl+J |⌘J |^J |Jump to line --- **Tools** | | | --- Ctrl+E |⌘E |M-C |Command entry --- Ctrl+Shift+E |⌘⇧E |M-S-C |Select command --- Ctrl+R |⌘R |^R |Run --- Ctrl+Shift+R |⌘⇧R |M-^R |Compile --- Ctrl+Shift+A |⌘⇧A |None |Set Arguments... --- Ctrl+Shift+B |⌘⇧B |M-^B |Build --- Ctrl+Shift+T |⌘⇧T |M-^T |Run tests --- Ctrl+Shift+X |⌘⇧X |M-^X |Stop --- Ctrl+Alt+E |^⌘E |M-X |Next Error --- Ctrl+Alt+Shift+E|^⌘⇧E |M-S-X |Previous Error --- Ctrl+F2 |⌘F2 |F1 |Toggle bookmark --- Ctrl+Shift+F2 |⌘⇧F2 |F6 |Clear bookmarks --- F2 |F2 |F2 |Next bookmark --- Shift+F2 |⇧F2 |F3 |Previous bookmark --- Alt+F2 |⌥F2 |F4 |Goto bookmark... --- F9 |F9 |F9 |Start/stop recording macro --- Shift+F9 |⇧F9 |F10 |Play recorded macro --- Ctrl+U |⌘U |^U |Quickly open `_USERHOME` --- None |None |None |Quickly open `_HOME` --- Ctrl+Alt+Shift+O|^⌘⇧O |M-S-O |Quickly open current directory --- Ctrl+Alt+Shift+P|^⌘⇧P |M-^P |Quickly open current project --- Ctrl+Shift+K |⌥⇧⇥ |M-S-K |Insert snippet... --- Tab |⇥ |Tab |Expand snippet or next placeholder --- Shift+Tab |⇧⇥ |S-Tab |Previous snippet placeholder --- Esc |Esc |Esc |Cancel snippet --- Ctrl+K |⌥⇥ |M-K |Complete trigger word --- Ctrl+Space |⌥Esc |^Space |Complete symbol --- Ctrl+H |^H |M-H<br/>M-S-H|Show documentation --- Ctrl+I |⌘I |M-S-I |Show style --- **Buffer** | | | --- Ctrl+Tab |^⇥ |M-N |Next buffer --- Ctrl+Shift+Tab |^⇧⇥ |M-P |Previous buffer --- Ctrl+B |⌘B |M-B<br/>M-S-B|Switch to buffer... --- None |None |None |Tab width: 2 --- None |None |None |Tab width: 3 --- None |None |None |Tab width: 4 --- None |None |None |Tab width: 8 --- Ctrl+Alt+Shift+T|^⇧T |M-T<br/>M-S-T|Toggle use tabs --- Ctrl+Alt+I |^I |M-I |Convert indentation --- None |None |None |CR+LF EOL mode --- None |None |None |LF EOL mode --- None |None |None |UTF-8 encoding --- None |None |None |ASCII encoding --- None |None |None |CP-1252 encoding --- None |None |None |UTF-16 encoding --- Ctrl+Alt+\\ |^\\ |None |Toggle wrap mode --- Ctrl+Alt+Shift+S|^⇧S |None |Toggle view whitespace --- Ctrl+Shift+L |⌘⇧L |M-S-L |Select lexer... --- **View** | | | --- Ctrl+Alt+N |^⌥⇥ |M-^V N |Next view --- Ctrl+Alt+P |^⌥⇧⇥ |M-^V P |Previous view --- Ctrl+Alt+S<br/>Ctrl+Alt+H|^S |M-^V S<br/>M-^V H|Split view horizontal --- Ctrl+Alt+V |^V |M-^V V |Split view vertical --- Ctrl+Alt+W |^W |M-^V W |Unsplit view --- Ctrl+Alt+Shift+W |^⇧W |M-^V S-W |Unsplit all views --- Ctrl+Alt++<br/>Ctrl+Alt+=|^+<br/>^=|M-^V +<br/>M-^V =|Grow view --- Ctrl+Alt+- |^- |M-^V - |Shrink view --- Ctrl+* |⌘* |M-* |Toggle current fold --- Ctrl+Alt+Shift+I |^⇧I |N/A |Toggle indent guides --- Ctrl+Alt+Shift+V |^⇧V |None |Toggle virtual space --- Ctrl+= |⌘= |N/A |Zoom in --- Ctrl+- |⌘- |N/A |Zoom out --- Ctrl+0 |⌘0 |N/A |Reset zoom --- **Help**| | | --- F1 |F1 |None|Open manual --- Shift+F1|⇧F1 |None|Open LuaDoc --- None |None|None|About --- **Movement** | | | --- Down |⇣<br/>^N |^N<br/>Down |Line down --- Shift+Down |⇧⇣<br/>^⇧N |S-Down |Line down extend selection --- Ctrl+Down |^⇣ |^Down |Scroll line down --- Alt+Shift+Down |⌥⇧⇣ |M-S-Down |Line down extend rect. selection --- Up |⇡<br/>^P |^P<br/>Up |Line up --- Shift+Up |⇧⇡<br/>^⇧P |S-Up |Line up extend selection --- Ctrl+Up |^⇡ |^Up |Scroll line up --- Alt+Shift+Up |⌥⇧⇡ |M-S-Up |Line up extend rect. selection --- Left |⇠<br/>^B |^B<br/>Left |Char left --- Shift+Left |⇧⇠<br/>^⇧B |S-Left |Char left extend selection --- Ctrl+Left |⌥⇠<br/>^⌘B |^Left |Word left --- Ctrl+Shift+Left |^⇧⇠<br/>^⌘⇧B|S-^Left |Word left extend selection --- Alt+Shift+Left |⌥⇧⇠|M-S-Left |Char left extend rect. selection --- Right |⇢<br/>^F |^F<br/>Right|Char right --- Shift+Right |⇧⇢<br/>^⇧F |S-Right |Char right extend selection --- Ctrl+Right |⌥⇢<br/>^⌘F |^Right |Word right --- Ctrl+Shift+Right|^⇧⇢<br/>^⌘⇧F|S-^Right |Word right extend selection --- Alt+Shift+Right |⌥⇧⇢ |M-S-Right |Char right extend rect. selection --- Home |⌘⇠<br/>^A |^A<br/>Home |Line start --- Shift+Home |⌘⇧⇠<br/>^⇧A |M-S-A |Line start extend selection --- Ctrl+Home |⌘⇡<br/>⌘↖ |M-^A |Document start --- Ctrl+Shift+Home |⌘⇧⇡<br/>⌘⇧↖ |None |Document start extend selection --- Alt+Shift+Home |⌥⇧↖ |None |Line start extend rect. selection --- End |⌘⇢<br/>^E |^E<br/>End |Line end --- Shift+End |⌘⇧⇢<br/>^⇧E |M-S-E |Line end extend selection --- Ctrl+End |⌘⇣<br/>⌘↘ |M-^E |Document end --- Ctrl+Shift+End |⌘⇧⇣<br/>⌘⇧↘ |None |Document end extend selection --- Alt+Shift+End |⌥⇧↘ |None |Line end extend rect. selection --- PgUp |⇞ |PgUp |Page up --- Shift+PgUp |⇧⇞ |M-S-U |Page up extend selection --- Alt+Shift+PgUp |⌥⇧⇞ |None |Page up extend rect. selection --- PgDn |⇟ |PgDn |Page down --- Shift+PgDn |⇧⇟ |M-S-D |Page down extend selection --- Alt+Shift+PgDn |⌥⇧⇟ |None |Page down extend rect. selection --- Ctrl+Del |⌘⌦ |^Del |Delete word right --- Ctrl+Shift+Del |⌘⇧⌦ |S-^Del |Delete line right --- Ins |Ins |Ins |Toggle overtype --- Bksp |⌫<br/>⇧⌫ |^H<br/>Bksp |Delete back --- Ctrl+Bksp |⌘⌫ |None |Delete word left --- Ctrl+Shift+Bksp |⌘⇧⌫ |None |Delete line left --- Tab |⇥ |Tab<br/>^I |Insert tab or indent --- Shift+Tab |⇧⇥ |S-Tab |Dedent --- None |^K |^K |Cut to line end --- None |^L |None |Center line vertically --- N/A |N/A |^^ |Mark text at the caret position --- N/A |N/A |^] |Swap caret and mark anchor --- **UTF-8 Input** | | | --- Ctrl+Shift+U *xxxx* Enter|⌘⇧U *xxxx* ↩|M-U *xxxx* Enter|Insert U-*xxxx* char. --- **Find Fields**| | | --- Left |⇠<br/>^B |^B<br/>Left |Cursor left --- Right |⇢<br/>^F |^F<br/>Right|Cursor right --- Del |⌦ |Del |Delete forward --- Bksp |⌫ |^H<br/>Bksp |Delete back --- Ctrl+V |⌘V |^V |Paste --- N/A |N/A |^X |Cut all --- N/A |N/A |^Y |Copy all --- N/A |N/A |^U |Erase all --- Home |↖<br/>⌘⇠<br/>^A|^A |Home --- End |↘<br/>⌘⇢<br/>^E|^E |End --- N/A |N/A |^T |Transpose characters --- N/A |N/A |Tab |Toggle find/replace buttons --- Tab |⇥ |Down |Focus replace field --- Shift+Tab |⇧⇥ |Up |Focus find field --- Up |⇡ |^P |Cycle back through history --- Down |⇣ |^N |Cycle forward through history --- N/A |N/A |F1 |Toggle "Match Case" --- N/A |N/A |F2 |Toggle "Whole Word" --- N/A |N/A |F3 |Toggle "Regex" --- N/A |N/A |F4 |Toggle "Find in Files" +-- Win32, Linux, BSD | macOS | Terminal | Command +-- -|-|-|- +-- **File**||| +-- Ctrl+N | ⌘N | M-^N | New file +-- Ctrl+O | ⌘O | ^O | Open file +-- Ctrl+Alt+O | ^⌘O | M-^O | Open recent file... +-- Ctrl+Shift+O | ⌘⇧O | M-O | Reload file +-- Ctrl+S | ⌘S | ^S | Save file +-- Ctrl+Shift+S | ⌘⇧S | M-^S | Save file as.. +-- None | None | None | Save all files +-- Ctrl+W | ⌘W | ^W | Close file +-- Ctrl+Shift+W | ⌘⇧W | M-^W | Close all files +-- None | None | None | Load session... +-- None | None | None | Save session... +-- Ctrl+Q | ⌘Q | ^Q | Quit +-- **Edit**| | | +-- Ctrl+Z<br/>Alt+Bksp | ⌘Z | ^Z^(†)<br/>M-Z | Undo +-- Ctrl+Y<br/>Ctrl+Shift+Z | ⌘⇧Z | ^Y<br/>M-S-Z | Redo +-- Ctrl+X<br/>Shift+Del | ⌘X<br/>⇧⌦ | ^X | Cut +-- Ctrl+C<br/>Ctrl+Ins | ⌘C | ^C | Copy +-- Ctrl+V<br/>Shift+Ins | ⌘V | ^V | Paste +-- Ctrl+Shift+V | ⌘⇧V | M-V | Paste Reindent +-- Ctrl+D | ⌘D | None | Duplicate line +-- Del | ⌦<br/>^D | Del<br/>^D | Delete +-- Alt+Del | ^⌦ | M-Del<br/>M-D | Delete word +-- Ctrl+A | ⌘A | M-A | Select all +-- Ctrl+M | ^M | M-M | Match brace +-- Ctrl+Enter | ^Esc | M-Enter^(‡) | Complete word +-- Ctrl+/ | ^/ | M-/ | Toggle block comment +-- Ctrl+T | ^T | ^T | Transpose characters +-- Ctrl+Shift+J | ^J | M-J | Join lines +-- Ctrl+| | ⌘| | ^\ | Filter text through +-- Ctrl+Shift+M | ^⇧M | M-S-M | Select between delimiters +-- Ctrl+< | ⌘< | M-< | Select between XML tags +-- Ctrl+> | ⌘> | None | Select in XML tag +-- Ctrl+Shift+D | ⌘⇧D | M-S-W | Select word +-- Ctrl+Shift+N | ⌘⇧N | M-S-N | Select line +-- Ctrl+Shift+P | ⌘⇧P | M-S-P | Select paragraph +-- Ctrl+Alt+U | ^U | M-^U | Upper case selection +-- Ctrl+Alt+Shift+U | ^⇧U | M-^L | Lower case selection +-- Alt+< | ^< | M-> | Enclose as XML tags +-- Alt+> | ^> | None | Enclose as single XML tag +-- Alt+" | ^" | None | Enclose in double quotes +-- Alt+' | ^' | None | Enclose in single quotes +-- Alt+( | ^( | M-) | Enclose in parentheses +-- Alt+[ | ^[ | M-] | Enclose in brackets +-- Alt+{ | ^{ | M-} | Enclose in braces +-- Ctrl+Shift+Up | ^⇧⇡ | S-^Up | Move selected lines up +-- Ctrl+Shift+Down | ^⇧⇣ | S-^Down | Move selected lines down +-- Alt+, | ^, | M-, | Navigate backward +-- Alt+. | ^. | M-. | Navigate forward +-- None | None | None | Record location +-- None | None | None | Clear navigation history +-- Ctrl+P | ⌘, | M-~ | Preferences +-- **Search**| | | +-- Ctrl+F | ⌘F | M-F<br/>M-S-F | Find +-- Ctrl+G<br/>F3 | ⌘G | M-G | Find next +-- Ctrl+Shift+G<br/>Shift+F3 | ⌘⇧G | M-S-G | Find previous +-- Ctrl+Alt+R | ^R | M-R | Replace +-- Ctrl+Alt+Shift+R | ^⇧R | M-S-R | Replace all +-- Ctrl+Alt+F | ^⌘F | M-^F | Find incremental +-- Ctrl+Shift+F | ⌘⇧F | None | Find in files +-- Ctrl+Alt+G | ^⌘G | None | Goto next file found +-- Ctrl+Alt+Shift+G | ^⌘⇧G | None | Goto previous file found +-- Ctrl+J | ⌘J | ^J | Jump to line +-- **Tools**| | | +-- Ctrl+E | ⌘E | M-C | Command entry +-- Ctrl+Shift+E | ⌘⇧E | M-S-C | Select command +-- Ctrl+R | ⌘R | ^R | Run +-- Ctrl+Shift+R | ⌘⇧R | M-^R | Compile +-- Ctrl+Shift+A | ⌘⇧A | None | Set Arguments... +-- Ctrl+Shift+B | ⌘⇧B | M-^B | Build +-- Ctrl+Shift+T | ⌘⇧T | M-^T | Run tests +-- Ctrl+Shift+X | ⌘⇧X | M-^X | Stop +-- Ctrl+Alt+E | ^⌘E | M-X | Next Error +-- Ctrl+Alt+Shift+E | ^⌘⇧E | M-S-X | Previous Error +-- Ctrl+F2 | ⌘F2 | F1 | Toggle bookmark +-- Ctrl+Shift+F2 | ⌘⇧F2 | F6 | Clear bookmarks +-- F2 | F2 | F2 | Next bookmark +-- Shift+F2 | ⇧F2 | F3 | Previous bookmark +-- Alt+F2 | ⌥F2 | F4 | Goto bookmark... +-- F9 | F9 | F9 | Start/stop recording macro +-- Shift+F9 | ⇧F9 | F10 | Play recorded macro +-- Ctrl+U | ⌘U | ^U | Quickly open `_USERHOME` +-- None | None | None | Quickly open `_HOME` +-- Ctrl+Alt+Shift+O | ^⌘⇧O | M-S-O | Quickly open current directory +-- Ctrl+Alt+Shift+P | ^⌘⇧P | M-^P | Quickly open current project +-- Ctrl+Shift+K | ⌥⇧⇥ | M-S-K | Insert snippet... +-- Tab | ⇥ | Tab | Expand snippet or next placeholder +-- Shift+Tab | ⇧⇥ | S-Tab | Previous snippet placeholder +-- Esc | Esc | Esc | Cancel snippet +-- Ctrl+K | ⌥⇥ | M-K | Complete trigger word +-- Ctrl+Space | ⌥Esc | ^Space | Complete symbol +-- Ctrl+H | ^H | M-H<br/>M-S-H | Show documentation +-- Ctrl+I | ⌘I | M-S-I | Show style +-- **Buffer**| | | +-- Ctrl+Tab | ^⇥ | M-N | Next buffer +-- Ctrl+Shift+Tab | ^⇧⇥ | M-P | Previous buffer +-- Ctrl+B | ⌘B | M-B<br/>M-S-B | Switch to buffer... +-- None | None | None | Tab width: 2 +-- None | None | None | Tab width: 3 +-- None | None | None | Tab width: 4 +-- None | None | None | Tab width: 8 +-- Ctrl+Alt+Shift+T | ^⇧T | M-T<br/>M-S-T | Toggle use tabs +-- Ctrl+Alt+I | ^I | M-I | Convert indentation +-- None | None | None | CR+LF EOL mode +-- None | None | None | LF EOL mode +-- None | None | None | UTF-8 encoding +-- None | None | None | ASCII encoding +-- None | None | None | CP-1252 encoding +-- None | None | None | UTF-16 encoding +-- Ctrl+Alt+\\ | ^\\ | None | Toggle wrap mode +-- Ctrl+Alt+Shift+S | ^⇧S | None | Toggle view whitespace +-- Ctrl+Shift+L | ⌘⇧L | M-S-L | Select lexer... +-- **View**| | | +-- Ctrl+Alt+N | ^⌥⇥ | M-^V N | Next view +-- Ctrl+Alt+P | ^⌥⇧⇥ | M-^V P | Previous view +-- Ctrl+Alt+S<br/>Ctrl+Alt+H | ^S | M-^V S<br/>M-^V H | Split view horizontal +-- Ctrl+Alt+V | ^V | M-^V V | Split view vertical +-- Ctrl+Alt+W | ^W | M-^V W | Unsplit view +-- Ctrl+Alt+Shift+W | ^⇧W | M-^V S-W | Unsplit all views +-- Ctrl+Alt++<br/>Ctrl+Alt+= | ^+<br/>^= | M-^V +<br/>M-^V = | Grow view +-- Ctrl+Alt+- | ^- | M-^V - | Shrink view +-- Ctrl+* | ⌘* | M-* | Toggle current fold +-- Ctrl+Alt+Shift+I | ^⇧I | N/A | Toggle indent guides +-- Ctrl+Alt+Shift+V | ^⇧V | None | Toggle virtual space +-- Ctrl+= | ⌘= | N/A | Zoom in +-- Ctrl+- | ⌘- | N/A | Zoom out +-- Ctrl+0 | ⌘0 | N/A | Reset zoom +-- **Help**|| | +-- F1 | F1 | None | Open manual +-- Shift+F1 | ⇧F1 | None | Open LuaDoc +-- None | None | None | About +-- **Movement**| | | +-- Down | ⇣<br/>^N | ^N<br/>Down | Line down +-- Shift+Down | ⇧⇣<br/>^⇧N | S-Down | Line down extend selection +-- Ctrl+Down | ^⇣ | ^Down | Scroll line down +-- Alt+Shift+Down | ⌥⇧⇣ | M-S-Down | Line down extend rect. selection +-- Up | ⇡<br/>^P | ^P<br/>Up | Line up +-- Shift+Up | ⇧⇡<br/>^⇧P | S-Up | Line up extend selection +-- Ctrl+Up | ^⇡ | ^Up | Scroll line up +-- Alt+Shift+Up | ⌥⇧⇡ | M-S-Up | Line up extend rect. selection +-- Left | ⇠<br/>^B | ^B<br/>Left | Char left +-- Shift+Left | ⇧⇠<br/>^⇧B | S-Left | Char left extend selection +-- Ctrl+Left | ⌥⇠<br/>^⌘B | ^Left | Word left +-- Ctrl+Shift+Left | ^⇧⇠<br/>^⌘⇧B | S-^Left | Word left extend selection +-- Alt+Shift+Left | ⌥⇧⇠| M-S-Left | Char left extend rect. selection +-- Right | ⇢<br/>^F | ^F<br/>Right | Char right +-- Shift+Right | ⇧⇢<br/>^⇧F | S-Right | Char right extend selection +-- Ctrl+Right | ⌥⇢<br/>^⌘F | ^Right | Word right +-- Ctrl+Shift+Right | ^⇧⇢<br/>^⌘⇧F | S-^Right | Word right extend selection +-- Alt+Shift+Right | ⌥⇧⇢ | M-S-Right | Char right extend rect. selection +-- Home | ⌘⇠<br/>^A | ^A<br/>Home | Line start +-- Shift+Home | ⌘⇧⇠<br/>^⇧A | M-S-A | Line start extend selection +-- Ctrl+Home | ⌘⇡<br/>⌘↖ | M-^A | Document start +-- Ctrl+Shift+Home | ⌘⇧⇡<br/>⌘⇧↖ | None | Document start extend selection +-- Alt+Shift+Home | ⌥⇧↖ | None | Line start extend rect. selection +-- End | ⌘⇢<br/>^E | ^E<br/>End | Line end +-- Shift+End | ⌘⇧⇢<br/>^⇧E | M-S-E | Line end extend selection +-- Ctrl+End | ⌘⇣<br/>⌘↘ | M-^E | Document end +-- Ctrl+Shift+End | ⌘⇧⇣<br/>⌘⇧↘ | None | Document end extend selection +-- Alt+Shift+End | ⌥⇧↘ | None | Line end extend rect. selection +-- PgUp | ⇞ | PgUp | Page up +-- Shift+PgUp | ⇧⇞ | M-S-U | Page up extend selection +-- Alt+Shift+PgUp | ⌥⇧⇞ | None | Page up extend rect. selection +-- PgDn | ⇟ | PgDn | Page down +-- Shift+PgDn | ⇧⇟ | M-S-D | Page down extend selection +-- Alt+Shift+PgDn | ⌥⇧⇟ | None | Page down extend rect. selection +-- Ctrl+Del | ⌘⌦ | ^Del | Delete word right +-- Ctrl+Shift+Del | ⌘⇧⌦ | S-^Del | Delete line right +-- Ins | Ins | Ins | Toggle overtype +-- Bksp | ⌫<br/>⇧⌫ | ^H<br/>Bksp | Delete back +-- Ctrl+Bksp | ⌘⌫ | None | Delete word left +-- Ctrl+Shift+Bksp | ⌘⇧⌫ | None | Delete line left +-- Tab | ⇥ | Tab<br/>^I | Insert tab or indent +-- Shift+Tab | ⇧⇥ | S-Tab | Dedent +-- None | ^K | ^K | Cut to line end +-- None | ^L | None | Center line vertically +-- N/A | N/A | ^^ | Mark text at the caret position +-- N/A | N/A | ^] | Swap caret and mark anchor +-- **UTF-8 Input**||| +-- Ctrl+Shift+U *xxxx* Enter | ⌘⇧U *xxxx* ↩ | M-U *xxxx* Enter | Insert U-*xxxx* char. +-- **Find Fields**||| +-- Left | ⇠<br/>^B | ^B<br/>Left | Cursor left +-- Right | ⇢<br/>^F | ^F<br/>Right | Cursor right +-- Del | ⌦ | Del | Delete forward +-- Bksp | ⌫ | ^H<br/>Bksp | Delete back +-- Ctrl+V | ⌘V | ^V | Paste +-- N/A | N/A | ^X | Cut all +-- N/A | N/A | ^Y | Copy all +-- N/A | N/A | ^U | Erase all +-- Home | ↖<br/>⌘⇠<br/>^A | ^A | Home +-- End | ↘<br/>⌘⇢<br/>^E | ^E | End +-- N/A | N/A | ^T | Transpose characters +-- N/A | N/A | Tab | Toggle find/replace buttons +-- Tab | ⇥ | Down | Focus replace field +-- Shift+Tab | ⇧⇥ | Up | Focus find field +-- Up | ⇡ | ^P | Cycle back through history +-- Down | ⇣ | ^N | Cycle forward through history +-- N/A | N/A | F1 | Toggle "Match Case" +-- N/A | N/A | F2 | Toggle "Whole Word" +-- N/A | N/A | F3 | Toggle "Regex" +-- N/A | N/A | F4 | Toggle "Find in Files" -- -- †: Some terminals interpret ^Z as suspend; see FAQ for workaround. -- @@ -251,13 +251,12 @@ module('textadept.keys')]] -- Key bindings available depend on your implementation of curses. -- -- For ncurses (Linux, macOS, BSD): --- * The only Control keys recognized are 'ctrl+a'-'ctrl+z', 'ctrl+ ', --- 'ctrl+\\', 'ctrl+]', 'ctrl+^', and 'ctrl+_'. +-- * The only Control keys recognized are 'ctrl+a'-'ctrl+z', 'ctrl+ ', 'ctrl+\\', 'ctrl+]', +-- 'ctrl+^', and 'ctrl+_'. -- * 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 --- Control+Shift+Symbol keys are. +-- * 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): @@ -272,8 +271,7 @@ module('textadept.keys')]] -- Control, Meta, and 'a' = 'ctrl+meta+a' local _L = _L --- Returns the menu command associated with the '/'-separated string of menu --- labels. +-- Returns the menu command associated with the '/'-separated string of menu labels. -- Labels are automatically localized. -- @param labels Path to the menu command. -- @usage m('Edit/Select/Select in XML Tag') @@ -283,6 +281,7 @@ local function m(labels) return menu[2] end +-- LuaFormatter off -- Bindings for Linux/Win32, macOS, Terminal. local bindings = { -- File. @@ -311,15 +310,13 @@ local bindings = { [m('Edit/Delete Word')] = {'alt+del', 'ctrl+del', {'meta+del', 'meta+d'}}, [buffer.select_all] = {'ctrl+a', 'cmd+a', 'meta+a'}, [m('Edit/Match Brace')] = {'ctrl+m', 'ctrl+m', 'meta+m'}, - [m('Edit/Complete Word')] = - {'ctrl+\n', 'ctrl+esc', {'ctrl+meta+j', 'ctrl+\n'}}, + [m('Edit/Complete Word')] = {'ctrl+\n', 'ctrl+esc', {'ctrl+meta+j', 'ctrl+\n'}}, [textadept.editing.toggle_comment] = {'ctrl+/', 'ctrl+/', 'meta+/'}, [textadept.editing.transpose_chars] = {'ctrl+t', 'ctrl+t', 'ctrl+t'}, [textadept.editing.join_lines] = {'ctrl+J', 'ctrl+j', 'meta+j'}, [m('Edit/Filter Through')] = {'ctrl+|', 'cmd+|', 'ctrl+\\'}, -- Select. - [m('Edit/Select/Select between Matching Delimiters')] = - {'ctrl+M', 'ctrl+M', 'meta+M'}, + [m('Edit/Select/Select between Matching Delimiters')] = {'ctrl+M', 'ctrl+M', 'meta+M'}, [m('Edit/Select/Select between XML Tags')] = {'ctrl+<', 'cmd+<', 'meta+<'}, [m('Edit/Select/Select in XML Tag')] = {'ctrl+>', 'cmd+>', nil}, [textadept.editing.select_word] = {'ctrl+D', 'cmd+D', 'meta+W'}, @@ -335,10 +332,8 @@ local bindings = { [m('Edit/Selection/Enclose in Parentheses')] = {'alt+(', 'ctrl+(', 'meta+)'}, [m('Edit/Selection/Enclose in Brackets')] = {'alt+[', 'ctrl+[', 'meta+]'}, [m('Edit/Selection/Enclose in Braces')] = {'alt+{', 'ctrl+{', 'meta+}'}, - [buffer.move_selected_lines_up] = - {'ctrl+shift+up', 'ctrl+shift+up', 'ctrl+shift+up'}, - [buffer.move_selected_lines_down] = - {'ctrl+shift+down', 'ctrl+shift+down', 'ctrl+shift+down'}, + [buffer.move_selected_lines_up] = {'ctrl+shift+up', 'ctrl+shift+up', 'ctrl+shift+up'}, + [buffer.move_selected_lines_down] = {'ctrl+shift+down', 'ctrl+shift+down', 'ctrl+shift+down'}, -- History. [textadept.history.back] = {'alt+,', 'ctrl+,', 'meta+,'}, [textadept.history.forward] = {'alt+.', 'ctrl+.', 'meta+.'}, @@ -385,11 +380,9 @@ local bindings = { [textadept.macros.record] = {'f9', 'f9', 'f9'}, [textadept.macros.play] = {'shift+f9', 'shift+f9', 'f10'}, -- Quick Open. - [m('Tools/Quick Open/Quickly Open User Home')] = - {'ctrl+u', 'cmd+u', 'ctrl+u'}, + [m('Tools/Quick Open/Quickly Open User Home')] = {'ctrl+u', 'cmd+u', 'ctrl+u'}, -- TODO: m('Tools/Quickly Open Textadept Home') - [m('Tools/Quick Open/Quickly Open Current Directory')] = - {'ctrl+alt+O', 'ctrl+cmd+O', 'meta+O'}, + [m('Tools/Quick Open/Quickly Open Current Directory')] = {'ctrl+alt+O', 'ctrl+cmd+O', 'meta+O'}, [io.quick_open] = {'ctrl+alt+P', 'ctrl+cmd+P', 'ctrl+meta+p'}, -- Snippets. [textadept.snippets.select] = {'ctrl+K', 'shift+alt+\t', 'meta+K'}, @@ -399,8 +392,7 @@ local bindings = { [m('Tools/Snippets/Complete Trigger Word')] = {'ctrl+k', 'alt+\t', 'meta+k'}, -- Other. [m('Tools/Complete Symbol')] = {'ctrl+ ', 'alt+esc', 'ctrl+ '}, - [textadept.editing.show_documentation] = - {'ctrl+h', 'ctrl+h', {'meta+h', 'meta+H'}}, + [textadept.editing.show_documentation] = {'ctrl+h', 'ctrl+h', {'meta+h', 'meta+H'}}, [m('Tools/Show Style')] = {'ctrl+i', 'cmd+i', 'meta+I'}, -- Buffer. @@ -412,8 +404,7 @@ local bindings = { -- TODO: m('Buffer/Indentation/Tab width: 3') -- TODO: m('Buffer/Indentation/Tab width: 4') -- TODO: m('Buffer/Indentation/Tab width: 8') - [m('Buffer/Indentation/Toggle Use Tabs')] = - {'ctrl+alt+T', 'ctrl+T', {'meta+t', 'meta+T'}}, + [m('Buffer/Indentation/Toggle Use Tabs')] = {'ctrl+alt+T', 'ctrl+T', {'meta+t', 'meta+T'}}, [textadept.editing.convert_indentation] = {'ctrl+alt+i', 'ctrl+i', 'meta+i'}, -- EOL Mode. -- TODO: m('Buffer/EOL Mode/CRLF') @@ -430,13 +421,11 @@ local bindings = { -- View. [m('View/Next View')] = {'ctrl+alt+n', 'ctrl+alt+\t', nil}, [m('View/Previous View')] = {'ctrl+alt+p', 'ctrl+alt+shift+\t', nil}, - [m('View/Split View Horizontal')] = - {{'ctrl+alt+s', 'ctrl+alt+h'}, 'ctrl+s', nil}, + [m('View/Split View Horizontal')] = {{'ctrl+alt+s', 'ctrl+alt+h'}, 'ctrl+s', nil}, [m('View/Split View Vertical')] = {'ctrl+alt+v', 'ctrl+v', nil}, [m('View/Unsplit View')] = {'ctrl+alt+w', 'ctrl+w', nil}, [m('View/Unsplit All Views')] = {'ctrl+alt+W', 'ctrl+W', nil}, - [m('View/Grow View')] = - {{'ctrl+alt++', 'ctrl+alt+='}, {'ctrl++', 'ctrl+='}, nil}, + [m('View/Grow View')] = {{'ctrl+alt++', 'ctrl+alt+='}, {'ctrl++', 'ctrl+='}, nil}, [m('View/Shrink View')] = {'ctrl+alt+-', 'ctrl+-', nil}, [m('View/Toggle Current Fold')] = {'ctrl+*', 'cmd+*', 'meta+*'}, [m('View/Toggle Show Indent Guides')] = {'ctrl+alt+I', 'ctrl+I', nil}, @@ -450,34 +439,27 @@ local bindings = { [m('Help/Show LuaDoc')] = {'shift+f1', 'shift+f1', nil}, -- Movement commands. - -- Unbound keys are handled by Scintilla, but when playing back a macro, this - -- is not possible. Define some useful default key bindings so Scintilla does - -- not have to handle them. Note that Scintilla still will handle some keys. + -- Unbound keys are handled by Scintilla, but when playing back a macro, this is not possible. + -- Define some useful default key bindings so Scintilla does not have to handle them. Note + -- that Scintilla still will handle some keys. [buffer.line_down] = {'down', {'down', 'ctrl+n'}, {'down', 'ctrl+n'}}, - [buffer.line_down_extend] = - {'shift+down', {'shift+down', 'ctrl+N'}, 'shift+down'}, + [buffer.line_down_extend] = {'shift+down', {'shift+down', 'ctrl+N'}, 'shift+down'}, [buffer.line_up] = {'up', {'up', 'ctrl+p'}, {'up', 'ctrl+p'}}, [buffer.line_up_extend] = {'shift+up', {'shift+up', 'ctrl+P'}, 'shift+up'}, [buffer.char_left] = {'left', {'left', 'ctrl+b'}, {'left', 'ctrl+b'}}, - [buffer.char_left_extend] = - {'shift+left', {'shift+left', 'ctrl+B'}, 'shift+left'}, + [buffer.char_left_extend] = {'shift+left', {'shift+left', 'ctrl+B'}, 'shift+left'}, [buffer.word_left] = {'ctrl+left', {'alt+left', 'ctrl+cmd+b'}, 'ctrl+left'}, [buffer.word_left_extend] = {'ctrl+shift+left', {'ctrl+shift+left', 'ctrl+cmd+B'}, 'ctrl+shift+left'}, [buffer.char_right] = {'right', {'right', 'ctrl+f'}, {'right', 'ctrl+f'}}, - [buffer.char_right_extend] = - {'shift+right', {'shift+right', 'ctrl+F'}, 'shift+right'}, - [buffer.word_right] = - {'ctrl+right', {'alt+right', 'ctrl+cmd+f'}, 'ctrl+right'}, - [buffer.word_right_end_extend] = { - 'ctrl+shift+right', {'ctrl+shift+right', 'ctrl+cmd+F'}, 'ctrl+shift+right' - }, + [buffer.char_right_extend] = {'shift+right', {'shift+right', 'ctrl+F'}, 'shift+right'}, + [buffer.word_right] = {'ctrl+right', {'alt+right', 'ctrl+cmd+f'}, 'ctrl+right'}, + [buffer.word_right_end_extend] = + {'ctrl+shift+right', {'ctrl+shift+right', 'ctrl+cmd+F'}, 'ctrl+shift+right'}, [buffer.vc_home] = {'home', {'cmd+left', 'ctrl+a'}, {'home', 'ctrl+a'}}, - [buffer.vc_home_extend] = - {'shift+home', {'cmd+shift+left', 'ctrl+A'}, 'meta+A'}, + [buffer.vc_home_extend] = {'shift+home', {'cmd+shift+left', 'ctrl+A'}, 'meta+A'}, [buffer.line_end] = {'end', {'cmd+right', 'ctrl+e'}, {'end', 'ctrl+e'}}, - [buffer.line_end_extend] = - {'shift+end', {'cmd+shift+right', 'ctrl+E'}, 'meta+E'}, + [buffer.line_end_extend] = {'shift+end', {'cmd+shift+right', 'ctrl+E'}, 'meta+E'}, [view.vertical_center_caret] = {nil, 'ctrl+l', nil}, [buffer.page_up_extend] = {nil, nil, 'meta+U'}, [buffer.page_down_extend] = {nil, nil, 'meta+D'}, @@ -486,11 +468,10 @@ local bindings = { [function() buffer:line_end_extend() - if not buffer.selection_empty then buffer:cut() else buffer:clear() end + buffer[not buffer.selection_empty and 'cut' or 'clear'](buffer) end] = {nil, 'ctrl+k', 'ctrl+k'}, [buffer.del_word_right] = {'ctrl+del', 'cmd+del', 'ctrl+del'}, - [buffer.del_line_right] = - {'ctrl+shift+del', 'cmd+shift+del', 'ctrl+shift+del'}, + [buffer.del_line_right] = {'ctrl+shift+del', 'cmd+shift+del', 'ctrl+shift+del'}, [buffer.delete_back] = {'\b', '\b', {'\b', 'ctrl+h'}}, [buffer.del_word_left] = {'ctrl+\b', 'cmd+\b', nil}, [buffer.del_line_left] = {'ctrl+shift+\b', 'cmd+shift+\b', nil}, @@ -500,10 +481,10 @@ local bindings = { -- Other. -- UTF-8 input. [function() - ui.command_entry.run( - function(code) buffer:add_text(utf8.char(tonumber(code, 16))) end) + ui.command_entry.run(function(code) buffer:add_text(utf8.char(tonumber(code, 16))) end) end] = {nil, 'cmd+U', 'meta+u'} } +-- LuaFormatter on local keys, plat = keys, CURSES and 3 or OSX and 2 or 1 for f, plat_keys in pairs(bindings) do @@ -517,16 +498,14 @@ end if CURSES then keys['ctrl+meta+v'] = { - n = m('View/Next View'), p = m('View/Previous View'), - s = m('View/Split View Horizontal'), h = m('View/Split View Horizontal'), - v = m('View/Split View Vertical'), w = m('View/Unsplit View'), - W = m('View/Unsplit All Views'), ['+'] = m('View/Grow View'), + n = m('View/Next View'), p = m('View/Previous View'), s = m('View/Split View Horizontal'), + h = m('View/Split View Horizontal'), v = m('View/Split View Vertical'), + w = m('View/Unsplit View'), W = m('View/Unsplit All Views'), ['+'] = m('View/Grow View'), ['='] = m('View/Grow View'), ['-'] = m('View/Shrink View') } end --- GTK-OSX reports Fn-key as a single keycode which confuses Scintilla. Do --- not propagate it. +-- GTK-OSX reports Fn-key as a single keycode which confuses Scintilla. Do not propagate it. if OSX then keys.fn = function() return true end end return M diff --git a/modules/textadept/macros.lua b/modules/textadept/macros.lua index 90729335..9df07421 100644 --- a/modules/textadept/macros.lua +++ b/modules/textadept/macros.lua @@ -4,34 +4,30 @@ --- -- A module for recording, playing, saving, and loading keyboard macros. -- Menu commands are also recorded. --- At this time, typing into multiple cursors during macro playback is not --- supported. +-- At this time, typing into multiple cursors during macro playback is not supported. module('textadept.macros')]] local M = {} local recording, macro --- List of commands bound to keys to ignore during macro recording, as the --- command(s) ultimately executed will be recorded in some form. +-- List of commands bound to keys to ignore during macro recording, as the command(s) ultimately +-- executed will be recorded in some form. local ignore events.connect(events.INITIALIZED, function() local m_tools = textadept.menu.menubar[_L['Tools']] ignore = { textadept.menu.menubar[_L['Search']][_L['Find']][2], textadept.menu.menubar[_L['Search']][_L['Find Incremental']][2], - m_tools[_L['Select Command']][2], - m_tools[_L['Macros']][_L['Start/Stop Recording']][2] + m_tools[_L['Select Command']][2], m_tools[_L['Macros']][_L['Start/Stop Recording']][2] } end) -- Event handlers for recording macro-able events. -local function event_recorder(event) - return function(...) macro[#macro + 1] = {event, ...} end -end +local function event_recorder(event) return function(...) macro[#macro + 1] = {event, ...} end end local event_recorders = { [events.KEYPRESS] = function(code, shift, control, alt, cmd) - -- Not every keypress should be recorded (e.g. toggling macro recording). - -- Use very basic key handling to try to identify key bindings to ignore. + -- Not every keypress should be recorded (e.g. toggling macro recording). Use very basic + -- key handling to try to identify key bindings to ignore. local key = code < 256 and string.char(code) or keys.KEYSYMS[code] if key then if shift and code >= 32 and code < 256 then shift = false end @@ -40,11 +36,11 @@ local event_recorders = { for i = 1, #ignore do if keys[key_seq] == ignore[i] then return end end end macro[#macro + 1] = {events.KEYPRESS, code, shift, control, alt, cmd} - end, + end, -- LuaFormatter [events.MENU_CLICKED] = event_recorder(events.MENU_CLICKED), [events.CHAR_ADDED] = event_recorder(events.CHAR_ADDED), - [events.FIND] = event_recorder(events.FIND), - [events.REPLACE] = event_recorder(events.REPLACE), + [events.FIND] = event_recorder(events.FIND), -- LuaFormatter + [events.REPLACE] = event_recorder(events.REPLACE), -- LuaFormatter [events.UPDATE_UI] = function() if #keys.keychain == 0 then ui.statusbar_text = _L['Macro recording'] end end @@ -71,9 +67,9 @@ end -- @name play function M.play() if recording or not macro then return end - -- If this function is run as a key command, `keys.keychain` cannot be cleared - -- until this function returns. Emit 'esc' to forcibly clear it so subsequent - -- keypress events can be properly handled. + -- If this function is run as a key command, `keys.keychain` cannot be cleared until this + -- function returns. Emit 'esc' to forcibly clear it so subsequent keypress events can be + -- properly handled. events.emit(events.KEYPRESS, not CURSES and 0xFF1B or 7) -- 'esc' for _, event in ipairs(macro) do if event[1] == events.CHAR_ADDED then @@ -86,8 +82,8 @@ end --- -- Saves a recorded macro to file *filename* or the user-selected file. --- @param filename Optional filename to save the recorded macro to. If `nil`, --- the user is prompted for one. +-- @param filename Optional filename to save the recorded macro to. If `nil`, the user is +-- prompted for one. -- @name save function M.save(filename) if recording or not macro then return end @@ -102,8 +98,7 @@ function M.save(filename) for _, event in ipairs(macro) do f:write(string.format('{%q,', event[1])) for i = 2, #event do - f:write(string.format( - type(event[i]) == 'string' and '%q,' or '%s,', event[i])) + f:write(string.format(type(event[i]) == 'string' and '%q,' or '%s,', event[i])) end f:write('},\n') end @@ -112,8 +107,7 @@ end --- -- Loads a macro from file *filename* or the user-selected file. --- @param filename Optional macro file to load. If `nil`, the user is prompted --- for one. +-- @param filename Optional macro file to load. If `nil`, the user is prompted for one. -- @name load function M.load(filename) if recording then return end diff --git a/modules/textadept/menu.lua b/modules/textadept/menu.lua index cd56cf73..54195bd9 100644 --- a/modules/textadept/menu.lua +++ b/modules/textadept/menu.lua @@ -6,19 +6,20 @@ local M = {} --[[ This comment is for LuaDoc. --- -- Defines the menus used by Textadept. --- Menus are simply tables of menu items and submenus and may be edited in --- place. A menu item itself is a table whose first element is a menu label and --- whose second element is a menu command to run. Submenus have `title` keys --- assigned to string text. +-- Menus are simply tables of menu items and submenus and may be edited in place. A menu item +-- itself is a table whose first element is a menu label and whose second element is a menu +-- command to run. Submenus have `title` keys assigned to string text. module('textadept.menu')]] local _L, SEPARATOR = _L, {''} --- The following buffer and view functions need to be made constant in order for --- menu items to identify the key associated with the functions. +-- LuaFormatter off +-- The following buffer and view functions need to be made constant in order for menu items to +-- identify the key associated with the functions. local menu_buffer_functions = {'undo','redo','cut','copy','paste','line_duplicate','clear','select_all','upper_case','lower_case','move_selected_lines_up','move_selected_lines_down'} for _, f in ipairs(menu_buffer_functions) do buffer[f] = buffer[f] end view.zoom_in, view.zoom_out = view.zoom_in, view.zoom_out +-- LuaFormatter on -- Commonly used functions in menu commands. local sel_enc = textadept.editing.select_enclosed @@ -41,10 +42,11 @@ local function open_page(url) os.spawn(string.format('%s "%s"', cmd, not OSX and url or 'file://' .. url)) end +-- LuaFormatter off --- -- The default main menubar. --- Individual menus, submenus, and menu items can be retrieved by name in --- addition to table index number. +-- Individual menus, submenus, and menu items can be retrieved by name in addition to table +-- index number. -- @class table -- @name menubar -- @usage textadept.menu.menubar[_L['File']][_L['New']] @@ -89,9 +91,7 @@ local default_menubar = { local match_pos = buffer:brace_match(buffer.current_pos, 0) if match_pos ~= -1 then buffer:goto_pos(match_pos) end end}, - {_L['Complete Word'], function() - textadept.editing.autocomplete('word') - end}, + {_L['Complete Word'], function() textadept.editing.autocomplete('word') end}, {_L['Toggle Block Comment'], textadept.editing.toggle_comment}, {_L['Transpose Characters'], textadept.editing.transpose_chars}, {_L['Join Lines'], textadept.editing.join_lines}, @@ -156,9 +156,7 @@ local default_menubar = { SEPARATOR, {_L['Find in Files'], function() ui.find.focus{in_files = true} end}, {_L['Goto Next File Found'], function() ui.find.goto_file_found(true) end}, - {_L['Goto Previous File Found'], function() - ui.find.goto_file_found(false) - end}, + {_L['Goto Previous File Found'], function() ui.find.goto_file_found(false) end}, SEPARATOR, {_L['Jump to'], textadept.editing.goto_line} }, @@ -181,9 +179,7 @@ local default_menubar = { {_L['Toggle Bookmark'], textadept.bookmarks.toggle}, {_L['Clear Bookmarks'], textadept.bookmarks.clear}, {_L['Next Bookmark'], function() textadept.bookmarks.goto_mark(true) end}, - {_L['Previous Bookmark'], function() - textadept.bookmarks.goto_mark(false) - end}, + {_L['Previous Bookmark'], function() textadept.bookmarks.goto_mark(false) end}, {_L['Goto Bookmark...'], textadept.bookmarks.goto_mark}, }, { @@ -199,8 +195,7 @@ local default_menubar = { {_L['Quickly Open User Home'], function() io.quick_open(_USERHOME) end}, {_L['Quickly Open Textadept Home'], function() io.quick_open(_HOME) end}, {_L['Quickly Open Current Directory'], function() - if not buffer.filename then return end - io.quick_open(buffer.filename:match('^(.+)[/\\]')) + if buffer.filename then io.quick_open(buffer.filename:match('^(.+)[/\\]')) end end}, {_L['Quickly Open Current Project'], io.quick_open}, }, @@ -211,25 +206,18 @@ local default_menubar = { {_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} + {_L['Complete Trigger Word'], function() textadept.editing.autocomplete('snippets') end} }, SEPARATOR, - {_L['Complete Symbol'], function() - textadept.editing.autocomplete(buffer:get_lexer(true)) - end}, + {_L['Complete Symbol'], function() textadept.editing.autocomplete(buffer:get_lexer(true)) end}, {_L['Show Documentation'], textadept.editing.show_documentation}, {_L['Show Style'], function() - local char = buffer:text_range( - buffer.current_pos, buffer:position_after(buffer.current_pos)) + local char = buffer:text_range(buffer.current_pos, buffer:position_after(buffer.current_pos)) if char == '' then return end -- end of buffer local bytes = string.rep(' 0x%X', #char):format(char:byte(1, #char)) local style = buffer.style_at[buffer.current_pos] - local text = string.format( - "'%s' (U+%04X:%s)\n%s %s\n%s %s (%d)", char, utf8.codepoint(char), - bytes, _L['Lexer'], buffer:get_lexer(true), _L['Style'], - buffer:name_of_style(style), style) + local text = string.format("'%s' (U+%04X:%s)\n%s %s\n%s %s (%d)", char, utf8.codepoint(char), + bytes, _L['Lexer'], buffer:get_lexer(true), _L['Style'], buffer:name_of_style(style), style) view:call_tip_show(buffer.current_pos, text) end} }, @@ -299,12 +287,11 @@ local default_menubar = { end}, SEPARATOR, {_L['Toggle Show Indent Guides'], function() - view.indentation_guides = - view.indentation_guides == 0 and view.IV_LOOKBOTH or 0 + view.indentation_guides = view.indentation_guides == 0 and view.IV_LOOKBOTH or 0 end}, {_L['Toggle Virtual Space'], function() - buffer.virtual_space_options = - buffer.virtual_space_options == 0 and buffer.VS_USERACCESSIBLE or 0 + buffer.virtual_space_options = buffer.virtual_space_options == 0 and + buffer.VS_USERACCESSIBLE or 0 end}, SEPARATOR, {_L['Zoom In'], view.zoom_in}, @@ -327,8 +314,7 @@ local default_menubar = { --- -- The default right-click context menu. --- Submenus, and menu items can be retrieved by name in addition to table index --- number. +-- Submenus, and menu items can be retrieved by name in addition to table index number. -- @class table -- @name context_menu -- @usage textadept.menu.context_menu[#textadept.menu.context_menu + 1] = {...} @@ -346,8 +332,7 @@ local default_context_menu = { --- -- The default tabbar context menu. --- Submenus, and menu items can be retrieved by name in addition to table index --- number. +-- Submenus, and menu items can be retrieved by name in addition to table index number. -- @class table -- @name tab_context_menu local default_tab_context_menu = { @@ -358,6 +343,7 @@ local default_tab_context_menu = { SEPARATOR, {_L['Reload'], buffer.reload}, } +-- LuaFormatter on -- Table of proxy tables for menus. local proxies = {} @@ -378,7 +364,10 @@ local function get_gdk_key(key_seq) local code = string.byte(key) if #key > 1 or code < 32 then for i, s in pairs(keys.KEYSYMS) do - if s == key and i > 0xFE20 then code = i break end + if s == key and i > 0xFE20 then + code = i + break + end end end return code, modifiers @@ -387,8 +376,8 @@ end -- Creates a menu suitable for `ui.menu()` from the menu table format. -- Also assigns key bindings. -- @param menu The menu to create a GTK menu from. --- @param contextmenu Flag indicating whether or not the menu is a context menu. --- If so, menu_id offset is 1000. The default value is `false`. +-- @param contextmenu Flag indicating whether or not the menu is a context menu. If so, menu_id +-- offset is 1000. The default value is `false`. -- @return GTK menu that can be passed to `ui.menu()`. -- @see ui.menu local function read_menu_table(menu, contextmenu) @@ -397,8 +386,7 @@ local function read_menu_table(menu, contextmenu) if item.title then gtkmenu[#gtkmenu + 1] = read_menu_table(item, contextmenu) else -- item = {label, function} - local menu_id = - not contextmenu and #menu_items + 1 or #contextmenu_items + 1000 + 1 + local menu_id = not contextmenu and #menu_items + 1 or #contextmenu_items + 1000 + 1 local key, mods = get_gdk_key(key_shortcuts[tostring(item[2])]) gtkmenu[#gtkmenu + 1] = {item[1], menu_id, key, mods} if item[2] then @@ -410,13 +398,12 @@ local function read_menu_table(menu, contextmenu) return gtkmenu end --- Returns a proxy table for menu table *menu* such that when a menu item is --- changed or added, *update* is called to update the menu in the UI. +-- Returns a proxy table for menu table *menu* such that when a menu item is changed or added, +-- *update* is called to update the menu in the UI. -- @param menu The menu or table of menus to create a proxy for. --- @param update The function to call to update the menu in the UI when a menu --- item is changed or added. --- @param menubar Used internally to keep track of the top-level menu for --- calling *update* with. +-- @param update The function to call to update the menu in the UI when a menu item is changed +-- or added. +-- @param menubar Used internally to keep track of the top-level menu for calling *update* with. local function proxy_menu(menu, update, menubar) return setmetatable({}, { __index = function(_, k) @@ -425,60 +412,59 @@ local function proxy_menu(menu, update, menubar) v = menu[k] elseif type(k) == 'string' then for _, item in ipairs(menu) do - if item.title == k or item[1] == k then v = item break end + if item.title == k or item[1] == k then + v = item + break + end end end return type(v) == 'table' and proxy_menu(v, update, menubar or menu) or v - end, + end, -- LuaFormatter __newindex = function(_, k, v) menu[k] = getmetatable(v) and getmetatable(v).menu or v - -- After adding or removing menus or menu items, update the menubar or - -- context menu. When updating a menu item's function, do nothing extra. + -- After adding or removing menus or menu items, update the menubar or context menu. When + -- updating a menu item's function, do nothing extra. if type(v) ~= 'function' then update(menubar or menu) end - end, - __len = function() return #menu end, - menu = menu -- store existing menu for copying (e.g. m[#m + 1] = m[#m]) + end, __len = function() return #menu end, menu = menu -- store existing menu for copying (e.g. m[#m + 1] = m[#m]) }) end -- Sets `ui.menubar` from menu table *menubar*. --- Each menu is an ordered list of menu items and has a `title` key for the --- title text. Menu items are tables containing menu text and either a function --- to call or a table containing a function with its parameters to call when an --- item is clicked. Menu items may also be sub-menus, ordered lists of menu --- items with an additional `title` key for the sub-menu's title text. --- @param menubar The table of menu tables to create the menubar from. If `nil`, --- clears the menubar from view, but keeps it intact in order for --- `M.select_command()` to function properly. +-- Each menu is an ordered list of menu items and has a `title` key for the title text. Menu +-- items are tables containing menu text and either a function to call or a table containing a +-- function with its parameters to call when an item is clicked. Menu items may also be sub-menus, +-- ordered lists of menu items with an additional `title` key for the sub-menu's title text. +-- @param menubar The table of menu tables to create the menubar from. If `nil`, clears the +-- menubar from view, but keeps it intact in order for `M.select_command()` to function properly. -- @see ui.menubar -- @see ui.menu local function set_menubar(menubar) - if not menubar then ui.menubar = {} return end + if not menubar then + ui.menubar = {} + return + end key_shortcuts, menu_items = {}, {} -- reset for key, f in pairs(keys) do key_shortcuts[tostring(f)] = key end local _menubar = {} - for _, menu in ipairs(menubar) do - _menubar[#_menubar + 1] = ui.menu(read_menu_table(menu)) - end + for _, menu in ipairs(menubar) do _menubar[#_menubar + 1] = ui.menu(read_menu_table(menu)) end ui.menubar = _menubar proxies.menubar = proxy_menu(menubar, set_menubar) end events.connect(events.INITIALIZED, function() set_menubar(default_menubar) end) -- Define menu proxy for use by keys.lua and user scripts. --- Do not use an update function because this is expensive at startup, and --- `events.INITIALIZED` will create the first visible menubar and proper proxy. +-- Do not use an update function because this is expensive at startup, and `events.INITIALIZED` +-- will create the first visible menubar and proper proxy. proxies.menubar = proxy_menu(default_menubar, function() end) --- Sets `ui.context_menu` and `ui.tab_context_menu` from menu item lists --- *buffer_menu* and *tab_menu*, respectively. --- Menu items are tables containing menu text and either a function to call or --- a table containing a function with its parameters to call when an item is --- clicked. Menu items may also be sub-menus, ordered lists of menu items with --- an additional `title` key for the sub-menu's title text. --- @param buffer_menu Optional menu table to create the buffer context menu --- from. If `nil`, uses the default context menu. --- @param tab_menu Optional menu table to create the tabbar context menu from. --- If `nil`, uses the default tab context menu. +-- Sets `ui.context_menu` and `ui.tab_context_menu` from menu item lists *buffer_menu* and +-- *tab_menu*, respectively. +-- Menu items are tables containing menu text and either a function to call or a table containing a +-- function with its parameters to call when an item is clicked. Menu items may also be sub-menus, +-- ordered lists of menu items with an additional `title` key for the sub-menu's title text. +-- @param buffer_menu Optional menu table to create the buffer context menu from. If `nil`, +-- uses the default context menu. +-- @param tab_menu Optional menu table to create the tabbar context menu from. If `nil`, uses +-- the default tab context menu. -- @see ui.context_menu -- @see ui.tab_context_menu -- @see ui.menu @@ -497,9 +483,8 @@ local function set_contextmenus(buffer_menu, tab_menu) end events.connect(events.INITIALIZED, set_contextmenus) -- Define menu proxies for use by user scripts. --- Do not use an update function because this is expensive at startup, and --- `events.INITIALIZED` will create these visible menus and their proper --- proxies. +-- Do not use an update function because this is expensive at startup, and `events.INITIALIZED` +-- will create these visible menus and their proper proxies. proxies.context_menu = proxy_menu(default_context_menu, function() end) proxies.tab_context_menu = proxy_menu(default_tab_context_menu, function() end) @@ -522,8 +507,7 @@ function M.select_command() if item.title then build_command_tables(item) elseif item[1] ~= '' then -- item = {label, function} - local label = - menu.title and string.format('%s: %s', menu.title, item[1]) or item[1] + local label = menu.title and string.format('%s: %s', menu.title, item[1]) or item[1] items[#items + 1] = label:gsub('_([^_])', '%1') items[#items + 1] = key_shortcuts[tostring(item[2])] or '' end @@ -531,15 +515,13 @@ function M.select_command() end build_command_tables(getmetatable(M.menubar).menu) local button, i = ui.dialogs.filteredlist{ - title = _L['Run Command'], columns = {_L['Command'], _L['Key Binding']}, - items = items + title = _L['Run Command'], columns = {_L['Command'], _L['Key Binding']}, items = items } if button == 1 and i then events.emit(events.MENU_CLICKED, i) end end return setmetatable(M, { - __index = function(_, k) return proxies[k] or rawget(M, k) end, - __newindex = function(_, k, v) + __index = function(_, k) return proxies[k] or rawget(M, k) end, __newindex = function(_, k, v) if k == 'menubar' then set_menubar(v) elseif k == 'context_menu' then diff --git a/modules/textadept/run.lua b/modules/textadept/run.lua index 3e0b4295..d39e7919 100644 --- a/modules/textadept/run.lua +++ b/modules/textadept/run.lua @@ -5,14 +5,12 @@ local M = {} --[[ This comment is for LuaDoc. --- -- Compile and run source code files with Textadept. --- [Language modules](#compile-and-run) may tweak the `compile_commands`, --- `run_commands`, and `error_patterns` tables for particular languages. --- The user may tweak `build_commands` and `test_commands` for particular --- projects. +-- [Language modules](#compile-and-run) may tweak the `compile_commands`, `run_commands`, and +-- `error_patterns` tables for particular languages. +-- The user may tweak `build_commands` and `test_commands` for particular projects. -- @field run_in_background (bool) -- Run shell commands silently in the background. --- This only applies when the message buffer is open, though it does not have --- to be visible. +-- This only applies when the message buffer is open, though it does not have to be visible. -- The default value is `false`. -- @field MARK_WARNING (number) -- The run or compile warning marker number. @@ -20,34 +18,32 @@ local M = {} -- The run or compile error marker number. -- @field _G.events.COMPILE_OUTPUT (string) -- Emitted when executing a language's compile shell command. --- By default, compiler output is printed to the message buffer. In order to --- override this behavior, connect to the event with an index of `1` and --- return `true`. +-- By default, compiler output is printed to the message buffer. In order to override this +-- behavior, connect to the event with an index of `1` and return `true`. -- Arguments: -- -- * `output`: A line of string output from the command. --- * `ext_or_lexer`: The file extension or lexer name associated with the --- executed compile command. +-- * `ext_or_lexer`: The file extension or lexer name associated with the executed compile +-- command. -- @field _G.events.RUN_OUTPUT (string) -- Emitted when executing a language's run shell command. --- By default, output is printed to the message buffer. In order to override --- this behavior, connect to the event with an index of `1` and return `true`. +-- By default, output is printed to the message buffer. In order to override this behavior, +-- connect to the event with an index of `1` and return `true`. -- Arguments: -- -- * `output`: A line of string output from the command. --- * `ext_or_lexer`: The file extension or lexer name associated with the --- executed run command. +-- * `ext_or_lexer`: The file extension or lexer name associated with the executed run command. -- @field _G.events.BUILD_OUTPUT (string) -- Emitted when executing a project's build shell command. --- By default, output is printed to the message buffer. In order to override --- this behavior, connect to the event with an index of `1` and return `true`. +-- By default, output is printed to the message buffer. In order to override this behavior, +-- connect to the event with an index of `1` and return `true`. -- Arguments: -- -- * `output`: A line of string output from the command. -- @field _G.events.TEST_OUTPUT (string) -- Emitted when executing a project's shell command for running tests. --- By default, output is printed to the message buffer. In order to override --- this behavior, connect to the event with an index of `1` and return `true`. +-- By default, output is printed to the message buffer. In order to override this behavior, +-- connect to the event with an index of `1` and return `true`. -- Arguments: -- -- * `output`: A line of string output from the command. @@ -59,26 +55,23 @@ M.MARK_WARNING = _SCINTILLA.next_marker_number() M.MARK_ERROR = _SCINTILLA.next_marker_number() -- Events. -local run_events = { - 'compile_output', 'run_output', 'build_output', 'test_output' -} +local run_events = {'compile_output', 'run_output', 'build_output', 'test_output'} for _, v in ipairs(run_events) do events[v:upper()] = v end --- Keep track of: the last process spawned in order to kill it if requested; the --- cwd of that process in order to jump to relative file paths in recognized --- warning or error messages; and the view the process was spawned from in order --- to jump to messages (which are displayed in a split view) in the original --- view. +-- Keep track of: the last process spawned in order to kill it if requested; the cwd of that +-- process in order to jump to relative file paths in recognized warning or error messages; +-- and the view the process was spawned from in order to jump to messages (which are displayed +-- in a split view) in the original view. local proc, cwd, preferred_view --- Scans the given message for a warning or error message and, if one is found, --- returns table of the warning/error's details. --- @param message The message to parse for warnings or errors. The message --- is assumed to be encoded in _CHARSET. --- @param ext_or_lexer Optional file extension or lexer name associated with the --- shell command that produced the warning/error. --- @return error details table with 'filename', 'line', 'column', and 'message' --- fields along with a 'warning' flag. +-- Scans the given message for a warning or error message and, if one is found, returns table +-- of the warning/error's details. +-- @param message The message to parse for warnings or errors. The message is assumed to be +-- encoded in _CHARSET. +-- @param ext_or_lexer Optional file extension or lexer name associated with the shell command +-- that produced the warning/error. +-- @return error details table with 'filename', 'line', 'column', and 'message' fields along +-- with a 'warning' flag. -- @see error_patterns local function scan_for_error(message, ext_or_lexer) for key, patterns in pairs(M.error_patterns) do @@ -99,15 +92,13 @@ local function scan_for_error(message, ext_or_lexer) i = i + 1 end local lower_message = message:lower() - detail.warning = - (lower_message:find('warning') or lower_message:find('note')) and + detail.warning = (lower_message:find('warning') or lower_message:find('note')) and not lower_message:find('error') - -- Compile and run commands specify the file extension or lexer name used - -- to determine the command, so the error patterns used are guaranteed to - -- be correct. Build and test commands have no such context and instead - -- iterate through all possible error patterns. Only consider the - -- error/warning valid if the extracted filename's extension or lexer name - -- matches the error pattern's extension or lexer name. + -- Compile and run commands specify the file extension or lexer name used to determine + -- the command, so the error patterns used are guaranteed to be correct. Build and + -- test commands have no such context and instead iterate through all possible error + -- patterns. Only consider the error/warning valid if the extracted filename's extension + -- or lexer name matches the error pattern's extension or lexer name. if ext_or_lexer then return detail end local ext = detail.filename:match('[^/\\.]+$') local lexer_name = textadept.file_types.extensions[ext] @@ -120,33 +111,30 @@ local function scan_for_error(message, ext_or_lexer) end -- Prints an output line from a compile, run, build, or test shell command. --- Assume output is UTF-8 unless there's a recognized warning or error message. --- In that case assume it is encoded in _CHARSET and mark it. +-- Assume output is UTF-8 unless there's a recognized warning or error message. In that case +-- assume it is encoded in _CHARSET and mark it. -- All stdout and stderr from the command is printed silently. -- @param line The output line to print. --- @param ext_or_lexer Optional file extension or lexer name associated with the --- executed command. This is used for better error detection in compile and --- run commands. +-- @param ext_or_lexer Optional file extension or lexer name associated with the executed command. +-- This is used for better error detection in compile and run commands. local function print_line(line, ext_or_lexer) local error = scan_for_error(line, ext_or_lexer) - ui.silent_print = M.run_in_background or ext_or_lexer or - not line:find('^> ') or line:find('^> exit') + ui.silent_print = M.run_in_background or ext_or_lexer or not line:find('^> ') or + line:find('^> exit') ui.print(not error and line or line:iconv('UTF-8', _CHARSET)) ui.silent_print = false if error then -- Current position is one line below the error due to ui.print()'s '\n'. - buffer:marker_add( - buffer.line_count - 1, error.warning and M.MARK_WARNING or M.MARK_ERROR) + buffer:marker_add(buffer.line_count - 1, error.warning and M.MARK_WARNING or M.MARK_ERROR) end end local output_buffer --- Prints the output from a compile, run, build, or test shell command as a --- series of lines, performing buffering as needed. +-- Prints the output from a compile, run, build, or test shell command as a series of lines, +-- performing buffering as needed. -- @param output The output to print, or `nil` to flush any buffered output. --- @param ext_or_lexer Optional file extension or lexer name associated with the --- executed command. This is used for better error detection in compile and --- run commands. +-- @param ext_or_lexer Optional file extension or lexer name associated with the executed command. +-- This is used for better error detection in compile and run commands. local function print_output(output, ext_or_lexer) if output then if output_buffer then output = output_buffer .. output end @@ -162,17 +150,15 @@ local function print_output(output, ext_or_lexer) end end --- Runs command *command* in working directory *dir*, emitting events of type --- *event* with any output received. --- @param command String command to run, or a function returning such a string --- and optional working directory and environment table. A returned working --- directory overrides *dir*. +-- Runs command *command* in working directory *dir*, emitting events of type *event* with any +-- output received. +-- @param command String command to run, or a function returning such a string and optional +-- working directory and environment table. A returned working directory overrides *dir*. -- @param dir String working directory to run *command* in. -- @param event String event name to emit command output with. -- @param macros Optional table of '%[char]' macros to expand within *command*. --- @param ext_or_lexer Optional file extension or lexer name associated with the --- executed command. This is used for better error detection in compile and --- run commands. +-- @param ext_or_lexer Optional file extension or lexer name associated with the executed command. +-- This is used for better error detection in compile and run commands. local function run_command(command, dir, event, macros, ext_or_lexer) local working_dir, env if type(command) == 'function' then command, working_dir, env = command() end @@ -183,10 +169,12 @@ local function run_command(command, dir, event, macros, ext_or_lexer) cwd = (working_dir or dir):gsub('[/\\]$', '') events.emit(event, string.format('> cd %s\n', cwd)) events.emit(event, string.format('> %s\n', command:iconv('UTF-8', _CHARSET))) - local args = {command, cwd, emit, emit, function(status) - emit() -- flush - events.emit(event, string.format('> exit status: %d\n', status)) - end} + local args = { + command, cwd, emit, emit, function(status) + emit() -- flush + events.emit(event, string.format('> exit status: %d\n', status)) + end + } if env then table.insert(args, 3, env) end proc = assert(os.spawn(table.unpack(args))) end @@ -204,21 +192,18 @@ local function compile_or_run(filename, commands) textadept.file_types.extensions[ext] local command = commands[filename] or commands[ext] or commands[lang] local dirname, basename = '', filename - if filename:find('[/\\]') then - dirname, basename = filename:match('^(.+)[/\\]([^/\\]+)$') - end - local event = commands == M.compile_commands and events.COMPILE_OUTPUT or - events.RUN_OUTPUT + if filename:find('[/\\]') then dirname, basename = filename:match('^(.+)[/\\]([^/\\]+)$') end + local event = commands == M.compile_commands and events.COMPILE_OUTPUT or events.RUN_OUTPUT local macros = { - ['%p'] = filename, ['%d'] = dirname, ['%f'] = basename, - ['%e'] = basename:match('^(.+)%.') -- no extension + ['%p'] = filename, ['%d'] = dirname, ['%f'] = basename, ['%e'] = basename:match('^(.+)%.') -- no extension } run_command(command, dirname, event, macros, commands[ext] and ext or lang) end +-- LuaFormatter off --- --- Map of filenames, file extensions, and lexer names to their associated --- "compile" shell command line strings or functions that return such strings. +-- Map of filenames, file extensions, and lexer names to their associated "compile" shell +-- command line strings or functions that return such strings. -- Command line strings may have the following macros: -- -- + `%f`: The file's name, including its extension. @@ -226,21 +211,21 @@ end -- + `%d`: The file's directory path. -- + `%p`: The file's full path. -- --- Functions may also return a working directory and process environment table --- to operate in. By default, the working directory is the current file's parent --- directory and the environment is Textadept's environment. +-- Functions may also return a working directory and process environment table to operate in. By +-- default, the working directory is the current file's parent directory and the environment +-- is Textadept's environment. -- @class table -- @name compile_commands M.compile_commands = {actionscript='mxmlc "%f"',ada='gnatmake "%f"',ansi_c='gcc -o "%e" "%f"',antlr='antlr4 "%f"',g='antlr3 "%f"',applescript='osacompile "%f" -o "%e.scpt"',asm='nasm "%f"'--[[ && ld "%e.o" -o "%e"']],boo='booc "%f"',caml='ocamlc -o "%e" "%f"',csharp=WIN32 and 'csc "%f"' or 'mcs "%f"',coffeescript='coffee -c "%f"',context='context --nonstopmode "%f"',cpp='g++ -o "%e" "%f"',cuda=WIN32 and 'nvcc -o "%e.exe" "%f"' or 'nvcc -o "%e" "%f"',dmd='dmd "%f"',dot='dot -Tps "%f" -o "%e.ps"',eiffel='se c "%f"',elixir='elixirc "%f"',erlang='erl -compile "%e"',faust='faust -o "%e.cpp" "%f"',fsharp=WIN32 and 'fsc.exe "%f"' or 'mono fsc.exe "%f"',fortran='gfortran -o "%e" "%f"',gap='gac -o "%e" "%f"',go='go build "%f"',groovy='groovyc "%f"',haskell=WIN32 and 'ghc -o "%e.exe" "%f"' or 'ghc -o "%e" "%f"',inform=function() return 'inform -c "'..buffer.filename:match('^(.+%.inform[/\\])Source')..'"' end,java='javac "%f"',ltx='pdflatex -file-line-error -halt-on-error "%f"',less='lessc --no-color "%f" "%e.css"',lilypond='lilypond "%f"',lisp='clisp -c "%f"',litcoffee='coffee -c "%f"',lua='luac -o "%e.luac" "%f"',moon='moonc "%f"',markdown='markdown "%f" > "%e.html"',myr='mbld -b "%e" "%f"',nemerle='ncc "%f" -out:"%e.exe"',nim='nim c "%f"',nsis='MakeNSIS "%f"',objective_c='gcc -o "%e" "%f"',pascal='fpc "%f"',perl='perl -c "%f"',php='php -l "%f"',pony='ponyc "%f"',prolog='gplc --no-top-level "%f"',python='python -m py_compile "%f"',ruby='ruby -c "%f"',rust='rustc "%f"',sass='sass "%f" "%e.css"',scala='scalac "%f"',sml='mlton "%f"',tex='pdflatex -file-line-error -halt-on-error "%f"',typescript='tsc "%f"',vala='valac "%f"',vb=WIN32 and 'vbc "%f"' or 'vbnc "%f"',zig='zig build-exe "%f"'} +-- LuaFormatter on --- --- Compiles file *filename* or the current file using an appropriate shell --- command from the `compile_commands` table. --- The shell command is determined from the file's filename, extension, or --- language in that order. +-- Compiles file *filename* or the current file using an appropriate shell command from the +-- `compile_commands` table. +-- The shell command is determined from the file's filename, extension, or language in that order. -- Emits `COMPILE_OUTPUT` events. --- @param filename Optional path to the file to compile. The default value is --- the current file's filename. +-- @param filename Optional path to the file to compile. The default value is the current +-- file's filename. -- @see compile_commands -- @see _G.events -- @name compile @@ -251,9 +236,10 @@ function M.compile(filename) end events.connect(events.COMPILE_OUTPUT, print_output) +-- LuaFormatter off --- --- Map of filenames, file extensions, and lexer names to their associated "run" --- shell command line strings or functions that return strings. +-- Map of filenames, file extensions, and lexer names to their associated "run" shell command +-- line strings or functions that return strings. -- Command line strings may have the following macros: -- -- + `%f`: The file's name, including its extension. @@ -261,21 +247,21 @@ events.connect(events.COMPILE_OUTPUT, print_output) -- + `%d`: The file's directory path. -- + `%p`: The file's full path. -- --- Functions may also return a working directory and process environment table --- to operate in. By default, the working directory is the current file's parent --- directory and the environment is Textadept's environment. +-- Functions may also return a working directory and process environment table to operate in. By +-- default, the working directory is the current file's parent directory and the environment +-- is Textadept's environment. -- @class table -- @name run_commands M.run_commands = {actionscript=WIN32 and 'start "" "%e.swf"' or OSX and 'open "file://%e.swf"' or 'xdg-open "%e.swf"',ada=WIN32 and '"%e"' or './"%e"',ansi_c=WIN32 and '"%e"' or './"%e"',applescript='osascript "%f"',asm='./"%e"',awk='awk -f "%f"',batch='"%f"',boo='booi "%f"',caml='ocamlrun "%e"',csharp=WIN32 and '"%e"' or 'mono "%e.exe"',chuck='chuck "%f"',clojure='clj -M "%f"',cmake='cmake -P "%f"',coffeescript='coffee "%f"',context=WIN32 and 'start "" "%e.pdf"' or OSX and 'open "%e.pdf"' or 'xdg-open "%e.pdf"',cpp=WIN32 and '"%e"' or './"%e"',crystal='crystal "%f"',cuda=WIN32 and '"%e"' or './"%e"',dart='dart "%f"',dmd=WIN32 and '"%e"' or './"%e"',eiffel="./a.out",elixir='elixir "%f"',fsharp=WIN32 and '"%e"' or 'mono "%e.exe"',fantom='fan "%f"',fennel='fennel "%f"',forth='gforth "%f" -e bye',fortran=WIN32 and '"%e"' or './"%e"',gnuplot='gnuplot "%f"',go='go run "%f"',groovy='groovy "%f"',haskell=WIN32 and '"%e"' or './"%e"',html=WIN32 and 'start "" "%f"' or OSX and 'open "file://%f"' or 'xdg-open "%f"',icon='icont "%e" -x',idl='idl -batch "%f"',Io='io "%f"',java='java "%e"',javascript='node "%f"',jq='jq -f "%f"',julia='julia "%f"',ltx=WIN32 and 'start "" "%e.pdf"' or OSX and 'open "%e.pdf"' or 'xdg-open "%e.pdf"',less='lessc --no-color "%f"',lilypond=WIN32 and 'start "" "%e.pdf"' or OSX and 'open "%e.pdf"' or 'xdg-open "%e.pdf"',lisp='clisp "%f"',litcoffee='coffee "%f"',lua='lua -e "io.stdout:setvbuf(\'no\')" "%f"',makefile=WIN32 and 'nmake -f "%f"' or 'make -f "%f"',markdown='markdown "%f"',moon='moon "%f"',myr=WIN32 and '"%e"' or './"%e"',nemerle=WIN32 and '"%e"' or 'mono "%e.exe"',nim='nim c -r "%f"',objective_c=WIN32 and '"%e"' or './"%e"',pascal=WIN32 and '"%e"' or './"%e"',perl='perl "%f"',php='php "%f"',pike='pike "%f"',pkgbuild='makepkg -p "%f"',pony=WIN32 and '"%e"' or './"%e"',prolog=WIN32 and '"%e"' or './"%e"',pure='pure "%f"',python=function() return buffer:get_line(1):find('^#!.-python3') and 'python3 -u "%f"' or 'python -u "%f"' end,rstats=WIN32 and 'Rterm -f "%f"' or 'R -f "%f"',rebol='REBOL "%f"',rexx=WIN32 and 'rexx "%f"' or 'regina "%f"',ruby='ruby "%f"',rust=WIN32 and '"%e"' or './"%e"',sass='sass "%f"',scala='scala "%e"',bash='bash "%f"',csh='tcsh "%f"',ksh='ksh "%f"',mksh='mksh "%f"',sh='sh "%f"',zsh='zsh "%f"',rc='rc "%f"',smalltalk='gst "%f"',sml=WIN32 and '"%e"' or './"%e"',snobol4='snobol4 -b "%f"',tcl='tclsh "%f"',tex=WIN32 and 'start "" "%e.pdf"' or OSX and 'open "%e.pdf"' or 'xdg-open "%e.pdf"',vala=WIN32 and '"%e"' or './"%e"',vb=WIN32 and '"%e"' or 'mono "%e.exe"',xs='xs "%f"',zig=WIN32 and '"%e"' or './"%e"'} +-- LuaFormatter on --- --- Runs file *filename* or the current file using an appropriate shell command --- from the `run_commands` table. --- The shell command is determined from the file's filename, extension, or --- language in that order. +-- Runs file *filename* or the current file using an appropriate shell command from the +-- `run_commands` table. +-- The shell command is determined from the file's filename, extension, or language in that order. -- Emits `RUN_OUTPUT` events. --- @param filename Optional path to the file to run. The default value is the --- current file's filename. +-- @param filename Optional path to the file to run. The default value is the current file's +-- filename. -- @see run_commands -- @see _G.events -- @name run @@ -287,15 +273,15 @@ end events.connect(events.RUN_OUTPUT, print_output) --- --- Appends the command line argument strings *run* and *compile* to their --- respective run and compile commands for file *filename* or the current file. --- If either is `nil`, prompts the user for missing the arguments. Each filename --- has its own set of compile and run arguments. +-- Appends the command line argument strings *run* and *compile* to their respective run and +-- compile commands for file *filename* or the current file. +-- If either is `nil`, prompts the user for missing the arguments. Each filename has its own +-- set of compile and run arguments. -- @param filename Optional path to the file to set run/compile arguments for. --- @param run Optional string run arguments to set. If `nil`, the user is --- prompted for them. Pass the empty string for no run arguments. --- @param compile Optional string compile arguments to set. If `nil`, the user --- is prompted for them. Pass the empty string for no compile arguments. +-- @param run Optional string run arguments to set. If `nil`, the user is prompted for them. Pass +-- the empty string for no run arguments. +-- @param compile Optional string compile arguments to set. If `nil`, the user is prompted +-- for them. Pass the empty string for no compile arguments. -- @see run_commands -- @see compile_commands -- @name set_arguments @@ -308,52 +294,49 @@ function M.set_arguments(filename, run, compile) assert_type(compile, 'string/nil', 3) local base_commands, utf8_args = {}, {} for i, commands in ipairs{M.run_commands, M.compile_commands} do - -- Compare the base run/compile command with the one for the current - -- file. The difference is any additional arguments set previously. - base_commands[i] = commands[filename:match('[^.]+$')] or - commands[buffer:get_lexer()] or '' + -- Compare the base run/compile command with the one for the current file. The difference + -- is any additional arguments set previously. + base_commands[i] = commands[filename:match('[^.]+$')] or commands[buffer:get_lexer()] or '' local current_command = commands[filename] or '' - local args = (i == 1 and run or compile) or - current_command:sub(#base_commands[i] + 2) + local args = (i == 1 and run or compile) or current_command:sub(#base_commands[i] + 2) utf8_args[i] = args:iconv('UTF-8', _CHARSET) end if not run or not compile then local button button, utf8_args = ui.dialogs.inputbox{ - title = _L['Set Arguments...']:gsub('_', ''), informative_text = { - _L['Command line arguments'], _L['For Run:'], _L['For Compile:'] - }, text = utf8_args, width = not CURSES and 400 or nil + title = _L['Set Arguments...']:gsub('_', ''), + informative_text = {_L['Command line arguments'], _L['For Run:'], _L['For Compile:']}, + text = utf8_args, width = not CURSES and 400 or nil } if button ~= 1 then return end end for i, commands in ipairs{M.run_commands, M.compile_commands} do - -- Add the additional arguments to the base run/compile command and set - -- the new command to be the one used for the current file. + -- Add the additional arguments to the base run/compile command and set the new command to + -- be the one used for the current file. commands[filename] = string.format('%s %s', base_commands[i], utf8_args[i]:iconv(_CHARSET, 'UTF-8')) end end +-- LuaFormatter off --- --- Map of project root paths and "makefiles" to their associated "build" shell --- command line strings or functions that return such strings. --- Functions may also return a working directory and process environment table --- to operate in. By default, the working directory is the project's root --- directory and the environment is Textadept's environment. +-- Map of project root paths and "makefiles" to their associated "build" shell command line +-- strings or functions that return such strings. +-- Functions may also return a working directory and process environment table to operate +-- in. By default, the working directory is the project's root directory and the environment +-- is Textadept's environment. -- @class table -- @name build_commands M.build_commands = {--[[Ant]]['build.xml']='ant',--[[Dockerfile]]Dockerfile='docker build .',--[[Make]]Makefile='make',GNUmakefile='make',makefile='make',--[[Meson]]['meson.build']='meson compile',--[[Maven]]['pom.xml']='mvn',--[[Ruby]]Rakefile='rake'} +-- LuaFormatter on --- --- Builds the project whose root path is *root_directory* or the current project --- using the shell command from the `build_commands` table. --- If a "makefile" type of build file is found, prompts the user for the full --- build command. --- The current project is determined by either the buffer's filename or the --- current working directory. +-- Builds the project whose root path is *root_directory* or the current project using the +-- shell command from the `build_commands` table. +-- If a "makefile" type of build file is found, prompts the user for the full build command. The +-- current project is determined by either the buffer's filename or the current working directory. -- Emits `BUILD_OUTPUT` events. --- @param root_directory The path to the project to build. The default value is --- the current project. +-- @param root_directory The path to the project to build. The default value is the current project. -- @see build_commands -- @see _G.events -- @name build @@ -368,8 +351,8 @@ function M.build(root_directory) for build_file, build_command in pairs(M.build_commands) do if lfs.attributes(string.format('%s/%s', root_directory, build_file)) then local button, utf8_command = ui.dialogs.inputbox{ - title = _L['Command'], informative_text = root_directory, - text = build_command, button1 = _L['OK'], button2 = _L['Cancel'] + title = _L['Command'], informative_text = root_directory, text = build_command, + button1 = _L['OK'], button2 = _L['Cancel'] } if button == 1 then command = utf8_command:iconv(_CHARSET, 'UTF-8') end break @@ -381,23 +364,23 @@ end events.connect(events.BUILD_OUTPUT, print_output) --- --- Map of project root paths to their associated "test" shell command line --- strings or functions that return such strings. --- Functions may also return a working directory and process environment table --- to operate in. By default, the working directory is the project's root --- directory and the environment is Textadept's environment. +-- Map of project root paths to their associated "test" shell command line strings or functions +-- that return such strings. +-- Functions may also return a working directory and process environment table to operate +-- in. By default, the working directory is the project's root directory and the environment +-- is Textadept's environment. -- @class table -- @name test_commands M.test_commands = {} --- --- Runs tests for the project whose root path is *root_directory* or the current --- project using the shell command from the `test_commands` table. --- The current project is determined by either the buffer's filename or the --- current working directory. +-- Runs tests for the project whose root path is *root_directory* or the current project using +-- the shell command from the `test_commands` table. +-- The current project is determined by either the buffer's filename or the current working +-- directory. -- Emits `TEST_OUTPUT` events. --- @param root_directory The path to the project to run tests for. The default --- value is the current project. +-- @param root_directory The path to the project to run tests for. The default value is the +-- current project. -- @see test_commands -- @see _G.events -- @name test @@ -407,8 +390,7 @@ function M.test(root_directory) if not root_directory then return end end for i = 1, #_BUFFERS do _BUFFERS[i]:annotation_clear_all() end - run_command( - M.test_commands[root_directory], root_directory, events.TEST_OUTPUT) + run_command(M.test_commands[root_directory], root_directory, events.TEST_OUTPUT) end events.connect(events.TEST_OUTPUT, print_output) @@ -422,56 +404,63 @@ local function is_msg_buf(buf) return buf._type == _L['[Message Buffer]'] end -- Send line as input to process stdin on return. events.connect(events.CHAR_ADDED, function(code) - if code == string.byte('\n') and proc and proc:status() == 'running' and - is_msg_buf(buffer) then + if code == string.byte('\n') and proc and proc:status() == 'running' and is_msg_buf(buffer) then local line_num = buffer:line_from_position(buffer.current_pos) - 1 proc:write(buffer:get_line(line_num)) end end) +-- LuaFormatter off --- --- Map of file extensions and lexer names to their associated lists of string --- patterns that match warning and error messages emitted by compile and run --- commands for those file extensions and lexers. --- Patterns match single lines and contain captures for a filename, line number, --- column number (optional), and warning or error message (optional). --- Double-clicking a warning or error message takes the user to the source of --- that warning/error. --- Note: `(.-)` captures in patterns are interpreted as filenames; `(%d+)` --- captures are interpreted as line numbers first, and then column numbers; and --- any other capture is treated as warning/error message text. +-- Map of file extensions and lexer names to their associated lists of string patterns that +-- match warning and error messages emitted by compile and run commands for those file extensions +-- and lexers. +-- Patterns match single lines and contain captures for a filename, line number, column number +-- (optional), and warning or error message (optional). Double-clicking a warning or error +-- message takes the user to the source of that warning/error. +-- Note: `(.-)` captures in patterns are interpreted as filenames; `(%d+)` captures are +-- interpreted as line numbers first, and then column numbers; and any other capture is treated +-- as warning/error message text. -- @class table -- @name error_patterns M.error_patterns = {actionscript={'^(.-)%((%d+)%): col: (%d+) (.+)$'},ada={'^(.-):(%d+):(%d+):%s*(.*)$','^[^:]+: (.-):(%d+) (.+)$'},ansi_c={'^(.-):(%d+):(%d+): (.+)$'},antlr={'^error%(%d+%): (.-):(%d+):(%d+): (.+)$','^warning%(%d+%): (.-):(%d+):(%d+): (.+)$'},--[[ANTLR]]g={'^error%(%d+%): (.-):(%d+):(%d+): (.+)$','^warning%(%d+%): (.-):(%d+):(%d+): (.+)$'},asm={'^(.-):(%d+): (.+)$'},awk={'^awk: (.-):(%d+): (.+)$'},boo={'^(.-)%((%d+),(%d+)%): (.+)$'},caml={'^%s*File "(.-)", line (%d+), characters (%d+)'},chuck={'^(.-)line%((%d+)%)%.char%((%d+)%): (.+)$'},clojure={' error .- at .-%((.-):(%d+)'},cmake={'^CMake Error at (.-):(%d+)','^(.-):(%d+):$'},coffeescript={'^(.-):(%d+):(%d+): (.+)$'},context={'error on line (%d+) in file (.-): (.+)$'},cpp={'^(.-):(%d+):(%d+): (.+)$'},csharp={'^(.-)%((%d+),(%d+)%): (.+)$'},cuda={'^(.-)%((%d+)%): (error.+)$'},dart={"^'(.-)': error: line (%d+) pos (%d+): (.+)$",'%(file://(.-):(%d+):(%d+)%)'},dmd={'^(.-)%((%d+)%): (Error.+)$'},dot={'^Warning: (.-): (.+) in line (%d+)'},eiffel={'^Line (%d+) columns? .- in .- %((.-)%):$','^line (%d+) column (%d+) file (.-)$'},elixir={'^(.-):(%d+): (.+)$','Error%) (.-):(%d+): (.+)$'},erlang={'^(.-):(%d+): (.+)$'},fantom={'^(.-)%((%d+),(%d+)%): (.+)$'},faust={'^(.-):(%d+):(.+)$'},fennel={'^%S+ error in (.-):(%d+)'},forth={'^(.-):(%d+): (.+)$'},fortran={'^(.-):(%d+)%D+(%d+):%s*(.*)$'},fsharp={'^(.-)%((%d+),(%d+)%): (.+)$'},gap={'^(.+) in (.-) line (%d+)$'},gnuplot={'^"(.-)", line (%d+): (.+)$'},go={'^(.-):(%d+):(%d+): (.+)$'},groovy={'^%s+at .-%((.-):(%d+)%)$','^(.-):(%d+): (.+)$'},haskell={'^(.-):(%d+):(%d+):%s*(.*)$'},icon={'^File (.-); Line (%d+) # (.+)$','^.-from line (%d+) in (.-)$'},java={'^%s+at .-%((.-):(%d+)%)$','^(.-):(%d+): (.+)$'},javascript={'^%s+at .-%((.-):(%d+):(%d+)%)$','^%s+at (.-):(%d+):(%d+)$','^(.-):(%d+):?$'},jq={'^jq: error: (.+) at (.-), line (%d+)'},julia={'^%s+%[%d+%].- at (.-):(%d+)$'},ltx={'^(.-):(%d+): (.+)$'},less={'^(.+) in (.-) on line (%d+), column (%d+):$'},lilypond={'^(.-):(%d+):(%d+):%s*(.*)$'},litcoffee={'^(.-):(%d+):(%d+): (.+)$'},lua={'^luac?: (.-):(%d+): (.+)$'},makefile={'^(.-):(%d+): (.+)$'},nemerle={'^(.-)%((%d+),(%d+)%): (.+)$'},nim={'^(.-)%((%d+), (%d+)%) (%w+:.+)$'},objective_c={'^(.-):(%d+):(%d+): (.+)$'},pascal={'^(.-)%((%d+),(%d+)%) (%w+:.+)$'},perl={'^(.+) at (.-) line (%d+)'},php={'^(.+) in (.-) on line (%d+)$'},pike={'^(.-):(%d+):(.+)$'},pony={'^(.-):(%d+):(%d+): (.+)$'},prolog={'^(.-):(%d+):(%d+): (.+)$','^(.-):(%d+): (.+)$'},pure={'^(.-), line (%d+): (.+)$'},python={'^%s*File "(.-)", line (%d+)'},rexx={'^Error %d+ running "(.-)", line (%d+): (.+)$'},ruby={'^%s+from (.-):(%d+):','^(.-):(%d+):%s*(.+)$'},rust={'^(.-):(%d+):(%d+): (.+)$',"panicked at '([^']+)', (.-):(%d+)"},sass={'^WARNING on line (%d+) of (.-):$','^%s+on line (%d+) of (.-)$'},scala={'^%s+at .-%((.-):(%d+)%)$','^(.-):(%d+): (.+)$'},sh={'^(.-): (%d+): %1: (.+)$'},bash={'^(.-): line (%d+): (.+)$'},zsh={'^(.-):(%d+): (.+)$'},smalltalk={'^(.-):(%d+): (.+)$','%((.-):(%d+)%)$'},snobol4={'^(.-):(%d+): (.+)$'},tcl={'^%s*%(file "(.-)" line (%d+)%)$'},tex={'^(.-):(%d+): (.+)$'},typescript={'^(.-):(%d+):(%d+) %- (.+)$'},vala={'^(.-):(%d+)%.(%d+)[%-%.%d]+: (.+)$','^(.-):(%d+):(%d+): (.+)$'},vb={'^(.-)%((%d+),(%d+)%): (.+)$'},xs={'^(.-):(%d+)%S* (.+)$'},zig={'^(.-):(%d+):(%d+): (.+)$'}} -- Note: APDL,IDL,REBOL,RouterOS,Spin,Verilog,VHDL are proprietary. -- Note: ASP,CSS,Desktop,diff,django,elm,fstab,gettext,Gtkrc,HTML,ini,JSON,JSP,Markdown,Networkd,Postscript,Properties,R,Reason,RHTML,Systemd,XML don't have parse-able errors. -- Note: Batch,BibTeX,ConTeXt,Dockerfile,GLSL,Inform,Io,Lisp,MoonScript,Scheme,SQL,TeX cannot be parsed for one reason or another. +-- LuaFormatter on --- --- Jumps to the source of the recognized compile/run warning or error on line --- number *line_num* in the message buffer. --- If *line_num* is `nil`, jumps to the next or previous warning or error, --- depending on boolean *next*. Displays an annotation with the warning or error --- message if possible. --- @param line_num Optional line number in the message buffer that contains the --- compile/run warning or error to go to. This parameter may be omitted --- completely. --- @param next Optional flag indicating whether to go to the next recognized --- warning/error or the previous one. Only applicable when *line_num* is --- `nil`. +-- Jumps to the source of the recognized compile/run warning or error on line number *line_num* +-- in the message buffer. +-- If *line_num* is `nil`, jumps to the next or previous warning or error, depending on boolean +-- *next*. Displays an annotation with the warning or error message if possible. +-- @param line_num Optional line number in the message buffer that contains the compile/run +-- warning or error to go to. This parameter may be omitted completely. +-- @param next Optional flag indicating whether to go to the next recognized warning/error or +-- the previous one. Only applicable when *line_num* is `nil`. -- @see error_patterns -- @name goto_error function M.goto_error(line_num, next) if type(line_num) == 'boolean' then line_num, next = nil, line_num end local msg_view, msg_buf = nil, nil for i = 1, #_VIEWS do - if is_msg_buf(_VIEWS[i].buffer) then msg_view = _VIEWS[i] break end + if is_msg_buf(_VIEWS[i].buffer) then + msg_view = _VIEWS[i] + break + end end for i = 1, #_BUFFERS do - if is_msg_buf(_BUFFERS[i]) then msg_buf = _BUFFERS[i] break end + if is_msg_buf(_BUFFERS[i]) then + msg_buf = _BUFFERS[i] + break + end end if not msg_view and not msg_buf then return end - if msg_view then ui.goto_view(msg_view) else view:goto_buffer(msg_buf) end + if msg_view then + ui.goto_view(msg_view) + else + view:goto_buffer(msg_buf) + end -- If no line number was given, find the next warning or error marker. if not assert_type(line_num, 'number/nil', 1) and next ~= nil then @@ -486,7 +475,11 @@ function M.goto_error(line_num, next) wline = f(buffer, next and 1 or buffer.line_count, WARN_BIT) eline = f(buffer, next and 1 or buffer.line_count, ERROR_BIT) elseif wline == -1 or eline == -1 then - if wline == -1 then wline = eline else eline = wline end + if wline == -1 then + wline = eline + else + eline = wline + end end line_num = (next and math.min or math.max)(wline, eline) if line_num == -1 and not wrapped then @@ -508,9 +501,7 @@ function M.goto_error(line_num, next) local sloppy = not detail.filename:find(not WIN32 and '^/' or '^%a:[/\\]') ui.goto_file(detail.filename, true, preferred_view, sloppy) textadept.editing.goto_line(detail.line) - if detail.column then - buffer:goto_pos(buffer:find_column(detail.line, detail.column)) - end + if detail.column then buffer:goto_pos(buffer:find_column(detail.line, detail.column)) end if not detail.message then return end buffer.annotation_text[detail.line] = detail.message if detail.warning then return end @@ -518,13 +509,12 @@ function M.goto_error(line_num, next) end events.connect(events.KEYPRESS, function(code) if keys.KEYSYMS[code] == '\n' and is_msg_buf(buffer) and - scan_for_error(buffer:get_cur_line():match('^[^\r\n]*')) then + scan_for_error(buffer:get_cur_line():match('^[^\r\n]*')) then M.goto_error(buffer:line_from_position(buffer.current_pos)) return true end end) -events.connect(events.DOUBLE_CLICK, function(_, line) - if is_msg_buf(buffer) then M.goto_error(line) end -end) +events.connect(events.DOUBLE_CLICK, + function(_, line) if is_msg_buf(buffer) then M.goto_error(line) end end) return M diff --git a/modules/textadept/session.lua b/modules/textadept/session.lua index 96f6e969..bf19e78e 100644 --- a/modules/textadept/session.lua +++ b/modules/textadept/session.lua @@ -7,23 +7,21 @@ local M = {} -- Session support for Textadept. -- @field save_on_quit (bool) -- Save the session when quitting. --- The default value is `true` unless the user passed the command line switch --- `-n` or `--nosession` to Textadept. +-- The default value is `true` unless the user passed the command line switch `-n` or +-- `--nosession` to Textadept. -- @field _G.events.SESSION_SAVE (string) -- Emitted when saving a session. -- Arguments: -- --- * `session`: Table of session data to save. All handlers will have access --- to this same table, and Textadept's default handler reserves the use of --- some keys. --- Note that functions, userdata, and circular table values cannot be saved. --- The latter case is not recognized at all, so beware. +-- * `session`: Table of session data to save. All handlers will have access to this same +-- table, and Textadept's default handler reserves the use of some keys. +-- Note that functions, userdata, and circular table values cannot be saved. The latter +-- case is not recognized at all, so beware. -- @field _G.events.SESSION_LOAD (string) -- Emitted when loading a session. -- Arguments: -- --- * `session`: Table of session data to load. All handlers will have access --- to this same table. +-- * `session`: Table of session data to load. All handlers will have access to this same table. module('textadept.session')]] M.save_on_quit = true @@ -35,12 +33,11 @@ for _, v in ipairs(session_events) do events[v:upper()] = v end local session_file = _USERHOME .. (not CURSES and '/session' or '/session_term') --- --- Loads session file *filename* or the user-selected session, returning `true` --- if a session file was opened and read. --- Textadept restores split views, opened buffers, cursor information, recent --- files, and bookmarks. --- @param filename Optional absolute path to the session file to load. If `nil`, --- the user is prompted for one. +-- Loads session file *filename* or the user-selected session, returning `true` if a session +-- file was opened and read. +-- Textadept restores split views, opened buffers, cursor information, recent files, and bookmarks. +-- @param filename Optional absolute path to the session file to load. If `nil`, the user is +-- prompted for one. -- @return `true` if the session file was opened and read; `nil` otherwise. -- @usage textadept.session.load(filename) -- @name load @@ -116,24 +113,18 @@ function M.load(filename) return true end -- Load session when no args are present. -local function load_default_session() - if M.save_on_quit then M.load(session_file) end -end +local function load_default_session() if M.save_on_quit then M.load(session_file) end end events.connect(events.ARG_NONE, load_default_session) -- Returns value *val* serialized as a string. -- This is a very simple implementation suitable for session saving only. --- Ignores function, userdata, and thread types, and does not handle circular --- tables. +-- Ignores function, userdata, and thread types, and does not handle circular tables. local function _tostring(val) if type(val) == 'table' then local t = {} - for k, v in pairs(val) do - t[#t + 1] = string.format('[%s]=%s,', _tostring(k), _tostring(v)) - end + for k, v in pairs(val) do t[#t + 1] = string.format('[%s]=%s,', _tostring(k), _tostring(v)) end return string.format('{%s}', table.concat(t)) - elseif type(val) == 'function' or type(val) == 'userdata' or - type(val) == 'thread' then + elseif type(val) == 'function' or type(val) == 'userdata' or type(val) == 'thread' then val = nil end return type(val) == 'string' and string.format('%q', val) or tostring(val) @@ -141,12 +132,11 @@ end --- -- Saves the session to file *filename* or the user-selected file. --- Saves split views, opened buffers, cursor information, recent files, and --- bookmarks. +-- Saves split views, opened buffers, cursor information, recent files, and bookmarks. -- Upon quitting, the current session is saved to *filename* again, unless -- `textadept.session.save_on_quit` is `false`. --- @param filename Optional absolute path to the session file to save. If `nil`, --- the user is prompted for one. +-- @param filename Optional absolute path to the session file to save. If `nil`, the user is +-- prompted for one. -- @usage textadept.session.save(filename) -- @name save function M.save(filename) @@ -174,7 +164,7 @@ function M.save(filename) filename = buffer.filename or buffer._type, anchor = current and buffer.anchor or buffer._anchor or 1, current_pos = current and buffer.current_pos or buffer._current_pos or 1, - top_line = current and view.first_visible_line or buffer._top_line or 1, + top_line = current and view.first_visible_line or buffer._top_line or 1 } local bookmarks = {} local BOOKMARK_BIT = 1 << textadept.bookmarks.MARK_BOOKMARK - 1 @@ -193,13 +183,11 @@ function M.save(filename) -- Serialize views. local function serialize_split(split) return split.buffer and _BUFFERS[split.buffer] or { - serialize_split(split[1]), serialize_split(split[2]), - vertical = split.vertical, size = split.size + serialize_split(split[1]), serialize_split(split[2]), vertical = split.vertical, + size = split.size } end - session.views = { - serialize_split(ui.get_split_table()), current = _VIEWS[view] - } + session.views = {serialize_split(ui.get_split_table()), current = _VIEWS[view]} -- Serialize recent files. session.recent_files = io.recent_files @@ -209,19 +197,14 @@ function M.save(filename) session_file = filename end -- Saves session on quit. -events.connect(events.QUIT, function() - if M.save_on_quit then M.save(session_file) end -end, 1) +events.connect(events.QUIT, function() if M.save_on_quit then M.save(session_file) end end, 1) -- Does not save session on quit. -args.register('-n', '--nosession', 0, function() - M.save_on_quit = false -end, 'No session functionality') +args.register('-n', '--nosession', 0, function() M.save_on_quit = false end, + 'No session functionality') -- Loads the given session on startup. args.register('-s', '--session', 1, function(name) - if not lfs.attributes(name) then - name = string.format('%s/%s', _USERHOME, name) - end + if not lfs.attributes(name) then name = string.format('%s/%s', _USERHOME, name) end M.load(name) events.disconnect(events.ARG_NONE, load_default_session) end, 'Load session') diff --git a/modules/textadept/snippets.lua b/modules/textadept/snippets.lua index 40d2febb..e900f2b4 100644 --- a/modules/textadept/snippets.lua +++ b/modules/textadept/snippets.lua @@ -8,57 +8,53 @@ local M = {} -- -- ### Overview -- --- Define snippets in the global `snippets` table in key-value pairs. Each pair --- consists of either a string trigger word and its snippet text, or a string --- lexer name (from the *lexers/* directory) with a table of trigger words and --- snippet texts. When searching for a snippet to insert based on a trigger --- word, Textadept considers snippets in the current lexer to have priority, --- followed by the ones in the global table. This means if there are two --- snippets with the same trigger word, Textadept inserts the one specific to --- the current lexer, not the global one. +-- Define snippets in the global `snippets` table in key-value pairs. Each pair consists of +-- either a string trigger word and its snippet text, or a string lexer name (from the *lexers/* +-- directory) with a table of trigger words and snippet texts. When searching for a snippet to +-- insert based on a trigger word, Textadept considers snippets in the current lexer to have +-- priority, followed by the ones in the global table. This means if there are two snippets +-- with the same trigger word, Textadept inserts the one specific to the current lexer, not +-- the global one. -- -- ### Special Sequences -- -- #### `%`*n*`(`*text*`)` -- --- Represents a placeholder, where *n* is an integer and *text* is default --- placeholder text. Textadept moves the caret to placeholders in numeric order --- each time it calls [`textadept.snippets.insert()`](), finishing at either --- the "%0" placeholder if it exists or at the end of the snippet. Examples are +-- Represents a placeholder, where *n* is an integer and *text* is default placeholder +-- text. Textadept moves the caret to placeholders in numeric order each time it calls +-- [`textadept.snippets.insert()`](), finishing at either the "%0" placeholder if it exists or +-- at the end of the snippet. Examples are -- -- snippets['foo'] = 'foobar%1(baz)' -- snippets['bar'] = 'start\n\t%0\nend' -- -- #### `%`*n*`{`*list*`}` -- --- Also represents a placeholder (where *n* is an integer), but presents a list --- of choices for placeholder text constructed from comma-separated *list*. --- Examples are +-- Also represents a placeholder (where *n* is an integer), but presents a list of choices for +-- placeholder text constructed from comma-separated *list*. Examples are -- -- snippets['op'] = 'operator(%1(1), %2(1), "%3{add,sub,mul,div}")' -- -- #### `%`*n* -- --- Represents a mirror, where *n* is an integer. Mirrors with the same *n* as a --- placeholder mirror any user input in the placeholder. If no placeholder --- exists for *n*, the first occurrence of that mirror in the snippet becomes --- the placeholder, but with no default text. Examples are +-- Represents a mirror, where *n* is an integer. Mirrors with the same *n* as a placeholder mirror +-- any user input in the placeholder. If no placeholder exists for *n*, the first occurrence +-- of that mirror in the snippet becomes the placeholder, but with no default text. Examples are -- -- snippets['foo'] = '%1(mirror), %1, on the wall' -- snippets['q'] = '"%1"' -- -- #### `%`*n*`<`*Lua code*`>`<br/>`%`*n*`[`*Shell code*`]` -- --- Represents a transform, where *n* is an integer that has an associated --- placeholder, *Lua code* is arbitrary Lua code, and *Shell code* is arbitrary --- Shell code. Textadept executes the code as text is typed into placeholder --- *n*. If the transform omits *n*, Textadept executes the transform's code the --- moment the editor inserts the snippet. +-- Represents a transform, where *n* is an integer that has an associated placeholder, *Lua code* +-- is arbitrary Lua code, and *Shell code* is arbitrary Shell code. Textadept executes the code +-- as text is typed into placeholder *n*. If the transform omits *n*, Textadept executes the +-- transform's code the moment the editor inserts the snippet. -- --- Textadept runs Lua code in its Lua State and replaces the transform with the --- code's return text. The code may use the temporary `text` and `selected_text` --- global variables which contain placeholder *n*'s text and the text originally --- selected when the snippet was inserted, respectively. An example is +-- Textadept runs Lua code in its Lua State and replaces the transform with the code's return +-- text. The code may use the temporary `text` and `selected_text` global variables which +-- contain placeholder *n*'s text and the text originally selected when the snippet was inserted, +-- respectively. An example is -- -- snippets['attr'] = [[ -- %1(int) %2(foo) = %3; @@ -71,29 +67,27 @@ local M = {} -- } -- ]] -- --- Textadept executes shell code using Lua's [`io.popen()`][] and replaces the --- transform with the process' standard output (stdout). The code may use a `%` --- character to represent placeholder *n*'s text. An example is +-- Textadept executes shell code using Lua's [`io.popen()`][] and replaces the transform with the +-- process' standard output (stdout). The code may use a `%` character to represent placeholder +-- *n*'s text. An example is -- -- snippets['env'] = '$%1(HOME) = %1[echo $%]' -- -- #### `%%` -- --- Stands for a single '%' since '%' by itself has a special meaning in --- snippets. +-- Stands for a single '%' since '%' by itself has a special meaning in snippets. -- -- #### `%(`<br/>`%{` -- --- Stands for a single '(' or '{', respectively, after a `%`*n* mirror. --- Otherwise, the mirror would be interpreted as a placeholder or transform. --- Note: it is currently not possible to escape a '<' or '[' immediately after --- a `%`*n* mirror due to `%<...>` and `%[...]` sequences being interpreted as --- code to execute. +-- Stands for a single '(' or '{', respectively, after a `%`*n* mirror. Otherwise, the mirror +-- would be interpreted as a placeholder or transform. Note: it is currently not possible to +-- escape a '<' or '[' immediately after a `%`*n* mirror due to `%<...>` and `%[...]` sequences +-- being interpreted as code to execute. -- -- #### `\t` -- --- A single unit of indentation based on the buffer's indentation settings --- ([`buffer.use_tabs`]() and [`buffer.tab_width`]()). +-- A single unit of indentation based on the buffer's indentation settings ([`buffer.use_tabs`]() +-- and [`buffer.tab_width`]()). -- -- #### `\n` -- @@ -112,12 +106,12 @@ M.INDIC_PLACEHOLDER = _SCINTILLA.next_indic_number() --- -- List of directory paths to look for snippet files in. --- Filenames are of the form *lexer.trigger.ext* or *trigger.ext* (*.ext* is an --- optional, arbitrary file extension). If the global `snippets` table does not --- contain a snippet for a given trigger, this table is consulted for a matching --- filename, and the contents of that file is inserted as a snippet. --- Note: If a directory has multiple snippets with the same trigger, the snippet --- chosen for insertion is not defined and may not be constant. +-- Filenames are of the form *lexer.trigger.ext* or *trigger.ext* (*.ext* is an optional, +-- arbitrary file extension). If the global `snippets` table does not contain a snippet for +-- a given trigger, this table is consulted for a matching filename, and the contents of that +-- file is inserted as a snippet. +-- Note: If a directory has multiple snippets with the same trigger, the snippet chosen for +-- insertion is not defined and may not be constant. -- @class table -- @name paths M.paths = {} @@ -125,37 +119,35 @@ M.paths = {} local INDIC_SNIPPET = _SCINTILLA.next_indic_number() local INDIC_CURRENTPLACEHOLDER = _SCINTILLA.next_indic_number() - --- 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. +-- LuaFormatter off +-- 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. -- @class table -- @name snippets -- @see _G.snippets local snippets = {actionscript={},ada={},apdl={},ansi_c={},antlr={},apl={},applescript={},asp={},autoit={},awk={},b_lang={},bash={},batch={},bibtex={},boo={},chuck={},clojure={},cmake={},coffeescript={},context={},cpp={},crystal={},csharp={},css={},cuda={},desktop={},django={},dmd={},dockerfile={},dot={},eiffel={},elixir={},elm={},erlang={},fantom={},faust={},fennel={},fish={},forth={},fortran={},fsharp={},fstab={},gap={},gettext={},gherkin={},glsl={},gnuplot={},go={},groovy={},gtkrc={},haskell={},html={},icon={},idl={},inform={},ini={},Io={},java={},javascript={},jq={},json={},jsp={},julia={},latex={},ledger={},less={},lilypond={},lisp={},logtalk={},lua={},makefile={},matlab={},meson={},moonscript={},myrddin={},nemerle={},networkd={},nim={},nsis={},objective_c={},pascal={},perl={},php={},pico8={},pike={},pkgbuild={},pony={},prolog={},props={},protobuf={},ps={},pure={},python={},rails={},rc={},reason={},rebol={},rest={},rexx={},rhtml={},routeros={},rstats={},ruby={},rust={},sass={},scala={},scheme={},smalltalk={},sml={},snobol4={},spin={},sql={},systemd={},tcl={},tex={},text={},toml={},typescript={},vala={},vb={},vbscript={},verilog={},vhdl={},wsf={},xml={},xs={},xtend={},yaml={},zig={}} - --- 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. +-- LuaFormatter on + +-- 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 matching_snippets = {} - local trigger = not no_trigger and buffer:text_range( - buffer:word_start_position(buffer.current_pos), buffer.current_pos) or '' + local trigger = not no_trigger and + buffer:text_range(buffer:word_start_position(buffer.current_pos), buffer.current_pos) or '' if no_trigger then grep = true end local lang = buffer:get_lexer(true) local name_patt = '^' .. trigger -- Search in the snippet tables. local snippet_tables = {snippets} - if type(snippets[lang]) == 'table' then - table.insert(snippet_tables, 1, snippets[lang]) - end + if type(snippets[lang]) == 'table' then table.insert(snippet_tables, 1, snippets[lang]) end for _, snippets in ipairs(snippet_tables) do if not grep and snippets[trigger] then return trigger, snippets[trigger] end if not grep then goto continue end @@ -169,14 +161,12 @@ local function find_snippet(grep, no_trigger) -- 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. + -- 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 == lang and p2 == trigger or p1 == trigger and p3 == '') or - grep and - (p1 == lang and p2 and p2:find(name_patt) or - p1 and p1:find(name_patt) and p3 == '') then + if not grep and (p1 == lang and p2 == trigger or p1 == trigger and p3 == '') or + (grep and + (p1 == lang and p2 and p2:find(name_patt) or p1 and p1:find(name_patt) and p3 == '')) then local f = io.open(string.format('%s/%s', M.paths[i], basename)) text = f:read('a') f:close() @@ -185,26 +175,25 @@ local function find_snippet(grep, no_trigger) end end end - if not grep then return nil, nil else return trigger, matching_snippets end + if not grep then return nil, nil end + return trigger, matching_snippets end -- A snippet object. -- @field trigger The word that triggered this snippet. --- @field original_sel_text The text originally selected when this snippet was --- inserted. +-- @field original_sel_text The text originally selected when this snippet was inserted. -- @field start_pos This snippet's start position. --- @field end_pos This snippet's end position. This is a metafield that is --- computed based on the `INDIC_SNIPPET` sentinel. --- @field placeholder_pos The beginning of the current placeholder in this --- snippet. This is used by transforms to identify text to transform. This is --- a metafield that is computed based on `INDIC_CURRENTPLACEHOLDER`. +-- @field end_pos This snippet's end position. This is a metafield that is computed based on the +-- `INDIC_SNIPPET` sentinel. +-- @field placeholder_pos The beginning of the current placeholder in this snippet. This is used +-- by transforms to identify text to transform. This is a metafield that is computed based on +-- `INDIC_CURRENTPLACEHOLDER`. -- @field index This snippet's current placeholder index. -- @field max_index The number of different placeholders in this snippet. --- @field snapshots A record of this snippet's text over time. The snapshot for --- a given placeholder index contains the state of the snippet with all --- placeholders of that index filled in (prior to moving to the next --- placeholder index). Snippet state consists of a `text` string field and a --- `placeholders` table field. +-- @field snapshots A record of this snippet's text over time. The snapshot for a given +-- placeholder index contains the state of the snippet with all placeholders of that index +-- filled in (prior to moving to the next placeholder index). Snippet state consists of a +-- `text` string field and a `placeholders` table field. -- @class table -- @name snippet local snippet = {} @@ -218,8 +207,8 @@ local stack = {} function snippet.new(text, trigger) local snip = setmetatable({ trigger = trigger, original_sel_text = buffer:get_sel_text(), - start_pos = buffer.selection_start - (trigger and #trigger or 0), index = 0, - max_index = 0, snapshots = {} + start_pos = buffer.selection_start - (trigger and #trigger or 0), index = 0, max_index = 0, + snapshots = {} }, snippet) -- Convert and match indentation. @@ -246,10 +235,10 @@ function snippet.new(text, trigger) local C, Cp, Ct, Cg, Cc = lpeg.C, lpeg.Cp, lpeg.Ct, lpeg.Cg, lpeg.Cc local patt = P{ V('plain_text') * V('placeholder') * Cp() + V('plain_text') * -1, - plain_text = C(((P(1) - '%' + '%' * S('({'))^1 + '%%')^0), - placeholder = Ct( - '%' * (V('index')^-1 * (V('angles') + V('brackets') + V('braces')) * - V('transform') + V('index') * (V('parens') + V('simple')))), + plain_text = C(((P(1) - '%' + '%' * S('({'))^1 + '%%')^0), -- LuaFormatter + placeholder = Ct('%' * + (V('index')^-1 * (V('angles') + V('brackets') + V('braces')) * V('transform') + V('index') * + (V('parens') + V('simple')))), -- LuaFormatter index = Cg(R('09')^1 / tonumber, 'index'), parens = '(' * Cg((1 - S('()') + V('parens'))^0, 'default') * ')', simple = Cg(Cc(true), 'simple'), transform = Cg(Cc(true), 'transform'), @@ -259,22 +248,21 @@ function snippet.new(text, trigger) } -- A snippet placeholder. -- Each placeholder is stored in a snippet snapshot. - -- @field id This placeholder's unique ID. This field is used as an - -- indicator's value for identification purposes. + -- @field id This placeholder's unique ID. This field is used as an indicator's value for + -- identification purposes. -- @field index This placeholder's index. -- @field default This placeholder's default text, if any. - -- @field transform Whether or not this placeholder is a transform (containing - -- either Lua or Shell code). + -- @field transform Whether or not this placeholder is a transform (containing either Lua or + -- Shell code). -- @field lua_code The Lua code of this transform. -- @field sh_code The Shell code of this transform. -- @field choice A list of options to insert from an autocompletion list. - -- @field position This placeholder's initial position in its snapshot. This - -- field will not update until the next snapshot is taken. Use - -- `snippet:each_placeholder()` to determine a placeholder's current - -- position. - -- @field length This placeholder's initial length in its snapshot. This field - -- will never update. Use `buffer:indicator_end()` in conjunction with - -- `snippet:each_placeholder()` to determine a placeholder's current length. + -- @field position This placeholder's initial position in its snapshot. This field will not + -- update until the next snapshot is taken. Use `snippet:each_placeholder()` to determine + -- a placeholder's current position. + -- @field length This placeholder's initial length in its snapshot. This field will never + -- update. Use `buffer:indicator_end()` in conjunction with `snippet:each_placeholder()` + -- to determine a placeholder's current length. -- @class table -- @name placeholder local text_part, placeholder, e = patt:match(text) @@ -285,17 +273,14 @@ function snippet.new(text, trigger) placeholder.id = #snapshot.placeholders + 1 snapshot.placeholders[#snapshot.placeholders + 1] = placeholder end - if text_part ~= '' then - snapshot.text = snapshot.text .. text_part:gsub('%%(%p)', '%1') - end + if text_part ~= '' then snapshot.text = snapshot.text .. text_part:gsub('%%(%p)', '%1') end placeholder.position = #snapshot.text if placeholder.default then if placeholder.default:find('%%%d+') then - -- Parses out embedded placeholders, adding them to this snippet's - -- snapshot. + -- Parses out embedded placeholders, adding them to this snippet's snapshot. -- @param s The placeholder string to parse. - -- @param start_pos The absolute position in the snippet `s` starts - -- from. All computed positions are anchored from here. + -- @param start_pos The absolute position in the snippet `s` starts from. All computed + -- positions are anchored from here. -- @return plain text from `s` (i.e. no placeholder markup) local function process_placeholders(s, start_pos) -- Processes a placeholder capture from LPeg. @@ -306,8 +291,7 @@ function snippet.new(text, trigger) position = start_pos + position - 1 if default then -- Process sub-placeholders starting at the index after '%n('. - default = process_placeholders( - default:sub(2, -2), position + #index + 2) + default = process_placeholders(default:sub(2, -2), position + #index + 2) end index = tonumber(index) if index > snip.max_index then snip.max_index = index end @@ -323,8 +307,7 @@ function snippet.new(text, trigger) parens = '(' * (1 - S('()') + V('parens'))^0 * ')' }, s) end - placeholder.default = process_placeholders( - placeholder.default, placeholder.position) + placeholder.default = process_placeholders(placeholder.default, placeholder.position) end snapshot.text = snapshot.text .. placeholder.default elseif placeholder.transform and not placeholder.index then @@ -336,9 +319,7 @@ function snippet.new(text, trigger) placeholder.position = snip.start_pos + placeholder.position -- absolute text_part, placeholder, e = patt:match(text, e) end - if text_part ~= '' then - snapshot.text = snapshot.text .. text_part:gsub('%%(%p)', '%1') - end + if text_part ~= '' then snapshot.text = snapshot.text .. text_part:gsub('%%(%p)', '%1') end snip.snapshots[0] = snapshot -- Insert the snippet into the buffer and mark its end position. @@ -359,20 +340,19 @@ function snippet:__index(k) local end_pos = buffer:indicator_end(INDIC_SNIPPET, self.start_pos) return end_pos > self.start_pos and end_pos or self.start_pos elseif k == 'placeholder_pos' then - -- Normally the marker is one character behind the placeholder. However - -- it will not exist at all if the placeholder is at the beginning of the - -- snippet. Also account for the marker being at the beginning of the - -- snippet. (If so, pos will point to the correct position.) + -- Normally the marker is one character behind the placeholder. However it will not exist + -- at all if the placeholder is at the beginning of the snippet. Also account for the marker + -- being at the beginning of the snippet. (If so, pos will point to the correct position.) local pos = buffer:indicator_end(INDIC_CURRENTPLACEHOLDER, self.start_pos) if pos == 1 then pos = self.start_pos end - return buffer:indicator_all_on_for(pos) & - 1 << INDIC_CURRENTPLACEHOLDER - 1 > 0 and pos + 1 or pos + return buffer:indicator_all_on_for(pos) & 1 << INDIC_CURRENTPLACEHOLDER - 1 > 0 and pos + 1 or + pos end return getmetatable(self)[k] end --- Inserts the current snapshot (based on `self.index`) of this snippet into --- the buffer and marks placeholders. +-- Inserts the current snapshot (based on `self.index`) of this snippet into the buffer and +-- marks placeholders. function snippet:insert() buffer:set_target_range(self.start_pos, self.end_pos) buffer:replace_target(self.snapshots[self.index].text) @@ -383,22 +363,19 @@ function snippet:insert() end end --- Jumps to the next placeholder in this snippet and adds additional carets --- at mirrors. +-- Jumps to the next placeholder in this snippet and adds additional carets at mirrors. function snippet:next() if buffer:auto_c_active() then buffer:auto_c_complete() end - -- Take a snapshot of the current state in order to restore it later if - -- necessary. + -- Take a snapshot of the current state in order to restore it later if necessary. if self.index > 0 and self.start_pos < self.end_pos then local text = buffer:text_range(self.start_pos, self.end_pos) local placeholders = {} for pos, ph in self:each_placeholder() do - -- Only the position of placeholders changes between snapshots; save it - -- and keep all other existing properties. - -- Note that nested placeholders will return the same placeholder id - -- twice: once before a nested placeholder, and again after. (e.g. - -- [foo[bar]baz] will will return the '[foo' and 'baz]' portions of the - -- same placeholder.) Only process the first occurrence. + -- Only the position of placeholders changes between snapshots; save it and keep all + -- other existing properties. + -- Note that nested placeholders will return the same placeholder id twice: once before + -- a nested placeholder, and again after. (e.g. [foo[bar]baz] will will return the '[foo' + -- and 'baz]' portions of the same placeholder.) Only process the first occurrence. if placeholders[ph.id] then goto continue end placeholders[ph.id] = setmetatable({position = pos}, { __index = self.snapshots[self.index - 1].placeholders[ph.id] @@ -413,8 +390,11 @@ function snippet:next() local ph = select(2, self:each_placeholder(self.index, 'default')()) or select(2, self:each_placeholder(self.index, 'choice')()) or select(2, self:each_placeholder(self.index, 'simple')()) or - self.index == 0 and {position = self.end_pos, length = 0} - if not ph then self:next() return end -- try next placeholder + (self.index == 0 and {position = self.end_pos, length = 0}) + if not ph then + self:next() -- try next placeholder + return + end -- Mark the position of the placeholder so transforms can identify it. buffer.indicator_current = INDIC_CURRENTPLACEHOLDER @@ -461,10 +441,13 @@ function snippet:next() if self.index == 0 then self:finish() end end --- Jumps to the previous placeholder in this snippet and restores the state --- associated with that placeholder. +-- Jumps to the previous placeholder in this snippet and restores the state associated with +-- that placeholder. function snippet:previous() - if self.index < 2 then self:finish(true) return end + if self.index < 2 then + self:finish(true) + return + end self.index = self.index - 2 self:insert() self:next() @@ -472,8 +455,8 @@ end -- Finishes or cancels this snippet depending on boolean *canceling*. -- The snippet cleans up after itself regardless. --- @param canceling Whether or not to cancel inserting this snippet. When --- `true`, the buffer is restored to its state prior to snippet expansion. +-- @param canceling Whether or not to cancel inserting this snippet. When `true`, the buffer +-- is restored to its state prior to snippet expansion. function snippet:finish(canceling) local s, e = self.start_pos, self.end_pos if e ~= s then buffer:delete_range(e, 1) end -- clear initial padding space @@ -487,47 +470,42 @@ function snippet:finish(canceling) stack[#stack] = nil end --- Returns a generator that returns each placeholder's position and state for --- all placeholders in this snippet. --- DO NOT modify the buffer while this generator is running. Doing so will --- affect the generator's state and cause errors. Re-run the generator each --- time a buffer edit is made (e.g. via `goto`). +-- Returns a generator that returns each placeholder's position and state for all placeholders +-- in this snippet. +-- DO NOT modify the buffer while this generator is running. Doing so will affect the generator's +-- state and cause errors. Re-run the generator each time a buffer edit is made (e.g. via `goto`). -- @param index Optional placeholder index to constrain results to. -- @param type Optional placeholder type to constrain results to. function snippet:each_placeholder(index, type) - local snapshot = - self.snapshots[self.index > 0 and self.index - 1 or #self.snapshots] + local snapshot = self.snapshots[self.index > 0 and self.index - 1 or #self.snapshots] local i = self.start_pos return function() local s = buffer:indicator_end(M.INDIC_PLACEHOLDER, i) while s > 1 and s <= self.end_pos do if buffer:indicator_all_on_for(i) & 1 << M.INDIC_PLACEHOLDER - 1 > 0 then - -- This next indicator comes directly after the previous one; adjust - -- start and end positions to compensate. + -- This next indicator comes directly after the previous one; adjust start and end + -- positions to compensate. s, i = buffer:indicator_start(M.INDIC_PLACEHOLDER, i), s else i = buffer:indicator_end(M.INDIC_PLACEHOLDER, s) end local id = buffer:indicator_value_at(M.INDIC_PLACEHOLDER, s) local ph = snapshot.placeholders[id] - if ph and (not index or ph.index == index) and (not type or ph[type]) then - return s, ph - end + if ph and (not index or ph.index == index) and (not type or ph[type]) then return s, ph end s = buffer:indicator_end(M.INDIC_PLACEHOLDER, i) end end end --- Returns the result of executing Lua or Shell code, in placeholder table --- *placeholder*, in the context of this snippet. +-- Returns the result of executing Lua or Shell code, in placeholder table *placeholder*, +-- in the context of this snippet. -- @param placeholder The placeholder that contains code to execute. function snippet:execute_code(placeholder) local s, e = self.placeholder_pos, buffer.selection_end if s > e then s, e = e, s end local text = self.index and buffer:text_range(s, e) or '' -- %<...>, %[...] if placeholder.lua_code then - local env = setmetatable( - {text = text, selected_text = self.original_sel_text}, {__index = _G}) + local env = setmetatable({text = text, selected_text = self.original_sel_text}, {__index = _G}) local f, result = load('return ' .. placeholder.lua_code, nil, 't', env) return f and select(2, pcall(f)) or result or '' elseif placeholder.sh_code then @@ -571,13 +549,11 @@ function snippet:update_transforms() end --- --- Inserts snippet text *text* or the snippet assigned to the trigger word --- behind the caret. --- Otherwise, if a snippet is active, goes to the active snippet's next --- placeholder. Returns `false` if no action was taken. --- @param text Optional snippet text to insert. If `nil`, attempts to insert a --- new snippet based on the trigger, the word behind caret, and the current --- lexer. +-- Inserts snippet text *text* or the snippet assigned to the trigger word behind the caret. +-- Otherwise, if a snippet is active, goes to the active snippet's next placeholder. Returns +-- `false` if no action was taken. +-- @param text Optional snippet text to insert. If `nil`, attempts to insert a new snippet +-- based on the trigger, the word behind caret, and the current lexer. -- @return `false` if no action was taken; `nil` otherwise. -- @see buffer.word_chars -- @name insert @@ -589,17 +565,18 @@ function M.insert(text) assert_type(text, 'string/nil', trigger or '?') end if text then snippet.new(text, trigger) end - if #stack > 0 then stack[#stack]:next() else return false end + if #stack == 0 then return false end + stack[#stack]:next() end --- --- Jumps back to the previous snippet placeholder, reverting any changes from --- the current one. +-- Jumps back to the previous snippet placeholder, reverting any changes from the current one. -- Returns `false` if no snippet is active. -- @return `false` if no snippet is active; `nil` otherwise. -- @name previous function M.previous() - if #stack > 0 then stack[#stack]:previous() else return false end + if #stack == 0 then return false end + stack[#stack]:previous() end --- @@ -608,12 +585,13 @@ end -- @return `false` if no snippet is active; `nil` otherwise. -- @name cancel_current function M.cancel_current() - if #stack > 0 then stack[#stack]:finish(true) else return false end + if #stack == 0 then return false end + stack[#stack]:finish(true) end --- --- Prompts the user to select a snippet to insert from a list of global and --- language-specific snippets. +-- Prompts the user to select a snippet to insert from a list of global and language-specific +-- snippets. -- @name select function M.select() local all_snippets, items = {}, {} @@ -625,8 +603,7 @@ function M.select() items[#items + 1], items[#items + 2] = trigger, all_snippets[trigger] end local button, i = ui.dialogs.filteredlist{ - title = _L['Select Snippet'], columns = {_L['Trigger'], _L['Snippet Text']}, - items = items + title = _L['Select Snippet'], columns = {_L['Trigger'], _L['Snippet Text']}, items = items } if button == 1 and i then M.insert(items[i * 2]) end end @@ -634,9 +611,7 @@ end -- Update snippet transforms when text is added or deleted. events.connect(events.UPDATE_UI, function(updated) if #stack == 0 then return end - if updated & buffer.UPDATE_CONTENT > 0 then - stack[#stack]:update_transforms() - end + if updated & buffer.UPDATE_CONTENT > 0 then stack[#stack]:update_transforms() end if #keys.keychain == 0 then ui.statusbar_text = _L['Snippet active'] end end) @@ -645,8 +620,7 @@ events.connect(events.VIEW_NEW, function() view.indic_style[INDIC_CURRENTPLACEHOLDER] = view.INDIC_HIDDEN end) --- Returns for the word behind the caret a list of snippet trigger word --- completions. +-- Returns for the word behind the caret a list of snippet trigger word completions. -- @see textadept.editing.autocomplete textadept.editing.autocompleters.snippet = function() local list, trigger, snippets = {}, find_snippet(true) @@ -657,8 +631,8 @@ textadept.editing.autocompleters.snippet = function() 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. +-- 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. -- @class table -- @name _G.snippets _G.snippets = snippets |