diff options
-rw-r--r-- | core/args.lua | 6 | ||||
-rw-r--r-- | core/events.lua | 1 | ||||
-rw-r--r-- | core/file_io.lua | 8 | ||||
-rw-r--r-- | core/gui.lua | 9 | ||||
-rw-r--r-- | core/init.lua | 22 | ||||
-rw-r--r-- | core/keys.lua | 43 | ||||
-rw-r--r-- | doc/markdowndoc.lua | 4 | ||||
-rw-r--r-- | init.lua | 2 | ||||
-rw-r--r-- | modules/cpp/init.lua | 14 | ||||
-rw-r--r-- | modules/lua/adeptsensedoc.lua | 4 | ||||
-rw-r--r-- | modules/lua/init.lua | 12 | ||||
-rw-r--r-- | modules/textadept/adeptsense.lua | 4 | ||||
-rw-r--r-- | modules/textadept/bookmarks.lua | 2 | ||||
-rw-r--r-- | modules/textadept/command_entry.lua | 8 | ||||
-rw-r--r-- | modules/textadept/editing.lua | 59 | ||||
-rw-r--r-- | modules/textadept/find.lua | 135 | ||||
-rw-r--r-- | modules/textadept/init.lua | 22 | ||||
-rw-r--r-- | modules/textadept/keys.lua | 101 | ||||
-rw-r--r-- | modules/textadept/menu.lua | 103 | ||||
-rw-r--r-- | modules/textadept/mime_types.lua | 13 | ||||
-rw-r--r-- | modules/textadept/run.lua | 1 | ||||
-rw-r--r-- | modules/textadept/session.lua | 17 | ||||
-rw-r--r-- | modules/textadept/snippets.lua | 26 |
23 files changed, 264 insertions, 352 deletions
diff --git a/core/args.lua b/core/args.lua index e6db7696..f0cdba65 100644 --- a/core/args.lua +++ b/core/args.lua @@ -12,8 +12,6 @@ local M = {} -- Emitted when no command line arguments are passed to Textadept on startup. module('args')]] -local arg = arg - -- Contains registered command line switches. -- @class table -- @name switches @@ -79,6 +77,8 @@ local function show_help() end if not CURSES then M.register('-h', '--help', 0, show_help, 'Shows this') end +local arg = arg + -- For Windows, create arg table from single command line string (arg[0]). if WIN32 and not CURSES and #arg[0] > 0 then local P, C = lpeg.P, lpeg.C @@ -99,7 +99,7 @@ if not lfs.attributes(userhome) then lfs.mkdir(userhome) end if not lfs.attributes(userhome..'/init.lua') then local f = io.open(userhome..'/init.lua', 'w') if f then - f:write("_M.textadept = require 'textadept'\n") + f:write("_M.textadept = require('textadept')\n") f:close() end end diff --git a/core/events.lua b/core/events.lua index 51644644..02bb81b2 100644 --- a/core/events.lua +++ b/core/events.lua @@ -290,7 +290,6 @@ function M.disconnect(event, id) end local error_emitted = false - --- -- Sequentially calls all handler functions for *event* with the given -- arguments. diff --git a/core/file_io.lua b/core/file_io.lua index 137463d9..145159a4 100644 --- a/core/file_io.lua +++ b/core/file_io.lua @@ -79,7 +79,7 @@ io.recent_files = {} -- @class table -- @name boms io.boms = { - ['UTF-16BE'] = '\254\255', ['UTF-16LE'] = '\255\254', + ['UTF-16BE'] = '\254\255', ['UTF-16LE'] = '\255\254', ['UTF-32BE'] = '\0\0\254\255', ['UTF-32LE'] = '\255\254\0\0' } @@ -346,7 +346,6 @@ end -- of Textadept. local function update_modified_file() if not buffer.filename then return end - local buffer = buffer local utf8_filename = buffer.filename local filename = utf8_filename:iconv(_CHARSET, 'UTF-8') local mod_time = lfs.attributes(filename, 'modification') @@ -373,7 +372,6 @@ events_connect(events.VIEW_AFTER_SWITCH, update_modified_file) -- Set additional buffer functions. events_connect(events.BUFFER_NEW, function() - local buffer = buffer buffer.reload = reload buffer.save, buffer.save_as = save, save_as buffer.close = close @@ -382,8 +380,8 @@ end) -- Close initial "Untitled" buffer. events_connect(events.FILE_OPENED, function(utf8_filename) - local b = _BUFFERS[1] - if #_BUFFERS == 2 and not (b.filename or b._type or b.dirty) then + local buf = _BUFFERS[1] + if #_BUFFERS == 2 and not (buf.filename or buf._type or buf.dirty) then view:goto_buffer(1) buffer:close() end diff --git a/core/gui.lua b/core/gui.lua index 6869468f..445a65de 100644 --- a/core/gui.lua +++ b/core/gui.lua @@ -19,8 +19,6 @@ local gui = gui -- The text displayed by the buffer statusbar. module('gui')]] -local _L = _L - -- Helper function for printing messages to buffers. -- @see gui._print local function _print(buffer_type, ...) @@ -161,6 +159,7 @@ end local theme_file = not CURSES and 'theme' or 'theme_term' local THEME + --- -- Sets the editor theme name to *name* or the default platform theme. -- Themes with *name* in the *`_USERHOME`/themes/* directory override themes of @@ -348,23 +347,21 @@ events_connect(events.APPLEEVENT_ODOC, function(uri) return events_emit(events.URI_DROPPED, 'file://'..uri) end) -local string_format = string.format local EOLs = {_L['CRLF'], _L['CR'], _L['LF']} local GETLEXERLANGUAGE = _SCINTILLA.properties.lexer_language[1] -- Sets docstatusbar text. events_connect(events.UPDATE_UI, function() - local buffer = buffer local pos = buffer.current_pos local line, max = buffer:line_from_position(pos) + 1, buffer.line_count local col = buffer.column[pos] + 1 local lexer = buffer:private_lexer_call(GETLEXERLANGUAGE):match('^[^/]+') local eol = EOLs[buffer.eol_mode + 1] - local tabs = string_format('%s %d', buffer.use_tabs and _L['Tabs:'] or + local tabs = string.format('%s %d', buffer.use_tabs and _L['Tabs:'] or _L['Spaces:'], buffer.tab_width) local enc = buffer.encoding or '' local text = not CURSES and '%s %d/%d %s %d %s %s %s %s' or '%s %d/%d %s %d %s %s %s %s' - gui.docstatusbar_text = string_format(text, _L['Line:'], line, max, + gui.docstatusbar_text = string.format(text, _L['Line:'], line, max, _L['Col:'], col, lexer, eol, tabs, enc) end) diff --git a/core/init.lua b/core/init.lua index d3a57482..83da8eff 100644 --- a/core/init.lua +++ b/core/init.lua @@ -4,24 +4,22 @@ _RELEASE = "Textadept 6.6 beta" package.path = _HOME..'/core/?.lua;'..package.path -_SCINTILLA = require 'iface' -args = require 'args' -_L = require 'locale' -events = require 'events' -require 'file_io' -require 'lfs_ext' -require 'gui' -keys = require 'keys' +_SCINTILLA = require('iface') +args = require('args') +_L = require('locale') +events = require('events') +require('file_io') +require('lfs_ext') +require('gui') +keys = require('keys') _LEXERPATH = _USERHOME..'/lexers/?.lua;'.._HOME..'/lexers' - -gui.set_theme() - _M = {} -- modules table - -- LuaJIT compatibility. if jit then module, package.searchers, bit32 = nil, package.loaders, bit end +gui.set_theme() + --[[ This comment is for LuaDoc. --- -- Extends Lua's _G table to provide extra functions and fields for Textadept. diff --git a/core/keys.lua b/core/keys.lua index f6373af6..13459982 100644 --- a/core/keys.lua +++ b/core/keys.lua @@ -122,22 +122,10 @@ local M = {} -- The default value is `nil`. module('keys')]] -local ADD = '' -local CTRL, ALT, META, SHIFT = 'c'..ADD, 'a'..ADD, 'm'..ADD, 's'..ADD -if CURSES then ALT = META end +local CTRL, ALT, META, SHIFT = 'c', not CURSES and 'a' or 'm', 'm', 's' M.CLEAR = 'esc' M.LANGUAGE_MODULE_PREFIX = (not OSX and not CURSES and CTRL or META)..'l' --- Optimize for speed. -local OSX = OSX -local string = string -local string_byte, string_char = string.byte, string.char -local table_unpack = table.unpack -local xpcall, next, type = xpcall, next, type -local no_args = {} -local getmetatable = getmetatable -local error = function(e) events.emit(events.ERROR, e) end - --- -- Lookup table for string representations of key codes higher than 255. -- Key codes can be identified by temporarily uncommenting the `print()` @@ -195,13 +183,15 @@ end -- Export for command_entry.lua without creating LuaDoc. if CURSES then M.clear_key_sequence = clear_key_sequence end +local none = {} +local function key_error(e) events.emit(events.ERROR, e) end -- Runs a given command. -- This is also used by *modules/textadept/menu.lua*. -- @param command A function or table as described above. -- @param command_type Equivalent to `type(command)`. -- @return the value the command returns. local function run_command(command, command_type) - local f, args = command_type == 'function' and command or command[1], no_args + local f, args = command_type == 'function' and command or command[1], none if command_type == 'table' then args = command -- If the argument is a view or buffer, use the current one instead. @@ -214,7 +204,7 @@ local function run_command(command, command_type) end end end - local _, result = xpcall(f, error, table_unpack(args, 2)) + local _, result = xpcall(f, key_error, table.unpack(args, 2)) return result end M.run_command = run_command -- export for menu.lua without creating LuaDoc @@ -251,7 +241,7 @@ end -- @return `true` to stop handling the key; `nil` otherwise. local function keypress(code, shift, control, alt, meta) --print(code, M.KEYSYMS[code], shift, control, alt, meta) - local key = code < 256 and (not CURSES or code ~= 7) and string_char(code) or + local key = code < 256 and (not CURSES or code ~= 7) and string.char(code) or M.KEYSYMS[code] if not key then return end shift = shift and (code >= 256 or code == 9) -- printable chars are uppercased @@ -285,27 +275,6 @@ local function keypress(code, shift, control, alt, meta) end events.connect(events.KEYPRESS, keypress, 1) --- Returns the GDK integer keycode and modifier mask for a key sequence. --- This is used for creating menu accelerators. --- @param key_seq The string key sequence. --- @return keycode and modifier mask -local function get_gdk_key(key_seq) - if not key_seq then return nil end - local mods, key = key_seq:match('^([cams]*)(.+)$') - if not mods or not key then return nil end - local modifiers = ((mods:find('s') or key:lower() ~= key) and 1 or 0) + - (mods:find('c') and 4 or 0) + (mods:find('a') and 8 or 0) + - (mods:find('m') and 268435456 or 0) - local byte = string_byte(key) - if #key > 1 or byte < 32 then - for i, s in pairs(M.KEYSYMS) do - if s == key and i > 0xFE20 then byte = i break end - end - end - return byte, modifiers -end -M.get_gdk_key = get_gdk_key -- export for menu.lua without generating LuaDoc - --- -- Map of key bindings to commands, with language-specific key tables assigned -- to a lexer name key. diff --git a/doc/markdowndoc.lua b/doc/markdowndoc.lua index 3abe6217..ea1ba26a 100644 --- a/doc/markdowndoc.lua +++ b/doc/markdowndoc.lua @@ -162,7 +162,7 @@ function M.start(doc) end h[#h + 1] = self end - (require 'lfs').mkdir(M.options.output_dir..'/api') + require('lfs').mkdir(M.options.output_dir..'/api') local navfile = M.options.output_dir..'/api/.nav.md' local f = io_open(navfile, 'wb') write_nav(f, hierarchy) @@ -174,7 +174,7 @@ function M.start(doc) -- Write index.html. template.nav = nav local api_index = M.options.output_dir..'/.api_index.md' - if (require 'lfs').attributes(api_index) then + if require('lfs').attributes(api_index) then local p = io_popen('markdown -f toc -T "'..api_index..'"') template.toc, template.main = p:read('*all'):match('^(.-\n</ul>\n)(.+)$') p:close() @@ -11,6 +11,6 @@ package.cpath = _USERHOME..so.._USERHOME..'/modules'..so..package.cpath local user_init, exists = _USERHOME..'/init.lua', lfs.attributes local ok, err = pcall(dofile, user_init) -if ok or not exists(user_init) then require 'textadept' else gui.print(err) end +if ok or not exists(user_init) then require('textadept') else gui.print(err) end if not RESETTING then args.process(arg) end diff --git a/modules/cpp/init.lua b/modules/cpp/init.lua index 5d62691a..0adf61cb 100644 --- a/modules/cpp/init.lua +++ b/modules/cpp/init.lua @@ -23,17 +23,17 @@ local M = {} -- from *`_USERHOME`/modules/cpp/api*. module('_M.cpp')]] -local m_editing, m_run = _M.textadept.editing, _M.textadept.run -- Comment string tables use lexer names. -m_editing.comment_string.cpp = '//' +_M.textadept.editing.comment_string.cpp = '//' + -- Compile and Run command tables use file extensions. -m_run.compile_command.c = +_M.textadept.run.compile_command.c = 'gcc -pedantic -Os -o "%(filename_noext)" %(filename)' -m_run.compile_command.cpp = +_M.textadept.run.compile_command.cpp = 'g++ -pedantic -Os -o "%(filename_noext)" %(filename)' -m_run.run_command.c = '%(filedir)%(filename_noext)' -m_run.run_command.cpp = '%(filedir)%(filename_noext)' -m_run.error_detail.c = { +_M.textadept.run.run_command.c = '%(filedir)%(filename_noext)' +_M.textadept.run.run_command.cpp = '%(filedir)%(filename_noext)' +_M.textadept.run.error_detail.c = { pattern = '^(.-):(%d+): (.+)$', filename = 1, line = 2, message = 3 } diff --git a/modules/lua/adeptsensedoc.lua b/modules/lua/adeptsensedoc.lua index 3edebe13..f0bf42f3 100644 --- a/modules/lua/adeptsensedoc.lua +++ b/modules/lua/adeptsensedoc.lua @@ -117,8 +117,8 @@ end -- Called by LuaDoc to process a doc object. -- @param doc The LuaDoc doc object. function M.start(doc) --- require 'luarocks.require' --- local profiler = require 'profiler' +-- require('luarocks.require') +-- local profiler = require('profiler') -- profiler.start() local modules, files = doc.modules, doc.files diff --git a/modules/lua/init.lua b/modules/lua/init.lua index 9abe2277..de9c7450 100644 --- a/modules/lua/init.lua +++ b/modules/lua/init.lua @@ -24,13 +24,13 @@ local M = {} -- from *`_USERHOME`/modules/lua/api*. module('_M.lua')]] -local m_editing, m_run = _M.textadept.editing, _M.textadept.run -- Comment string tables use lexer names. -m_editing.comment_string.lua = '--' +_M.textadept.editing.comment_string.lua = '--' + -- Compile and Run command tables use file extensions. -m_run.compile_command.lua = 'luac %(filename)' -m_run.run_command.lua = 'lua %(filename)' -m_run.error_detail.lua = { +_M.textadept.run.compile_command.lua = 'luac %(filename)' +_M.textadept.run.run_command.lua = 'lua %(filename)' +_M.textadept.run.error_detail.lua = { pattern = '^lua: (.-):(%d+): (.+)$', filename = 1, line = 2, message = 3 } @@ -109,7 +109,6 @@ local control_structure_patterns = { -- @see control_structure_patterns -- @name try_to_autocomplete_end function M.try_to_autocomplete_end() - local buffer = buffer local line_num = buffer:line_from_position(buffer.current_pos) local line = buffer:get_line(line_num) local line_indentation = buffer.line_indentation @@ -133,7 +132,6 @@ end -- Show syntax errors as annotations. events.connect(events.FILE_AFTER_SAVE, function() if buffer:get_lexer() ~= 'lua' then return end - local buffer = buffer buffer:annotation_clear_all() local text = buffer:get_text():gsub('^#![^\n]+', '') -- ignore shebang line local f, err = load(text) diff --git a/modules/textadept/adeptsense.lua b/modules/textadept/adeptsense.lua index 74998977..6d58ff41 100644 --- a/modules/textadept/adeptsense.lua +++ b/modules/textadept/adeptsense.lua @@ -323,7 +323,7 @@ local M = {} -- contain: -- -- -- Load CSS Adeptsense. --- if not _M.css then _M.css = require 'css' end +-- if not _M.css then _M.css = require('css') end -- -- You will have to do something similar if you are writing an Adeptsense for a -- child lexer language. @@ -577,7 +577,6 @@ end -- @see get_completions -- @name complete function M.complete(sense, only_fields, only_functions) - local buffer = buffer sense = sense or (_M[buffer:get_lexer(true)] or {}).sense if not sense then return end local symbol, part = sense:get_symbol() @@ -672,7 +671,6 @@ local apidocs = nil -- @see get_apidoc -- @name show_apidoc function M.show_apidoc(sense) - local buffer = buffer if buffer:call_tip_active() then events.emit(events.CALL_TIP_CLICK) return end sense = sense or (_M[buffer:get_lexer(true)] or {}).sense if not sense then return end diff --git a/modules/textadept/bookmarks.lua b/modules/textadept/bookmarks.lua index 449626d7..3f383a56 100644 --- a/modules/textadept/bookmarks.lua +++ b/modules/textadept/bookmarks.lua @@ -20,7 +20,6 @@ local MARK_BOOKMARK = _SCINTILLA.next_marker_number() -- current line. The default value is `nil`, toggling a bookmark. -- @name toggle function M.toggle(on) - local buffer = buffer local line = buffer:line_from_position(buffer.current_pos) local f = on and buffer.marker_add or buffer.marker_delete if on == nil then -- toggle @@ -45,7 +44,6 @@ end -- @param start `0` when going to the next mark, `buffer.line_count` when going -- to the previous mark. local function goto_mark(f, increment, wrap_start) - local buffer = buffer local current_line = buffer:line_from_position(buffer.current_pos) local line = f(buffer, current_line + increment, 2^MARK_BOOKMARK) if line == -1 then line = f(buffer, wrap_start, 2^MARK_BOOKMARK) end diff --git a/modules/textadept/command_entry.lua b/modules/textadept/command_entry.lua index c4ab7b7a..a22b10c6 100644 --- a/modules/textadept/command_entry.lua +++ b/modules/textadept/command_entry.lua @@ -120,7 +120,7 @@ function M.complete_lua(code) local substring = (code or M.entry_text):match('[%w_.:]+$') or '' local path, op, prefix = substring:match('^([%w_.:]-)([.:]?)([%w_]*)$') local f, err = load('return ('..path..')', nil, 'bt', env) - local ok, tbl = pcall(f) + local ok, result = pcall(f) local cmpls = {} prefix = '^'..prefix if not ok then -- shorthand notation @@ -136,8 +136,8 @@ function M.complete_lua(code) if p:find(prefix) then cmpls[#cmpls + 1] = p end end else - if type(tbl) ~= 'table' then return end - for k in pairs(tbl) do + if type(result) ~= 'table' then return end + for k in pairs(result) do if type(k) == 'string' and k:find(prefix) then cmpls[#cmpls + 1] = k end end if path == 'buffer' and op == ':' then @@ -152,10 +152,8 @@ function M.complete_lua(code) end table.sort(cmpls) M.show_completions(cmpls) - return true end -local events = events -- Pass command entry keys to the default keypress handler. -- Since the command entry is designed to be modal, command entry key bindings -- should stay separate from editor key bindings. diff --git a/modules/textadept/editing.lua b/modules/textadept/editing.lua index 59799709..baaa09ff 100644 --- a/modules/textadept/editing.lua +++ b/modules/textadept/editing.lua @@ -92,31 +92,26 @@ M.typeover_chars = {[41] = 1, [93] = 1, [125] = 1, [39] = 1, [34] = 1} -- @name current_call_tip local current_call_tip = {} -local events, events_connect = events, events.connect -local K = keys.KEYSYMS - -- Matches characters specified in char_matches. -events_connect(events.CHAR_ADDED, function(c) +events.connect(events.CHAR_ADDED, function(c) if not M.AUTOPAIR then return end - local buffer = buffer local match = (M.char_matches[buffer:get_lexer(true)] or M.char_matches)[c] if match and buffer.selections == 1 then buffer:insert_text(-1, match) end end) -- Removes matched chars on backspace. -events_connect(events.KEYPRESS, function(code) - if not M.AUTOPAIR or K[code] ~= '\b' or buffer.selections ~= 1 then return end - local buffer = buffer - local pos = buffer.current_pos - local c = buffer.char_at[pos - 1] - local match = (M.char_matches[buffer:get_lexer(true)] or M.char_matches)[c] +events.connect(events.KEYPRESS, function(code) + if not M.AUTOPAIR or keys.KEYSYMS[code] ~= '\b' or buffer.selections ~= 1 then + return + end + local pos, char = buffer.current_pos, buffer.char_at[buffer.current_pos - 1] + local match = (M.char_matches[buffer:get_lexer(true)] or M.char_matches)[char] if match and buffer.char_at[pos] == string.byte(match) then buffer:clear() end end) -- Highlights matching braces. -events_connect(events.UPDATE_UI, function() +events.connect(events.UPDATE_UI, function() if not M.HIGHLIGHT_BRACES then return end - local buffer = buffer local pos = buffer.current_pos if (M.braces[buffer:get_lexer(true)] or M.braces)[buffer.char_at[pos]] then local match = buffer:brace_match(pos) @@ -131,9 +126,8 @@ events_connect(events.UPDATE_UI, function() end) -- Moves over typeover characters when typed. -events_connect(events.KEYPRESS, function(code) +events.connect(events.KEYPRESS, function(code) if not M.TYPEOVER_CHARS then return end - local buffer = buffer if M.typeover_chars[code] and buffer.char_at[buffer.current_pos] == code then buffer:char_right() return true @@ -141,7 +135,7 @@ events_connect(events.KEYPRESS, function(code) end) -- Auto-indent on return. -events_connect(events.CHAR_ADDED, function(char) +events.connect(events.CHAR_ADDED, function(char) if not M.AUTOINDENT or char ~= 10 then return end local buffer = buffer local pos = buffer.current_pos @@ -155,7 +149,7 @@ events_connect(events.CHAR_ADDED, function(char) end) -- Autocomplete multiple selections. -events_connect(events.AUTO_C_SELECTION, function(text, position) +events.connect(events.AUTO_C_SELECTION, function(text, position) local buffer = buffer local pos = buffer.selection_n_caret[buffer.main_selection] buffer:begin_undo_action() @@ -171,7 +165,7 @@ events_connect(events.AUTO_C_SELECTION, function(text, position) end) -- Prepares the buffer for saving to a file. -events_connect(events.FILE_BEFORE_SAVE, function() +events.connect(events.FILE_BEFORE_SAVE, function() if not M.STRIP_WHITESPACE_ON_SAVE then return end local buffer = buffer buffer:begin_undo_action() @@ -189,7 +183,7 @@ events_connect(events.FILE_BEFORE_SAVE, function() end -- Ensure ending newline. local e = buffer:position_from_line(lines) - if lines == 1 or lines > 1 and e > buffer:position_from_line(lines - 1) then + if lines == 1 or e > buffer:position_from_line(lines - 1) then buffer:insert_text(e, '\n') end -- Convert non-consistent EOLs @@ -204,7 +198,6 @@ end) -- between matching braces. The default value is `false`. -- @name match_brace function M.match_brace(select) - local buffer = buffer local pos = buffer.current_pos local match_pos = buffer:brace_match(pos) if match_pos == -1 then return end @@ -232,7 +225,7 @@ function M.autocomplete_word(default_words) local buffer = buffer local pos, length = buffer.current_pos, buffer.length local completions, c_list = {}, {} - local buffer_text = buffer:get_text(buffer.length) + local buffer_text = buffer:get_text() local root = buffer_text:sub(1, pos):match('['..buffer.word_chars..']+$') if not root or root == '' then return end for _, word in ipairs(default_words or {}) do @@ -288,10 +281,8 @@ end -- @name block_comment function M.block_comment(prefix) local buffer = buffer - if not prefix then - prefix = M.comment_string[buffer:get_lexer(true)] - if not prefix then return end - end + prefix = prefix or M.comment_string[buffer:get_lexer(true)] + if not prefix then return end local anchor, pos = buffer.selection_start, buffer.selection_end local s = buffer:line_from_position(anchor) local e = buffer:line_from_position(pos) @@ -338,9 +329,8 @@ end -- transposed. Otherwise, the characters to the left and right are. -- @name transpose_chars function M.transpose_chars() - local buffer = buffer - local pos, c = buffer.current_pos, buffer.char_at[buffer.current_pos] - local eol = c == 10 or c == 13 or pos == buffer.length + local pos, char = buffer.current_pos, buffer.char_at[buffer.current_pos] + local eol = char == 10 or char == 13 or pos == buffer.length if eol then pos = pos - 1 end buffer.target_start, buffer.target_end = pos - 1, pos + 1 buffer:replace_target(buffer:text_range(pos - 1, pos + 1):reverse()) @@ -354,7 +344,6 @@ end -- joining. -- @name join_lines function M.join_lines() - local buffer = buffer buffer:target_from_selection() buffer:line_end() local line = buffer:line_from_position(buffer.target_start) @@ -371,7 +360,6 @@ end -- @param right The right part of the enclosure. -- @name enclose function M.enclose(left, right) - local buffer = buffer buffer:target_from_selection() local s, e = buffer.target_start, buffer.target_end if s == e then buffer.target_start = buffer:word_start_position(s, true) end @@ -387,7 +375,6 @@ end -- @param right The right part of the enclosure. -- @name select_enclosed function M.select_enclosed(left, right) - local buffer = buffer local anchor, pos = buffer.anchor, buffer.current_pos if anchor ~= pos then buffer:goto_pos(pos - #right) end buffer:search_anchor() @@ -403,7 +390,6 @@ end -- @see buffer.word_chars -- @name select_word function M.select_word() - local buffer = buffer buffer:set_sel(buffer:word_start_position(buffer.current_pos, true), buffer:word_end_position(buffer.current_pos, true)) end @@ -485,12 +471,11 @@ local INDIC_HIGHLIGHT = _SCINTILLA.next_indic_number() -- Clears highlighted word indicators and markers. local function clear_highlighted_words() - local buffer = buffer buffer.indicator_current = INDIC_HIGHLIGHT buffer:indicator_clear_range(0, buffer.length) end -events_connect(events.KEYPRESS, function(code) - if K[code] == 'esc' then clear_highlighted_words() end +events.connect(events.KEYPRESS, function(code) + if keys.KEYSYMS[code] == 'esc' then clear_highlighted_words() end end) --- @@ -519,14 +504,13 @@ end -- Sets view properties for highlighted word indicators and markers. local function set_highlight_properties() - local buffer = buffer buffer.indic_fore[INDIC_HIGHLIGHT] = M.INDIC_HIGHLIGHT_BACK buffer.indic_style[INDIC_HIGHLIGHT] = _SCINTILLA.constants.INDIC_ROUNDBOX buffer.indic_alpha[INDIC_HIGHLIGHT] = 255 if not CURSES then buffer.indic_under[INDIC_HIGHLIGHT] = true end end if buffer then set_highlight_properties() end -events_connect(events.VIEW_NEW, set_highlight_properties) +events.connect(events.VIEW_NEW, set_highlight_properties) --- -- Passes selected or all buffer text to string shell command *cmd* as standard @@ -545,7 +529,6 @@ events_connect(events.VIEW_NEW, set_highlight_properties) -- through. -- @name filter_through function M.filter_through(cmd) - local buffer = buffer local s, e = buffer.selection_start, buffer.selection_end local input if s ~= e then -- use selected lines as input diff --git a/modules/textadept/find.lua b/modules/textadept/find.lua index 5b0adae8..4b93d57f 100644 --- a/modules/textadept/find.lua +++ b/modules/textadept/find.lua @@ -73,7 +73,6 @@ M.lua_pattern_label_text = not CURSES and _L['_Lua pattern'] or M.in_files_label_text = not CURSES and _L['_In files'] or _L['Files(F4)'] -- Events. -local events, events_connect = events, events.connect events.FIND_WRAPPED = 'find_wrapped' local preferred_view @@ -102,49 +101,6 @@ local escapes = { ['\\r'] = '\r', ['\\t'] = '\t', ['\\v'] = '\v', ['\\\\'] = '\\' } ---- --- Searches the *utf8_dir* or user-specified directory for files that match --- search text and options and prints the results to a buffer. --- Use the `find_text`, `match_case`, `whole_word`, and `lua` fields to set the --- search text and option flags, respectively. Use `FILTER` to set the search --- filter. --- @param utf8_dir Optional UTF-8-encoded directory path to search. If `nil`, --- the user is prompted for one. --- @see FILTER --- @name find_in_files -function M.find_in_files(utf8_dir) - if not utf8_dir then - utf8_dir = gui.dialog('fileselect', - '--title', _L['Find in Files'], - '--select-only-directories', - '--with-directory', - (buffer.filename or ''):match('^.+[/\\]') or '', - '--no-newline') - end - if utf8_dir == '' then return end - - local text = M.find_entry_text - if not M.lua then text = text:gsub('([().*+?^$%%[%]-])', '%%%1') end - if not M.match_case then text = text:lower() end - if M.whole_word then text = '%f[%w_]'..text..'%f[^%w_]' end - local matches = {_L['Find:']..' '..text} - lfs.dir_foreach(utf8_dir, function(file) - local match_case = M.match_case - local line_num = 1 - for line in io.lines(file) do - if (match_case and line or line:lower()):find(text) then - file = file:iconv('UTF-8', _CHARSET) - matches[#matches + 1] = ('%s:%s:%s'):format(file, line_num, line) - end - line_num = line_num + 1 - end - end, M.FILTER, true) - if #matches == 1 then matches[2] = _L['No results found'] end - matches[#matches + 1] = '' - if buffer._type ~= _L['[Files Found Buffer]'] then preferred_view = view end - gui._print(_L['[Files Found Buffer]'], table.concat(matches, '\n')) -end - local c = _SCINTILLA.constants -- Finds and selects text in the current buffer. @@ -218,7 +174,7 @@ local function find_(text, next, flags, nowrap, wrapped) return result end -events_connect(events.FIND, find_) +events.connect(events.FIND, find_) -- Finds and selects text incrementally in the current buffer from a starting -- position. @@ -257,26 +213,47 @@ function M.find_incremental(text, next, anchor) gui.command_entry.enter_mode('find_incremental') end --- Optimize for speed. -local load, pcall = load, pcall - --- Runs the given code. --- This function is passed to `string.gsub()` in the `replace()` function. --- @param code The code to run. -local function run(code) - local ok, val = pcall(load('return '..code)) - if not ok then - gui.dialog('ok-msgbox', - '--title', _L['Error'], - '--text', _L['An error occured:'], - '--informative-text', val:gsub('"', '\\"'), - '--icon', 'gtk-dialog-error', - '--button1', _L['_OK'], - '--button2', _L['_Cancel'], - '--no-cancel') - error() +--- +-- Searches the *utf8_dir* or user-specified directory for files that match +-- search text and options and prints the results to a buffer. +-- Use the `find_text`, `match_case`, `whole_word`, and `lua` fields to set the +-- search text and option flags, respectively. Use `FILTER` to set the search +-- filter. +-- @param utf8_dir Optional UTF-8-encoded directory path to search. If `nil`, +-- the user is prompted for one. +-- @see FILTER +-- @name find_in_files +function M.find_in_files(utf8_dir) + if not utf8_dir then + utf8_dir = gui.dialog('fileselect', + '--title', _L['Find in Files'], + '--select-only-directories', + '--with-directory', + (buffer.filename or ''):match('^.+[/\\]') or '', + '--no-newline') end - return val + if utf8_dir == '' then return end + + local text = M.find_entry_text + if not M.lua then text = text:gsub('([().*+?^$%%[%]-])', '%%%1') end + if not M.match_case then text = text:lower() end + if M.whole_word then text = '%f[%w_]'..text..'%f[^%w_]' end + local matches = {_L['Find:']..' '..text} + lfs.dir_foreach(utf8_dir, function(file) + local match_case = M.match_case + local line_num = 1 + for line in io.lines(file) do + if (match_case and line or line:lower()):find(text) then + file = file:iconv('UTF-8', _CHARSET) + matches[#matches + 1] = ('%s:%s:%s'):format(file, line_num, line) + end + line_num = line_num + 1 + end + end, M.FILTER, true) + if #matches == 1 then matches[2] = _L['No results found'] end + matches[#matches + 1] = '' + if buffer._type ~= _L['[Files Found Buffer]'] then preferred_view = view end + gui._print(_L['[Files Found Buffer]'], table.concat(matches, '\n')) end -- Replaces found text. @@ -290,27 +267,38 @@ end local function replace(rtext) if buffer:get_sel_text() == '' then return end if M.in_files then M.in_files = false end - local buffer = buffer buffer:target_from_selection() rtext = rtext:gsub('%%%%', '\\037') -- escape '%%' - local captures = M.captures - if captures then - for i = 1, #captures do - rtext = rtext:gsub('%%'..i, (captures[i]:gsub('%%', '%%%%'))) + if M.captures then + for i = 1, #M.captures do + rtext = rtext:gsub('%%'..i, (M.captures[i]:gsub('%%', '%%%%'))) end end - local ok, rtext = pcall(rtext.gsub, rtext, '%%(%b())', run) + local ok, rtext = pcall(rtext.gsub, rtext, '%%(%b())', function(code) + local ok, result = pcall(load('return '..code)) + if not ok then error(result) end + return result + end) if ok then rtext = rtext:gsub('\\037', '%%') -- unescape '%' buffer:replace_target(rtext:gsub('\\[abfnrtv\\]', escapes)) buffer:goto_pos(buffer.target_end) -- 'find' text after this replacement else + gui.dialog('ok-msgbox', + '--title', _L['Error'], + '--text', _L['An error occured:'], + '--informative-text', + rtext:match(':1:(.+)$') or rtext:match(':%d+:(.+)$'), + '--icon', 'gtk-dialog-error', + '--button1', _L['_OK'], + '--button2', _L['_Cancel'], + '--no-cancel') -- Since find is called after replace returns, have it 'find' the current -- text again, rather than the next occurance so the user can fix the error. buffer:goto_pos(buffer.current_pos) end end -events_connect(events.REPLACE, replace) +events.connect(events.REPLACE, replace) local MARK_FIND = _SCINTILLA.next_marker_number() -- Replaces all found text. @@ -356,7 +344,7 @@ local function replace_all(ftext, rtext) gui.statusbar_text = ("%d %s"):format(count, _L['replacement(s) made']) buffer:end_undo_action() end -events_connect(events.REPLACE_ALL, replace_all) +events.connect(events.REPLACE_ALL, replace_all) -- Returns whether or not the given buffer is a files found buffer. local function is_ff_buf(buf) return buf._type == _L['[Files Found Buffer]'] end @@ -382,7 +370,6 @@ function M.goto_file_found(line, next) -- If not line was given, find the next search result. if not line and next ~= nil then - local buffer = buffer if next then buffer:line_end() else buffer:home() end buffer:search_anchor() local f = buffer['search_'..(next and 'next' or 'prev')] @@ -404,7 +391,7 @@ function M.goto_file_found(line, next) gui.goto_file(file, true, preferred_view) _M.textadept.editing.goto_line(line_num) end -events_connect(events.DOUBLE_CLICK, +events.connect(events.DOUBLE_CLICK, function(pos, line) M.goto_file_found(line) end) --[[ The functions below are Lua C functions. diff --git a/modules/textadept/init.lua b/modules/textadept/init.lua index c751eef6..c34a7055 100644 --- a/modules/textadept/init.lua +++ b/modules/textadept/init.lua @@ -9,18 +9,18 @@ _M.textadept = M -- It provides utilities for editing text in Textadept. module('_M.textadept')]] -M.adeptsense = require 'textadept.adeptsense' -M.bookmarks = require 'textadept.bookmarks' -require 'textadept.command_entry' -M.editing = require 'textadept.editing' -require 'textadept.find' -M.mime_types = require 'textadept.mime_types' -M.run = require 'textadept.run' -M.session = require 'textadept.session' -M.snippets = require 'textadept.snippets' +M.adeptsense = require('textadept.adeptsense') +M.bookmarks = require('textadept.bookmarks') +require('textadept.command_entry') +M.editing = require('textadept.editing') +require('textadept.find') +M.mime_types = require('textadept.mime_types') +M.run = require('textadept.run') +M.session = require('textadept.session') +M.snippets = require('textadept.snippets') -- These need to be loaded last. -M.keys = require 'textadept.keys' -M.menu = require 'textadept.menu' +M.keys = require('textadept.keys') +M.menu = require('textadept.menu') return M diff --git a/modules/textadept/keys.lua b/modules/textadept/keys.lua index e88bbb6e..2c2f1b43 100644 --- a/modules/textadept/keys.lua +++ b/modules/textadept/keys.lua @@ -215,7 +215,6 @@ M.utils = { end, enclose_as_xml_tags = function() _M.textadept.editing.enclose('<', '>') - local buffer = buffer local pos = buffer.current_pos while buffer.char_at[pos - 1] ~= 60 do pos = pos - 1 end -- '<' buffer:insert_text(-1, '</'..buffer:text_range(pos, buffer.current_pos)) @@ -229,7 +228,6 @@ M.utils = { if buffer.filename then io.snapopen(buffer.filename:match('^(.+)[/\\]')) end end, show_style = function() - local buffer = buffer local style = buffer.style_at[buffer.current_pos] local text = string.format("%s %s\n%s %s (%d)", _L['Lexer'], buffer:get_lexer(true), _L['Style'], @@ -245,7 +243,7 @@ M.utils = { if type(state) == 'boolean' then buffer[property] = not state elseif type(state) == 'number' then - buffer[property] = buffer[property] == 0 and (i or 1) or 0 + buffer[property] = state == 0 and (i or 1) or 0 end events.emit(events.UPDATE_UI) -- for updating statusbar end, @@ -262,26 +260,23 @@ M.utils = { grow = function() if view.size then view.size = view.size + 10 end end, shrink = function() if view.size then view.size = view.size - 10 end end, toggle_current_fold = function() - local buffer = buffer buffer:toggle_fold(buffer:line_from_position(buffer.current_pos)) end, reset_zoom = function() buffer.zoom = 0 end, open_webpage = function(url) - local cmd if WIN32 then - cmd = string.format('start "" "%s"', url) - local p = io.popen(cmd) + local p = io.popen(string.format('start "" "%s"', url)) if not p then error(_L['Error loading webpage:']..url) end p:close() else - cmd = string.format(OSX and 'open "file://%s"' or 'xdg-open "%s" &', url) - local _, _, code = os.execute(cmd) + local _, _, code = os.execute(string.format(OSX and 'open "file://%s"' or + 'xdg-open "%s" &', url)) if code ~= 0 then error(_L['Error loading webpage:']..url) end end end, cut_to_eol = function() - _G.buffer:line_end_extend() - _G.buffer:cut() + buffer:line_end_extend() + buffer:cut() end } -- The following buffer functions need to be constantized in order for menu @@ -299,13 +294,9 @@ events.connect(events.BUFFER_NEW, constantize_menu_buffer_functions) -- Scintilla's first buffer does not have this. if not RESETTING then constantize_menu_buffer_functions() end -local keys = keys -local io, gui, gui_find, gui_ce = io, gui, gui.find, gui.command_entry -local buffer, view = buffer, view -local m_textadept, m_editing = _M.textadept, _M.textadept.editing -local m_bookmarks, m_snippets = m_textadept.bookmarks, m_textadept.snippets -local OSX, c = OSX, _SCINTILLA.constants -local utils = M.utils +local _M, keys, buffer, view = _M, keys, buffer, view +local m_editing, utils = _M.textadept.editing, M.utils +local OSX, CURSES, c = OSX, CURSES, _SCINTILLA.constants -- Windows and Linux key bindings. -- @@ -372,8 +363,8 @@ keys[not OSX and 'cs' or 'ms'] = buffer.save keys[not OSX and (not CURSES and 'cS' or 'cms') or 'mS'] = buffer.save_as keys[not OSX and 'cw' or 'mw'] = buffer.close keys[not OSX and (not CURSES and 'cW' or 'cmw') or 'mW'] = io.close_all --- TODO: m_textadept.sessions.load --- TODO: m_textadept.sessions.save +-- TODO: _M.textadept.sessions.load +-- TODO: _M.textadept.sessions.save keys[not OSX and 'cq' or 'mq'] = quit -- Edit. @@ -399,7 +390,7 @@ keys[not OSX and not CURSES and 'c/' or 'm/'] = m_editing.block_comment keys.ct = m_editing.transpose_chars keys[not OSX and (not CURSES and 'cJ' or 'mj') or 'cj'] = m_editing.join_lines keys[not OSX and (not CURSES and 'c|' or 'c\\') - or 'm|'] = {gui_ce.enter_mode, 'filter_through'} + or 'm|'] = {gui.command_entry.enter_mode, 'filter_through'} -- Select. keys[not CURSES and 'cM' or 'mM'] = {m_editing.match_brace, 'select'} keys[not OSX and not CURSES and 'c<' @@ -441,55 +432,58 @@ keys.csup = buffer.move_selected_lines_up keys.csdown = buffer.move_selected_lines_down -- Search. -keys[not OSX and not CURSES and 'cf' or 'mf'] = gui_find.focus +keys[not OSX and not CURSES and 'cf' or 'mf'] = gui.find.focus if CURSES then keys.mF = keys.mf end -- in case mf is used by GUI terminals -keys[not OSX and not CURSES and 'cg' or 'mg'] = gui_find.find_next +keys[not OSX and not CURSES and 'cg' or 'mg'] = gui.find.find_next if not OSX and not CURSES then keys.f3 = keys.cg end -keys[not OSX and not CURSES and 'cG' or 'mG'] = gui_find.find_prev +keys[not OSX and not CURSES and 'cG' or 'mG'] = gui.find.find_prev if not OSX and not CURSES then keys.sf3 = keys.cG end -keys[not OSX and (not CURSES and 'car' or 'mr') or 'cr'] = gui_find.replace -keys[not OSX and (not CURSES and 'caR' or 'mR') or 'cR'] = gui_find.replace_all +keys[not OSX and (not CURSES and 'car' or 'mr') or 'cr'] = gui.find.replace +keys[not OSX and (not CURSES and 'caR' or 'mR') or 'cR'] = gui.find.replace_all -- Find Next is an when find pane is focused in GUI. -- Find Prev is ap when find pane is focused in GUI. -- Replace is ar when find pane is focused in GUI. -- Replace All is aa when find pane is focused in GUI. -keys[not OSX and not CURSES and 'caf' or 'cmf'] = gui_find.find_incremental +keys[not OSX and not CURSES and 'caf' or 'cmf'] = gui.find.find_incremental if not CURSES then keys[not OSX and 'cF' or 'mF'] = utils.find_in_files end -- Find in Files is ai when find pane is focused in GUI. if not CURSES then - keys[not OSX and 'cag' or 'cmg'] = {gui_find.goto_file_found, false, true} - keys[not OSX and 'caG' or 'cmG'] = {gui_find.goto_file_found, false, false} + keys[not OSX and 'cag' or 'cmg'] = {gui.find.goto_file_found, false, true} + keys[not OSX and 'caG' or 'cmG'] = {gui.find.goto_file_found, false, false} end keys[not OSX and 'cj' or 'mj'] = m_editing.goto_line -- Tools. keys[not OSX and (not CURSES and 'ce' or 'mc') - or 'me'] = {gui_ce.enter_mode, 'lua_command'} + or 'me'] = {gui.command_entry.enter_mode, 'lua_command'} keys[not OSX and (not CURSES and 'cE' or 'mC') or 'mE'] = utils.select_command -keys[not OSX and 'cr' or 'mr'] = m_textadept.run.run +keys[not OSX and 'cr' or 'mr'] = _M.textadept.run.run keys[not OSX and (not CURSES and 'cR' or 'cmr') - or 'mR'] = m_textadept.run.compile + or 'mR'] = _M.textadept.run.compile keys[not OSX and (not CURSES and 'cae' or 'mx') - or 'cme'] = {m_textadept.run.goto_error, false, true} + or 'cme'] = {_M.textadept.run.goto_error, false, true} keys[not OSX and (not CURSES and 'caE' or 'mX') - or 'cmE'] = {m_textadept.run.goto_error, false, false} + or 'cmE'] = {_M.textadept.run.goto_error, false, false} -- Adeptsense. keys[not OSX and ((not CURSES or WIN32) and 'c ' or 'c@') - or 'aesc'] = m_textadept.adeptsense.complete -keys[not CURSES and 'ch' or 'mh'] = m_textadept.adeptsense.show_apidoc + or 'aesc'] = _M.textadept.adeptsense.complete +keys[not CURSES and 'ch' or 'mh'] = _M.textadept.adeptsense.show_apidoc if CURSES then keys.mH = keys.mh end -- in case mh is used by GUI terminals -- Snippets. -keys[not OSX and (not CURSES and 'ck' or 'mk') or 'a\t'] = m_snippets._select -keys['\t'] = m_snippets._insert -keys['s\t'] = m_snippets._previous +keys[not OSX and (not CURSES and 'ck' or 'mk') + or 'a\t'] = _M.textadept.snippets._select +keys['\t'] = _M.textadept.snippets._insert +keys['s\t'] = _M.textadept.snippets._previous keys[not OSX and (not CURSES and 'cK' or 'mK') - or 'as\t'] = m_snippets._cancel_current + or 'as\t'] = _M.textadept.snippets._cancel_current -- Bookmark. -keys[not OSX and (not CURSES and 'cf2' or 'f1') or 'mf2'] = m_bookmarks.toggle -keys[not OSX and (not CURSES and 'csf2' or 'f6') or 'msf2'] = m_bookmarks.clear -keys.f2 = m_bookmarks.goto_next -keys[not CURSES and 'sf2' or 'f3'] = m_bookmarks.goto_prev -keys[not CURSES and 'af2' or 'f4'] = m_bookmarks.goto_bookmark +keys[not OSX and (not CURSES and 'cf2' or 'f1') + or 'mf2'] = _M.textadept.bookmarks.toggle +keys[not OSX and (not CURSES and 'csf2' or 'f6') + or 'msf2'] = _M.textadept.bookmarks.clear +keys.f2 = _M.textadept.bookmarks.goto_next +keys[not CURSES and 'sf2' or 'f3'] = _M.textadept.bookmarks.goto_prev +keys[not CURSES and 'af2' or 'f4'] = _M.textadept.bookmarks.goto_bookmark -- Snapopen. keys[not OSX and 'cu' or 'mu'] = {io.snapopen, _USERHOME} -- TODO: {io.snapopen, _HOME} @@ -523,7 +517,7 @@ keys[not OSX and (not CURSES and 'cai' or 'mi') -- TODO: {utils.set_encoding, 'MacRoman'} -- TODO: {utils.set_encoding, 'UTF-16LE'} keys[not OSX and not CURSES and 'cL' - or 'mL'] = m_textadept.mime_types.select_lexer + or 'mL'] = _M.textadept.mime_types.select_lexer keys.f5 = {buffer.colourise, buffer, 0, -1} if CURSES then keys.cl = keys.f5 end @@ -594,27 +588,28 @@ end -- Modes. keys.lua_command = { - ['\t'] = gui_ce.complete_lua, - ['\n'] = {gui_ce.finish_mode, gui_ce.execute_lua} + ['\t'] = gui.command_entry.complete_lua, + ['\n'] = {gui.command_entry.finish_mode, gui.command_entry.execute_lua} } keys.filter_through = { - ['\n'] = {gui_ce.finish_mode, m_editing.filter_through}, + ['\n'] = {gui.command_entry.finish_mode, m_editing.filter_through}, } keys.find_incremental = { ['\n'] = function() - gui_find.find_incremental(gui_ce.entry_text, true, true) + gui.find.find_incremental(gui.command_entry.entry_text, true, true) end, ['cr'] = function() - gui_find.find_incremental(gui_ce.entry_text, false, true) + gui.find.find_incremental(gui.command_entry.entry_text, false, true) end, ['\b'] = function() - gui_find.find_incremental(gui_ce.entry_text:sub(1, -2), true) + gui.find.find_incremental(gui.command_entry.entry_text:sub(1, -2), true) return false -- propagate end } +-- Add the character for any key pressed without modifiers to incremental find. setmetatable(keys.find_incremental, {__index = function(t, k) if #k > 1 and k:find('^[cams]*.+$') then return end - gui_find.find_incremental(gui_ce.entry_text..k, true) + gui.find.find_incremental(gui.command_entry.entry_text..k, true) end}) return M diff --git a/modules/textadept/menu.lua b/modules/textadept/menu.lua index 3115bdea..67436b1d 100644 --- a/modules/textadept/menu.lua +++ b/modules/textadept/menu.lua @@ -24,10 +24,8 @@ local function get_id(f) return id end -local _L, io, gui, gui_find, buffer, view = _L, io, gui, gui.find, buffer, view -local m_textadept, m_editing = _M.textadept, _M.textadept.editing -local m_bookmarks, Msnippets = m_textadept.bookmarks, m_textadept.snippets -local utils = m_textadept.keys.utils +local _L, _M, buffer, view = _L, _M, buffer, view +local m_editing, utils = _M.textadept.editing, _M.textadept.keys.utils local SEPARATOR, c = {''}, _SCINTILLA.constants -- The default main menubar. @@ -43,8 +41,8 @@ local menubar = { {_L['_Close'], buffer.close}, {_L['Close All'], io.close_all}, SEPARATOR, - {_L['Loa_d Session...'], m_textadept.session.load}, - {_L['Sav_e Session...'], m_textadept.session.save}, + {_L['Loa_d Session...'], _M.textadept.session.load}, + {_L['Sav_e Session...'], _M.textadept.session.save}, SEPARATOR, {_L['_Quit'], quit}, }, @@ -98,16 +96,16 @@ local menubar = { }, }, { title = _L['_Search'], - {_L['_Find'], gui_find.focus}, - {_L['Find _Next'], gui_find.find_next}, - {_L['Find _Previous'], gui_find.find_prev}, - {_L['_Replace'], gui_find.replace}, - {_L['Replace _All'], gui_find.replace_all}, - {_L['Find _Incremental'], gui_find.find_incremental}, + {_L['_Find'], gui.find.focus}, + {_L['Find _Next'], gui.find.find_next}, + {_L['Find _Previous'], gui.find.find_prev}, + {_L['_Replace'], gui.find.replace}, + {_L['Replace _All'], gui.find.replace_all}, + {_L['Find _Incremental'], gui.find.find_incremental}, SEPARATOR, {_L['Find in Fi_les'], utils.find_in_files}, - {_L['Goto Nex_t File Found'], {gui_find.goto_file_found, false, true}}, - {_L['Goto Previou_s File Found'], {gui_find.goto_file_found, false, false}}, + {_L['Goto Nex_t File Found'], {gui.find.goto_file_found, false, true}}, + {_L['Goto Previou_s File Found'], {gui.find.goto_file_found, false, false}}, SEPARATOR, {_L['_Jump to'], m_editing.goto_line}, }, @@ -115,21 +113,21 @@ local menubar = { {_L['Command _Entry'], {gui.command_entry.enter_mode, 'lua_command'}}, {_L['Select Co_mmand'], utils.select_command}, SEPARATOR, - {_L['_Run'], m_textadept.run.run}, - {_L['_Compile'], m_textadept.run.compile}, - {_L['_Next Error'], {m_textadept.run.goto_error, false, true}}, - {_L['_Previous Error'], {m_textadept.run.goto_error, false, false}}, + {_L['_Run'], _M.textadept.run.run}, + {_L['_Compile'], _M.textadept.run.compile}, + {_L['_Next Error'], {_M.textadept.run.goto_error, false, true}}, + {_L['_Previous Error'], {_M.textadept.run.goto_error, false, false}}, SEPARATOR, { title = _L['_Adeptsense'], - {_L['_Complete Symbol'], m_textadept.adeptsense.complete}, - {_L['Show _Documentation'], m_textadept.adeptsense.show_apidoc}, + {_L['_Complete Symbol'], _M.textadept.adeptsense.complete}, + {_L['Show _Documentation'], _M.textadept.adeptsense.show_apidoc}, }, { title = _L['_Bookmark'], - {_L['_Toggle Bookmark'], m_bookmarks.toggle}, - {_L['_Clear Bookmarks'], m_bookmarks.clear}, - {_L['_Next Bookmark'], m_bookmarks.goto_next}, - {_L['_Previous Bookmark'], m_bookmarks.goto_prev}, - {_L['_Goto Bookmark...'], m_bookmarks.goto_bookmark}, + {_L['_Toggle Bookmark'], _M.textadept.bookmarks.toggle}, + {_L['_Clear Bookmarks'], _M.textadept.bookmarks.clear}, + {_L['_Next Bookmark'], _M.textadept.bookmarks.goto_next}, + {_L['_Previous Bookmark'], _M.textadept.bookmarks.goto_prev}, + {_L['_Goto Bookmark...'], _M.textadept.bookmarks.goto_bookmark}, }, { title = _L['Snap_open'], {_L['Snapopen _User Home'], {io.snapopen, _USERHOME}}, @@ -137,10 +135,10 @@ local menubar = { {_L['Snapopen _Current Directory'], utils.snapopen_filedir}, }, { title = _L['_Snippets'], - {_L['_Insert Snippet...'], Msnippets._select}, - {_L['_Expand Snippet/Next Placeholder'], Msnippets._insert}, - {_L['_Previous Snippet Placeholder'], Msnippets._previous}, - {_L['_Cancel Snippet'], Msnippets._cancel_current}, + {_L['_Insert Snippet...'], _M.textadept.snippets._select}, + {_L['_Expand Snippet/Next Placeholder'], _M.textadept.snippets._insert}, + {_L['_Previous Snippet Placeholder'], _M.textadept.snippets._previous}, + {_L['_Cancel Snippet'], _M.textadept.snippets._cancel_current}, }, SEPARATOR, {_L['Show St_yle'], utils.show_style}, @@ -172,7 +170,7 @@ local menubar = { {_L['UTF-1_6 Encoding'], {utils.set_encoding, 'UTF-16LE'}}, }, SEPARATOR, - {_L['Select _Lexer...'], m_textadept.mime_types.select_lexer}, + {_L['Select _Lexer...'], _M.textadept.mime_types.select_lexer}, {_L['_Refresh Syntax Highlighting'], {buffer.colourise, buffer, 0, -1}}, }, { title = _L['_View'], @@ -228,8 +226,27 @@ local context_menu = { {_L['Select _All'], buffer.select_all} } -local key_shortcuts = {} -local menu_actions, contextmenu_actions = {}, {} +-- Returns the GDK integer keycode and modifier mask for a key sequence. +-- This is used for creating menu accelerators. +-- @param key_seq The string key sequence. +-- @return keycode and modifier mask +local function get_gdk_key(key_seq) + if not key_seq then return nil end + local mods, key = key_seq:match('^([cams]*)(.+)$') + if not mods or not key then return nil end + local modifiers = ((mods:find('s') or key:lower() ~= key) and 1 or 0) + + (mods:find('c') and 4 or 0) + (mods:find('a') and 8 or 0) + + (mods:find('m') and 268435456 or 0) + local byte = string.byte(key) + if #key > 1 or byte < 32 then + for i, s in pairs(keys.KEYSYMS) do + if s == key and i > 0xFE20 then byte = i break end + end + end + return byte, modifiers +end + +local key_shortcuts, menu_actions, contextmenu_actions -- Creates a menu suitable for `gui.menu()` from the menu table format. -- Also assigns key commands. @@ -248,7 +265,7 @@ local function read_menu_table(menu, contextmenu) local label, f = menuitem[1], menuitem[2] local menu_id = not contextmenu and #menu_actions + 1 or #contextmenu_actions + 1000 + 1 - local key, mods = keys.get_gdk_key(key_shortcuts[get_id(f)]) + local key, mods = get_gdk_key(key_shortcuts[get_id(f)]) gtkmenu[#gtkmenu + 1] = {label, menu_id, key, mods} if f then local actions = not contextmenu and menu_actions or contextmenu_actions @@ -259,8 +276,6 @@ local function read_menu_table(menu, contextmenu) return gtkmenu end -local items, commands - -- Builds the item and commands tables for the filtered list dialog. -- @param menu The menu to read from. -- @param title The title of the menu. @@ -280,6 +295,8 @@ local function build_command_tables(menu, title, items, commands) end end +local items, commands + --- -- Sets `gui.menubar` from *menubar*, a table of menus. -- Each menu is an ordered list of menu items and has a `title` key for the @@ -321,19 +338,17 @@ function M.set_contextmenu(menu) end if not CURSES then M.set_contextmenu(context_menu) end -local columns = {_L['Command'], _L['Key Command']} --- -- Prompts the user to select a menu command to run. -- @name select_command function M.select_command() - local i = gui.filteredlist(_L['Run Command'], columns, items, true, + local i = gui.filteredlist(_L['Run Command'], + {_L['Command'], _L['Key Command']}, items, true, CURSES and {'--width', gui.size[1] - 2} or '') if i then keys.run_command(commands[i + 1], type(commands[i + 1])) end end -local events, events_connect = events, events.connect - -events_connect(events.MENU_CLICKED, function(menu_id) +events.connect(events.MENU_CLICKED, function(menu_id) local actions = menu_id < 1000 and menu_actions or contextmenu_actions local action = actions[menu_id < 1000 and menu_id or menu_id - 1000] if type(action) ~= 'function' and type(action) ~= 'table' then @@ -348,10 +363,10 @@ if not CURSES then local lang = _G.buffer:get_lexer(true) M.set_contextmenu(_M[lang] and _M[lang].context_menu or context_menu) end - events_connect(events.LANGUAGE_MODULE_LOADED, set_language_contextmenu) - events_connect(events.BUFFER_AFTER_SWITCH, set_language_contextmenu) - events_connect(events.VIEW_AFTER_SWITCH, set_language_contextmenu) - events_connect(events.BUFFER_NEW, set_lang_contextmenu) + events.connect(events.LANGUAGE_MODULE_LOADED, set_language_contextmenu) + events.connect(events.BUFFER_AFTER_SWITCH, set_language_contextmenu) + events.connect(events.VIEW_AFTER_SWITCH, set_language_contextmenu) + events.connect(events.BUFFER_NEW, set_lang_contextmenu) end return M diff --git a/modules/textadept/mime_types.lua b/modules/textadept/mime_types.lua index 0baa6a8a..90924fb3 100644 --- a/modules/textadept/mime_types.lua +++ b/modules/textadept/mime_types.lua @@ -15,7 +15,6 @@ local M = {} module('_M.textadept.mime_types')]] -- Events. -local events, events_connect = events, events.connect events.LANGUAGE_MODULE_LOADED = 'language_module_loaded' --- @@ -112,19 +111,19 @@ local function set_lexer_functions() buffer.get_lexer, buffer.set_lexer = get_lexer, set_lexer buffer.get_style_name = get_style_name end -events_connect(events.BUFFER_NEW, set_lexer_functions, 1) +events.connect(events.BUFFER_NEW, set_lexer_functions, 1) -- Scintilla's first buffer does not have these. if not RESETTING then set_lexer_functions() end -- Auto-detect lexer on file open or save as. -events_connect(events.FILE_OPENED, function() buffer:set_lexer() end) -events_connect(events.FILE_SAVED_AS, function() buffer:set_lexer() end) +events.connect(events.FILE_OPENED, function() buffer:set_lexer() end) +events.connect(events.FILE_SAVED_AS, function() buffer:set_lexer() end) -- Restores the buffer's lexer. local function restore_lexer() buffer:set_lexer(buffer._lexer) end -events_connect(events.BUFFER_AFTER_SWITCH, restore_lexer) -events_connect(events.VIEW_NEW, restore_lexer) -events_connect(events.RESET_AFTER, restore_lexer) +events.connect(events.BUFFER_AFTER_SWITCH, restore_lexer) +events.connect(events.VIEW_NEW, restore_lexer) +events.connect(events.RESET_AFTER, restore_lexer) --- -- Prompts the user to select a lexer for the current buffer. diff --git a/modules/textadept/run.lua b/modules/textadept/run.lua index e5965fde..91c8a522 100644 --- a/modules/textadept/run.lua +++ b/modules/textadept/run.lua @@ -218,7 +218,6 @@ function M.goto_error(line, next) -- If no line was given, find the next error marker. if not line and next ~= nil then - local buffer = buffer local f = buffer['marker_'..(next and 'next' or 'previous')] line = f(buffer, buffer:line_from_position(buffer.current_pos) + (next and 1 or -1), 2^MARK_ERROR) diff --git a/modules/textadept/session.lua b/modules/textadept/session.lua index e6a9063e..a7cd6dae 100644 --- a/modules/textadept/session.lua +++ b/modules/textadept/session.lua @@ -71,11 +71,9 @@ function M.load(filename) local anchor = tonumber(anchor) or 0 local current_pos = tonumber(current_pos) or 0 local first_visible_line = tonumber(first_visible_line) or 0 - local buffer = buffer buffer._anchor, buffer._current_pos = anchor, current_pos buffer._first_visible_line = first_visible_line - buffer:line_scroll(0, - buffer:visible_from_doc_line(first_visible_line)) + buffer:line_scroll(0, buffer:visible_from_doc_line(first_visible_line)) buffer:set_sel(anchor, current_pos) elseif line:find('^%s*split%d:') then local level, num, type, size = line:match('^(%s*)split(%d): (%S+) (%d+)') @@ -97,10 +95,7 @@ function M.load(filename) local filename = line:match('^recent: (.+)$') local recent, exists = io.recent_files, false for i, file in ipairs(recent) do - if filename == file then - exists = true - break - end + if filename == file then exists = true break end end if not exists then recent[#recent + 1] = filename end end @@ -186,9 +181,9 @@ function M.save(filename) -- Write out other things. local size = gui.size session[#session + 1] = ("size: %d %d"):format(size[1], size[2]) - for i, filename in ipairs(io.recent_files) do + for i = 1, #io.recent_files do if i > M.MAX_RECENT_FILES then break end - session[#session + 1] = ("recent: %s"):format(filename) + session[#session + 1] = ("recent: %s"):format(io.recent_files[i]) end -- Write the session. local f = io.open(filename, 'wb') @@ -203,8 +198,8 @@ events.connect(events.QUIT, function() end, 1) -- Does not save session on quit. -local function no_session() M.SAVE_ON_QUIT = false end -args.register('-n', '--nosession', 0, no_session, '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 lfs.attributes(name) then M.load(name) return end diff --git a/modules/textadept/snippets.lua b/modules/textadept/snippets.lua index 5917f41c..05324a25 100644 --- a/modules/textadept/snippets.lua +++ b/modules/textadept/snippets.lua @@ -79,19 +79,13 @@ module('_M.textadept.snippets')]=] -- The stack of currently running snippets. local snippet_stack = {} --- Contains newline sequences for `buffer.eol_mode`. --- This table is used by `new_snippet()`. --- @class table --- @name newlines -local newlines = {[0] = '\r\n', '\r', '\n'} - local INDIC_SNIPPET = _SCINTILLA.next_indic_number() +local newlines = {[0] = '\r\n', '\r', '\n'} -- Inserts a new snippet. -- @param text The new snippet to insert. -- @param trigger The trigger text used to expand the snippet, if any. local function new_snippet(text, trigger) - local buffer = buffer local snippet = setmetatable({ trigger = trigger, original_sel_text = buffer:get_sel_text(), @@ -140,7 +134,6 @@ end -- @see buffer.word_chars -- @name _insert function M._insert(text) - local buffer = buffer local trigger if not text then local lexer = buffer:get_lexer(true) @@ -179,7 +172,7 @@ end -- language-specific snippets. -- @name _select function M._select() - local list = {} + local list, t = {}, {} local type = type for trigger, text in pairs(snippets) do if type(text) == 'string' then list[#list + 1] = trigger..'\0 \0'..text end @@ -191,7 +184,6 @@ function M._select() end end table.sort(list) - local t = {} for i = 1, #list do t[#t + 1], t[#t + 2], t[#t + 3] = list[i]:match('^(%Z+)%z(%Z+)%z(%Z+)$') end @@ -238,7 +230,6 @@ M._snippet_mt = { -- @param snippet The snippet returned by `new_snippet()`. -- @param text The snippet's text. set_text = function(snippet, text) - local buffer = buffer buffer.target_start = snippet.start_position buffer.target_end = snippet:get_end_position() buffer:replace_target(text) @@ -341,19 +332,15 @@ M._snippet_mt = { -- Goes to the previous placeholder in a snippet. -- @param snippet The snippet returned by `new_snippet()`. previous = function(snippet) - if snippet.index > 2 then - snippet:set_text(snippet.snapshots[snippet.index - 2]) - snippet.index = snippet.index - 2 - snippet:next() - else - snippet:cancel() - end + if snippet.index <= 2 then snippet:cancel() return end + snippet:set_text(snippet.snapshots[snippet.index - 2]) + snippet.index = snippet.index - 2 + snippet:next() end, -- Cancels a snippet. -- @param snippet The snippet returned by `new_snippet()`. cancel = function(snippet) - local buffer = buffer buffer:set_sel(snippet.start_position, snippet:get_end_position()) buffer:replace_sel(snippet.trigger or snippet.original_sel_text) buffer.indicator_current = INDIC_SNIPPET @@ -364,7 +351,6 @@ M._snippet_mt = { -- Finishes a snippet by going to its "%0" placeholder and cleaning up. -- @param snippet The snippet returned by `new_snippet()`. finish = function(snippet) - local buffer = buffer snippet:set_text(snippet.unescape_text(snippet:get_text(), true)) local s, e = snippet:get_text():find('%%0') if s and e then |