From 03c4016d07477781aa3adcc9edf340c0bec9c6c8 Mon Sep 17 00:00:00 2001 From: mitchell <70453897+orbitalquark@users.noreply.github.com> Date: Tue, 20 Oct 2020 15:29:03 -0400 Subject: Code cleanup. Of note: * io.save_all_files() does not visit each buffer to save anymore. An unintended side-effect was checking for outside modification (but only if the file itself was modified), so outside changes will always be saved over now. * The menu clicked handler uses assert_type(), so the 'Unknown command' localization is no longer needed. * When printing to a new buffer type would split the view, use an existing split view when possible. * Prefer 'goto continue' construct in loops over nested 'if's. * Fixed clearing of ui.find.replace_entry_text on reset in the GUI version. * Fixed lack of statusbar updating when setting options like buffer EOL mode, indentation, and encoding. * Renamed internal new_snippet() to new() and put it in the snippet metatable. --- core/args.lua | 6 +- core/assert.lua | 2 +- core/events.lua | 7 +-- core/file_io.lua | 66 ++++++++-------------- core/init.lua | 14 ++--- core/keys.lua | 27 +++------ core/lfs_ext.lua | 62 ++++++++++---------- core/locale.conf | 3 - core/locale.lua | 14 ++--- core/locales/locale.ar.conf | 3 - core/locales/locale.de.conf | 3 - core/locales/locale.es.conf | 3 - core/locales/locale.fr.conf | 3 - core/locales/locale.it.conf | 3 - core/locales/locale.pl.conf | 3 - core/locales/locale.ru.conf | 3 - core/locales/locale.sv.conf | 3 - core/locales/locale.zh.conf | 3 - core/ui.lua | 134 ++++++++++++++++++++++---------------------- 19 files changed, 151 insertions(+), 211 deletions(-) (limited to 'core') diff --git a/core/args.lua b/core/args.lua index 3d249c9a..af605d36 100644 --- a/core/args.lua +++ b/core/args.lua @@ -11,7 +11,7 @@ module('args')]] events.ARG_NONE = 'arg_none' --- Contains registered command line options. +-- Map of registered command line options. -- @class table -- @name options local options = {} @@ -44,6 +44,8 @@ end -- Emits an `ARG_NONE` event when no arguments are present unless -- *no_emit_arg_none* is `true`. -- @param arg Argument table. +-- @param no_emit_arg_none When `true`, do not emit `ARG_NONE` when no arguments +-- are present. The default value is `false`. -- @see register -- @see _G.events local function process(arg, no_emit_arg_none) @@ -135,7 +137,7 @@ M.register('-t', '--test', 1, function(patterns) local arg = {} for patt in (patterns or ''):gmatch('[^,]+') do arg[#arg + 1] = patt end local env = setmetatable({arg = arg}, {__index = _G}) - assert(loadfile(_HOME..'/test/test.lua', 't', env))() + assert(loadfile(_HOME .. '/test/test.lua', 't', env))() end) end, 'Runs unit tests indicated by comma-separated list of patterns (or all)') diff --git a/core/assert.lua b/core/assert.lua index baa08d5b..80e50a6e 100644 --- a/core/assert.lua +++ b/core/assert.lua @@ -31,7 +31,7 @@ end -- This is intended to be used with API function arguments so users receive more -- helpful error messages. -- @param v Value to assert the type of. --- @param expected_type String type to assert. It may be a punctuation-delimited +-- @param expected_type String type to assert. It may be a non-letter-delimited -- list of type options. -- @param narg The positional argument number *v* is associated with. This is -- not required to be a number. diff --git a/core/events.lua b/core/events.lua index 7282172d..1c146145 100644 --- a/core/events.lua +++ b/core/events.lua @@ -391,11 +391,10 @@ end -- Handles Scintilla notifications. M.connect('SCN', function(notification) - local f = _SCINTILLA.events[notification.code] - if not f then return end + local iface = _SCINTILLA.events[notification.code] local args = {} - for i = 2, #f do args[i - 1] = notification[f[i]] end - return M.emit(f[1], table.unpack(args)) + for i = 2, #iface do args[i - 1] = notification[iface[i]] end + return M.emit(iface[1], table.unpack(args)) end) -- Set event constants. diff --git a/core/file_io.lua b/core/file_io.lua index 39d005b2..0426083a 100644 --- a/core/file_io.lua +++ b/core/file_io.lua @@ -42,13 +42,8 @@ module('io')]] -- Events. -local events, events_connect = events, events.connect -events.FILE_OPENED = 'file_opened' -events.FILE_BEFORE_RELOAD = 'file_before_reload' -events.FILE_AFTER_RELOAD = 'file_after_reload' -events.FILE_BEFORE_SAVE = 'file_before_save' -events.FILE_AFTER_SAVE = 'file_after_save' -events.FILE_CHANGED = 'file_changed' +local file_io_events = {'file_opened','file_before_reload','file_after_reload','file_before_save','file_after_save','file_changed'} +for _, v in ipairs(file_io_events) do events[v:upper()] = v end io.quick_open_max = 1000 @@ -137,7 +132,7 @@ function io.open_file(filenames, encodings) buffer.code_page = buffer.encoding and buffer.CP_UTF8 or 0 -- Detect EOL mode. local s, e = text:find('\r?\n') - if s then buffer.eol_mode = buffer[s < e and 'EOL_CRLF' or 'EOL_LF'] end + if s then buffer.eol_mode = buffer[s ~= e and 'EOL_CRLF' or 'EOL_LF'] end -- Insert buffer text and set properties. buffer:append_text(text) buffer:empty_undo_buffer() @@ -225,22 +220,17 @@ end -- @see buffer.save -- @name save_all_files function io.save_all_files() - local current_buffer = buffer for _, buffer in ipairs(_BUFFERS) do - if buffer.filename and buffer.modify then - view:goto_buffer(buffer) - buffer:save() - end + if buffer.filename and buffer.modify then buffer:save() end end - view:goto_buffer(current_buffer) end -- LuaDoc is in core/.buffer.luadoc. local function close(buffer, force) if not buffer then buffer = _G.buffer end - local filename = buffer.filename or buffer._type or _L['Untitled'] - if buffer.filename then filename = filename:iconv('UTF-8', _CHARSET) end if buffer.modify and not force then + local filename = buffer.filename or buffer._type or _L['Untitled'] + if buffer.filename then filename = filename:iconv('UTF-8', _CHARSET) end local button = ui.dialogs.msgbox{ title = _L['Close without saving?'], text = _L['There are unsaved changes in'], informative_text = filename, @@ -262,15 +252,12 @@ end -- @see buffer.close -- @name close_all_buffers function io.close_all_buffers() - while #_BUFFERS > 1 do - view:goto_buffer(_BUFFERS[#_BUFFERS]) - if not buffer:close() then return nil end -- do not propagate key command - end + while #_BUFFERS > 1 do if not buffer:close() then return nil end end return buffer:close() -- the last one end -- Sets buffer io methods and the default buffer encoding. -events_connect(events.BUFFER_NEW, function() +events.connect(events.BUFFER_NEW, function() buffer.reload = reload buffer.set_encoding, buffer.encoding = set_encoding, 'UTF-8' buffer.save, buffer.save_as, buffer.close = save, save_as, close @@ -286,20 +273,19 @@ io._reload, io._save, io._save_as, io._close = reload, save, save_as, close local function update_modified_file() if not buffer.filename then return end local mod_time = lfs.attributes(buffer.filename, 'modification') - if not mod_time or not buffer.mod_time then return end - if buffer.mod_time < mod_time then + if mod_time and buffer.mod_time and buffer.mod_time < mod_time then buffer.mod_time = mod_time events.emit(events.FILE_CHANGED, buffer.filename) end end -events_connect(events.BUFFER_AFTER_SWITCH, update_modified_file) -events_connect(events.VIEW_AFTER_SWITCH, update_modified_file) -events_connect(events.FOCUS, update_modified_file) -events_connect(events.RESUME, update_modified_file) +events.connect(events.BUFFER_AFTER_SWITCH, update_modified_file) +events.connect(events.VIEW_AFTER_SWITCH, update_modified_file) +events.connect(events.FOCUS, update_modified_file) +events.connect(events.RESUME, update_modified_file) -- Prompts the user to reload the current file if it has been externally -- modified. -events_connect(events.FILE_CHANGED, function(filename) +events.connect(events.FILE_CHANGED, function(filename) local button = ui.dialogs.msgbox{ title = _L['Reload?'], text = _L['Reload modified file?'], informative_text = string.format( @@ -312,12 +298,10 @@ events_connect(events.FILE_CHANGED, function(filename) end) -- Closes the initial "Untitled" buffer when another buffer is opened. -events_connect(events.FILE_OPENED, function() - local buf = _BUFFERS[1] - if #_BUFFERS == 2 and not (buf.filename or buf._type or buf.modify) then - view:goto_buffer(_BUFFERS[1]) - buffer:close() - end +events.connect(events.FILE_OPENED, function() + if #_BUFFERS > 2 then return end + local first = _BUFFERS[1] + if not (first.filename or first._type or first.modify) then first:close() end end) --- @@ -392,8 +376,8 @@ io.quick_open_filters = {} -- search. The default value is the current project's root directory, if -- available. -- @param filter Optional filter for files and directories to include and/or --- exclude. The default value is `lfs.default_filter` unless *paths* is a --- string and a filter for it is defined in `io.quick_open_filters`. +-- exclude. The default value is `lfs.default_filter` unless a filter for +-- *paths* is defined in `io.quick_open_filters`. -- @param opts Optional table of additional options for -- `ui.dialogs.filteredlist()`. -- @usage io.quick_open(buffer.filename:match('^(.+)[/\\]')) -- list all files @@ -412,15 +396,13 @@ function io.quick_open(paths, filter, opts) paths = io.get_project_root() if not paths then return end end - if type(paths) == 'string' then - if not filter then filter = io.quick_open_filters[paths] end - paths = {paths} + if not assert_type(filter, 'string/table/nil', 2) then + filter = io.quick_open_filters[paths] or lfs.default_filter end - assert_type(filter, 'string/table/nil', 2) assert_type(opts, 'table/nil', 3) local utf8_list = {} - for i = 1, #paths do - for filename in lfs.walk(paths[i], filter or lfs.default_filter) do + for _, path in ipairs(type(paths) == 'table' and paths or {paths}) do + for filename in lfs.walk(path, filter) do if #utf8_list >= io.quick_open_max then break end utf8_list[#utf8_list + 1] = filename:iconv('UTF-8', _CHARSET) end diff --git a/core/init.lua b/core/init.lua index f71cd6be..e2674e48 100644 --- a/core/init.lua +++ b/core/init.lua @@ -44,22 +44,20 @@ end -- argument. -- Documentation is in core/.buffer.luadoc. local function text_range(buffer, start_pos, end_pos) - assert_type(start_pos, 'number', 2) - assert_type(end_pos, 'number', 3) local target_start, target_end = buffer.target_start, buffer.target_end - if start_pos < 1 then start_pos = 1 end - if end_pos > buffer.length + 1 then end_pos = buffer.length + 1 end - buffer:set_target_range(start_pos, end_pos) + buffer:set_target_range( + math.max(1, assert_type(start_pos, 'number', 2)), + math.min(assert_type(end_pos, 'number', 3), buffer.length + 1)) local text = buffer.target_text buffer:set_target_range(target_start, target_end) -- restore return text end +local GETNAMEDSTYLE = _SCINTILLA.properties.named_styles[1] -- Documentation is in core/.buffer.luadoc. local function style_of_name(buffer, style_name) - assert_type(style_name, 'string', 2) - local GETNAMEDSTYLE = _SCINTILLA.properties.named_styles[1] - return buffer:private_lexer_call(GETNAMEDSTYLE, style_name) + return buffer:private_lexer_call( + GETNAMEDSTYLE, assert_type(style_name, 'string', 2)) end events.connect(events.BUFFER_NEW, function() diff --git a/core/keys.lua b/core/keys.lua index ac9523ab..2d4d8781 100644 --- a/core/keys.lua +++ b/core/keys.lua @@ -112,8 +112,8 @@ local M = {} -- The default value is `nil`. module('keys')]] -local CTRL, ALT, SHIFT = 'ctrl+', not CURSES and 'alt+' or 'meta+', 'shift+' -local CMD = 'cmd+' +local CTRL, ALT, CMD, SHIFT = 'ctrl+', 'alt+', 'cmd+', 'shift+' +if CURSES then ALT = 'meta+' end M.CLEAR = 'esc' --- @@ -151,7 +151,7 @@ local INVALID, PROPAGATE, CHAIN, HALT = -1, 0, 1, 2 -- Error handler for key commands that simply emits the error. This is needed -- so `key_command()` can return `HALT` instead of never returning due to the -- error. -local function key_error(e) events.emit(events.ERROR, e) end +local function key_error(errmsg) events.emit(events.ERROR, errmsg) end -- Runs a key command associated with the current keychain. -- @param prefix Optional prefix name for mode/lexer-specific commands. @@ -171,19 +171,11 @@ local function key_command(prefix) return select(2, xpcall(key, key_error)) == false and PROPAGATE or HALT end --- Handles Textadept keypresses. --- It is called every time a key is pressed, and based on a mode or lexer, --- executes a command. The command is looked up in the `_G.keys` table. --- @param code The keycode. --- @param shift Whether or not the Shift modifier is pressed. --- @param control Whether or not the Control modifier is pressed. --- @param alt Whether or not the Alt/option modifier is pressed. --- @param cmd Whether or not the Command modifier on macOS is pressed. --- @param caps_lock Whether or not Caps Lock is enabled. --- @return `true` to stop handling the key; `nil` otherwise. -local function keypress(code, shift, control, alt, cmd, caps_lock) - --print(code, M.KEYSYMS[code], shift, control, alt, cmd, caps_lock) - if caps_lock and (shift or control or alt or cmd) and code < 256 then +-- Handles Textadept keypresses, executing commands based on a mode or lexer as +-- necessary. +events.connect(events.KEYPRESS, function(code, shift, control, alt, cmd, caps) + --print(code, M.KEYSYMS[code], shift, control, alt, cmd, caps) + if caps and (shift or control or alt or cmd) and code < 256 then code = string[shift and 'upper' or 'lower'](string.char(code)):byte() end local key = code >= 32 and code < 256 and string.char(code) or M.KEYSYMS[code] @@ -216,8 +208,7 @@ local function keypress(code, shift, control, alt, cmd, caps_lock) return true end -- PROPAGATE otherwise. -end -events.connect(events.KEYPRESS, keypress) +end) --[[ This comment is for LuaDoc. --- diff --git a/core/lfs_ext.lua b/core/lfs_ext.lua index 86a0cada..c24ee2e9 100644 --- a/core/lfs_ext.lua +++ b/core/lfs_ext.lua @@ -22,33 +22,6 @@ lfs.default_filter = {--[[Extensions]]'!.a','!.bmp','!.bz2','!.class','!.dll','! -- @param level Utility value indicating the directory level this function is -- at. local function walk(dir, filter, n, include_dirs, level) - if not level then - -- Convert filter to a table from nil or string arguments. - if not filter then filter = lfs.default_filter end - if type(filter) == 'string' then filter = {filter} end - -- Process the given filter into something that can match files more easily - -- and/or quickly. For example, convert '.ext' shorthand to '%.ext$', - -- substitute '/' with '[/\\]', and enable hash lookup for file extensions - -- to include or exclude. - local processed_filter = { - consider_any = true, - exts = setmetatable({}, {__index = function() return true end}) - } - for _, patt in ipairs(filter) do - patt = patt:gsub('^(!?)%%?%.([^.]+)$', '%1%%.%2$') -- '.lua' to '%.lua$' - patt = patt:gsub('/([^\\])', '[/\\]%1') -- '/' to '[/\\]' - local include = not patt:find('^!') - local ext = patt:match('^!?%%.([^.]+)%$$') - if ext then - processed_filter.exts[ext] = include - if include then setmetatable(processed_filter.exts, nil) end - else - if include then processed_filter.consider_any = false end - processed_filter[#processed_filter + 1] = patt - end - end - filter = processed_filter - end for basename in lfs.dir(dir) do if basename:find('^%.%.?$') then goto continue end -- ignore . and .. local filename = dir .. (dir ~= '/' and '/' or '') .. basename @@ -68,14 +41,15 @@ local function walk(dir, filter, n, include_dirs, level) -- Treat inclusive patterns as logical OR. include = include or (not patt:find('^!') and filename:find(patt)) end + if not include then goto continue end local sep = not WIN32 and '/' or '\\' local os_filename = not WIN32 and filename or filename:gsub('/', sep) - if include and mode == 'directory' then + if mode == 'file' then + coroutine.yield(os_filename) + elseif mode == 'directory' then if include_dirs then coroutine.yield(os_filename .. sep) end if n and (level or 0) >= n then goto continue end walk(filename, filter, n, include_dirs, (level or 0) + 1) - elseif include and mode == 'file' then - coroutine.yield(os_filename) end ::continue:: end @@ -104,9 +78,33 @@ end -- @name walk function lfs.walk(dir, filter, n, include_dirs) assert_type(dir, 'string', 1) - assert_type(filter, 'string/table/nil', 2) + if not assert_type(filter, 'string/table/nil', 2) then + filter = lfs.default_filter + end assert_type(n, 'number/nil', 3) - local co = coroutine.create(function() walk(dir, filter, n, include_dirs) end) + -- Process the given filter into something that can match files more easily + -- and/or quickly. For example, convert '.ext' shorthand to '%.ext$', + -- substitute '/' with '[/\\]', and enable hash lookup for file extensions + -- to include or exclude. + local processed_filter = { + consider_any = true, + exts = setmetatable({}, {__index = function() return true end}) + } + for _, patt in ipairs(type(filter) == 'table' and filter or {filter}) do + patt = patt:gsub('^(!?)%%?%.([^.]+)$', '%1%%.%2$') -- '.lua' to '%.lua$' + patt = patt:gsub('/([^\\])', '[/\\]%1') -- '/' to '[/\\]' + local include = not patt:find('^!') + local ext = patt:match('^!?%%.([^.]+)%$$') + if ext then + processed_filter.exts[ext] = include + if include then setmetatable(processed_filter.exts, nil) end + else + if include then processed_filter.consider_any = false end + processed_filter[#processed_filter + 1] = patt + end + end + local co = coroutine.create( + function() walk(dir, processed_filter, n, include_dirs) end) return function() return select(2, coroutine.resume(co)) end end diff --git a/core/locale.conf b/core/locale.conf index d5f60436..18a62e2b 100644 --- a/core/locale.conf +++ b/core/locale.conf @@ -336,9 +336,6 @@ Help = _Help Show Manual = Show _Manual Show LuaDoc = Show _LuaDoc About = _About -# The error message displayed when activating a menu item associated with an -# unknown command. -Unknown command: = Unknown command: # The text displayed in the dialog for running an arbitrary menu command. Any # key binding associated with commands are also shown. Run Command = Run Command diff --git a/core/locale.lua b/core/locale.lua index 48701116..3a661fae 100644 --- a/core/locale.lua +++ b/core/locale.lua @@ -23,14 +23,14 @@ assert(f, '"core/locale.conf" not found') for line in f:lines() do -- Any line that starts with a non-word character except '[' is considered a -- comment. - if not line:find('^%s*[^%w_%[]') then - local id, str = line:match('^(.-)%s*=%s*(.-)\r?$') - if id and str and assert(not M[id], 'duplicate locale key "%s"', id) then - M[id] = not CURSES and str or str:gsub('_', '') - end + if not line:find('^%s*[%w_%[]') then goto continue end + local id, str = line:match('^(.-)%s*=%s*(.-)\r?$') + if id and str and assert(not M[id], 'duplicate locale key "%s"', id) then + M[id] = not CURSES and str or str:gsub('_', '') end + ::continue:: end f:close() -setmetatable(M, {__index = function(_, k) return 'No Localization:' .. k end}) -return M +return setmetatable( + M, {__index = function(_, k) return 'No Localization:' .. k end}) diff --git a/core/locales/locale.ar.conf b/core/locales/locale.ar.conf index 953d3d38..e894445e 100644 --- a/core/locales/locale.ar.conf +++ b/core/locales/locale.ar.conf @@ -336,9 +336,6 @@ Help = م_ساعدة Show Manual = عرض الد_ليل Show LuaDoc = عرض و_ثائق لُوَ About = ع_ن -# The error message displayed when activating a menu item associated with an -# unknown command. -Unknown command: = أمر مجهول: # The text displayed in the dialog for running an arbitrary menu command. Any # key binding associated with commands are also shown. Run Command = شغِّل الأمر diff --git a/core/locales/locale.de.conf b/core/locales/locale.de.conf index 22d46b5c..d73ca229 100644 --- a/core/locales/locale.de.conf +++ b/core/locales/locale.de.conf @@ -336,9 +336,6 @@ Help = _Hilfe Show Manual = Handbuch anzeigen Show LuaDoc = LuaDoc anzeigen About = _Über Textadept -# The error message displayed when activating a menu item associated with an -# unknown command. -Unknown command: = Unbekannter Befehl: # The text displayed in the dialog for running an arbitrary menu command. Any # key binding associated with commands are also shown. Run Command = Befehl ausführen diff --git a/core/locales/locale.es.conf b/core/locales/locale.es.conf index 354a33fc..273b90ca 100644 --- a/core/locales/locale.es.conf +++ b/core/locales/locale.es.conf @@ -336,9 +336,6 @@ Help = A_yuda Show Manual = Mostrar _manual Show LuaDoc = Mostrar _LuaDoc About = Acerca _de -# The error message displayed when activating a menu item associated with an -# unknown command. -Unknown command: = Comando desconocido: # The text displayed in the dialog for running an arbitrary menu command. Any # key binding associated with commands are also shown. Run Command = Ejecutar comando diff --git a/core/locales/locale.fr.conf b/core/locales/locale.fr.conf index b2fff92d..f3afccfa 100644 --- a/core/locales/locale.fr.conf +++ b/core/locales/locale.fr.conf @@ -337,9 +337,6 @@ Help = Aid_e Show Manual = Voir _manuel Show LuaDoc = Voir la documentation sur l’_API About = À _propos -# The error message displayed when activating a menu item associated with an -# unknown command. -Unknown command: = Commande inconnue: # The text displayed in the dialog for running an arbitrary menu command. Any # key binding associated with commands are also shown. Run Command = Lancer une commande diff --git a/core/locales/locale.it.conf b/core/locales/locale.it.conf index 91d4958a..d9c508a1 100644 --- a/core/locales/locale.it.conf +++ b/core/locales/locale.it.conf @@ -336,9 +336,6 @@ Help = _Aiuto Show Manual = _Manuale Show LuaDoc = _Documentazione sull’API About = _Informazioni -# The error message displayed when activating a menu item associated with an -# unknown command. -Unknown command: = Comando sconosciuto: # The text displayed in the dialog for running an arbitrary menu command. Any # key binding associated with commands are also shown. Run Command = Scegli un comando diff --git a/core/locales/locale.pl.conf b/core/locales/locale.pl.conf index bbe34282..a33b1d69 100644 --- a/core/locales/locale.pl.conf +++ b/core/locales/locale.pl.conf @@ -337,9 +337,6 @@ Help = P_omoc Show Manual = Po_dręcznik użytkownika... Show LuaDoc = _LuaDoc... About = _O programie... -# The error message displayed when activating a menu item associated with an -# unknown command. -Unknown command: = Nieznane polecenie: # The text displayed in the dialog for running an arbitrary menu command. Any # key binding associated with commands are also shown. Run Command = Wykonaj polecenie diff --git a/core/locales/locale.ru.conf b/core/locales/locale.ru.conf index 3bfb7198..476d0f63 100644 --- a/core/locales/locale.ru.conf +++ b/core/locales/locale.ru.conf @@ -336,9 +336,6 @@ Help = _Справка Show Manual = Показать _руководство Show LuaDoc = Показать документацию по _lua About = _О программе -# The error message displayed when activating a menu item associated with an -# unknown command. -Unknown command: = Неизвестная команда: # The text displayed in the dialog for running an arbitrary menu command. Any # key binding associated with commands are also shown. Run Command = Выполнить команду diff --git a/core/locales/locale.sv.conf b/core/locales/locale.sv.conf index d56d2456..f6f01d17 100644 --- a/core/locales/locale.sv.conf +++ b/core/locales/locale.sv.conf @@ -336,9 +336,6 @@ Help = _Hjälp Show Manual = _Manual Show LuaDoc = _LuaDoc About = _Om -# The error message displayed when activating a menu item associated with an -# unknown command. -Unknown command: = Okänt kommando: # The text displayed in the dialog for running an arbitrary menu command. Any # key binding associated with commands are also shown. Run Command = Kör kommando diff --git a/core/locales/locale.zh.conf b/core/locales/locale.zh.conf index dbce6e55..54476596 100644 --- a/core/locales/locale.zh.conf +++ b/core/locales/locale.zh.conf @@ -336,9 +336,6 @@ Help = 帮助(_H) Show Manual = 打开手册(_M) Show LuaDoc = 打开_LuaDoc About = 关于(_A) -# The error message displayed when activating a menu item associated with an -# unknown command. -Unknown command: = 未知命令: # The text displayed in the dialog for running an arbitrary menu command. Any # key binding associated with commands are also shown. Run Command = 运行命令 diff --git a/core/ui.lua b/core/ui.lua index 343b4510..73616719 100644 --- a/core/ui.lua +++ b/core/ui.lua @@ -37,6 +37,12 @@ module('ui')]] ui.silent_print = false +-- Helper function for jumping to another view to print to, or creating a new +-- view to print to (the latter depending on settings). +local function prepare_view() + if #_VIEWS > 1 then ui.goto_view(1) elseif not ui.tabs then view:split() end +end + -- Helper function for printing messages to buffers. -- @see ui._print local function _print(buffer_type, ...) @@ -45,21 +51,19 @@ local function _print(buffer_type, ...) if buf._type == buffer_type then buffer = buf break end end if not buffer then - if not ui.tabs then view:split() end + prepare_view() buffer = _G.buffer.new() buffer._type = buffer_type elseif not ui.silent_print then for _, view in ipairs(_VIEWS) do - if view.buffer._type == buffer_type then ui.goto_view(view) break end - end - if view.buffer._type ~= buffer_type then - if #_VIEWS > 1 then - ui.goto_view(1) - elseif not ui.tabs then - view:split() + if view.buffer._type == buffer_type then + ui.goto_view(view) + goto view_found end - view:goto_buffer(buffer) end + prepare_view() + view:goto_buffer(buffer) + ::view_found:: end local args, n = {...}, select('#', ...) for i = 1, n do args[i] = tostring(args[i]) end @@ -115,8 +119,7 @@ ui.dialogs = setmetatable({}, {__index = function(_, k) -- Transform key-value pairs into command line arguments. local args = {} for option, value in pairs(options) do - assert_type(value, 'string/number/table/boolean', option) - if value then + if assert_type(value, 'string/number/table/boolean', option) then args[#args + 1] = '--' .. option:gsub('_', '-') if type(value) == 'table' then for i, val in ipairs(value) do @@ -139,7 +142,7 @@ ui.dialogs = setmetatable({}, {__index = function(_, k) if k == 'progressbar' then args[#args + 1] = assert_type(f, 'function', 2) end - -- Call gtdialog, stripping any trailing newline in the standard output. + -- Call gtdialog, stripping any trailing newline in the output. local result = ui.dialog( k:gsub('_', '-'), table.unpack(args)):match('^(.-)\n?$') -- Depending on the dialog type, transform the result into Lua objects. @@ -185,12 +188,10 @@ ui.dialogs = setmetatable({}, {__index = function(_, k) end end}) -local events, events_connect = events, events.connect - local buffers_zorder = {} -- Adds new buffers to the z-order list. -events_connect(events.BUFFER_NEW, function() +events.connect(events.BUFFER_NEW, function() if buffer ~= ui.command_entry then table.insert(buffers_zorder, 1, buffer) end end) @@ -206,13 +207,14 @@ local function update_zorder() end table.insert(buffers_zorder, 1, buffer) end -events_connect(events.BUFFER_AFTER_SWITCH, update_zorder) -events_connect(events.VIEW_AFTER_SWITCH, update_zorder) +events.connect(events.BUFFER_AFTER_SWITCH, update_zorder) +events.connect(events.VIEW_AFTER_SWITCH, update_zorder) +events.connect(events.BUFFER_DELETED, update_zorder) -- Saves and restores buffer zorder data during a reset. -events_connect( +events.connect( events.RESET_BEFORE, function(persist) persist.ui_zorder = buffers_zorder end) -events_connect( +events.connect( events.RESET_AFTER, function(persist) buffers_zorder = persist.ui_zorder end) --- @@ -237,9 +239,8 @@ function ui.switch_buffer(zorder) local button, i = ui.dialogs.filteredlist{ title = _L['Switch Buffers'], columns = columns, items = utf8_list } - if button == 1 and i then - view:goto_buffer(buffers[not zorder and i or i + 1]) - end + if button ~= 1 or not i then return end + view:goto_buffer(buffers[not zorder and i or i + 1]) end --- @@ -290,10 +291,10 @@ function ui.goto_file(filename, split, preferred_view, sloppy) end -- Ensure title, statusbar, etc. are updated for new views. -events_connect(events.VIEW_NEW, function() events.emit(events.UPDATE_UI, 3) end) +events.connect(events.VIEW_NEW, function() events.emit(events.UPDATE_UI, 3) end) -- Switches between buffers when a tab is clicked. -events_connect( +events.connect( events.TAB_CLICKED, function(index) view:goto_buffer(_BUFFERS[index]) end) -- Sets the title of the Textadept window to the buffer's filename. @@ -309,11 +310,11 @@ local function set_title() end -- Changes Textadept title to show the buffer as being "clean" or "dirty". -events_connect(events.SAVE_POINT_REACHED, set_title) -events_connect(events.SAVE_POINT_LEFT, set_title) +events.connect(events.SAVE_POINT_REACHED, set_title) +events.connect(events.SAVE_POINT_LEFT, set_title) -- Open uri(s). -events_connect(events.URI_DROPPED, function(utf8_uris) +events.connect(events.URI_DROPPED, function(utf8_uris) for utf8_path in utf8_uris:gmatch('file://([^\r\n]+)') do local path = utf8_path:gsub('%%(%x%x)', function(hex) return string.char(tonumber(hex, 16)) @@ -325,25 +326,25 @@ events_connect(events.URI_DROPPED, function(utf8_uris) end ui.goto_view(view) -- work around any view focus synchronization issues end) -events_connect(events.APPLEEVENT_ODOC, function(uri) +events.connect(events.APPLEEVENT_ODOC, function(uri) return events.emit(events.URI_DROPPED, 'file://' .. uri) end) -- Sets buffer statusbar text. -events_connect(events.UPDATE_UI, function(updated) +events.connect(events.UPDATE_UI, function(updated) if updated & 3 == 0 then return end -- ignore scrolling local text = not CURSES and '%s %d/%d %s %d %s %s %s %s' or '%s %d/%d %s %d %s %s %s %s' - local pos = buffer.selection_n_caret[buffer.main_selection] + local pos = buffer.current_pos local line, max = buffer:line_from_position(pos), buffer.line_count local col = buffer.column[pos] local lang = buffer:get_lexer() local eol = buffer.eol_mode == buffer.EOL_CRLF and _L['CRLF'] or _L['LF'] local tabs = string.format( '%s %d', buffer.use_tabs and _L['Tabs:'] or _L['Spaces:'], buffer.tab_width) - local enc = buffer.encoding or '' + local encoding = buffer.encoding or '' ui.buffer_statusbar_text = string.format( - text, _L['Line:'], line, max, _L['Col:'], col, lang, eol, tabs, enc) + text, _L['Line:'], line, max, _L['Col:'], col, lang, eol, tabs, encoding) end) -- Save buffer properties. @@ -357,19 +358,17 @@ local function save_buffer_state() buffer._x_offset = view.x_offset -- Save fold state. local folds, i = {}, view:contracted_fold_next(1) - while i >= 1 do - folds[#folds + 1], i = i, view:contracted_fold_next(i + 1) - end + while i >= 1 do folds[#folds + 1], i = i, view:contracted_fold_next(i + 1) end buffer._folds = folds end -events_connect(events.BUFFER_BEFORE_SWITCH, save_buffer_state) -events_connect(events.FILE_BEFORE_RELOAD, save_buffer_state) +events.connect(events.BUFFER_BEFORE_SWITCH, save_buffer_state) +events.connect(events.FILE_BEFORE_RELOAD, save_buffer_state) -- Restore buffer properties. local function restore_buffer_state() if not buffer._folds then return end -- Restore fold state. - for i = 1, #buffer._folds do view:toggle_fold(buffer._folds[i]) end + for _, line in ipairs(buffer._folds) do view:toggle_fold(line) end -- Restore view state. buffer:set_sel(buffer._anchor, buffer._current_pos) buffer.selection_n_anchor_virtual_space[1] = buffer._anchor_virtual_space @@ -379,17 +378,17 @@ local function restore_buffer_state() view:line_scroll(0, view:visible_from_doc_line(_top_line) - top_line) view.x_offset = buffer._x_offset or 0 end -events_connect(events.BUFFER_AFTER_SWITCH, restore_buffer_state) -events_connect(events.FILE_AFTER_RELOAD, restore_buffer_state) +events.connect(events.BUFFER_AFTER_SWITCH, restore_buffer_state) +events.connect(events.FILE_AFTER_RELOAD, restore_buffer_state) -- Updates titlebar and statusbar. local function update_bars() set_title() events.emit(events.UPDATE_UI, 3) end -events_connect(events.BUFFER_NEW, update_bars) -events_connect(events.BUFFER_AFTER_SWITCH, update_bars) -events_connect(events.VIEW_AFTER_SWITCH, update_bars) +events.connect(events.BUFFER_NEW, update_bars) +events.connect(events.BUFFER_AFTER_SWITCH, update_bars) +events.connect(events.VIEW_AFTER_SWITCH, update_bars) -- Save view state. local function save_view_state() @@ -400,8 +399,8 @@ local function save_view_state() buffer._margin_width_n[i] = view.margin_width_n[i] end end -events_connect(events.BUFFER_BEFORE_SWITCH, save_view_state) -events_connect(events.VIEW_BEFORE_SWITCH, save_view_state) +events.connect(events.BUFFER_BEFORE_SWITCH, save_view_state) +events.connect(events.VIEW_BEFORE_SWITCH, save_view_state) -- Restore view state. local function restore_view_state() @@ -412,21 +411,21 @@ local function restore_view_state() view.margin_width_n[i] = buffer._margin_width_n[i] end end -events_connect(events.BUFFER_AFTER_SWITCH, restore_view_state) -events_connect(events.VIEW_AFTER_SWITCH, restore_view_state) +events.connect(events.BUFFER_AFTER_SWITCH, restore_view_state) +events.connect(events.VIEW_AFTER_SWITCH, restore_view_state) -events_connect( +events.connect( events.RESET_AFTER, function() ui.statusbar_text = _L['Lua reset'] end) -- Prompts for confirmation if any buffers are modified. -events_connect(events.QUIT, function() +events.connect(events.QUIT, function() local utf8_list = {} for _, buffer in ipairs(_BUFFERS) do - if buffer.modify then - local filename = buffer.filename or buffer._type or _L['Untitled'] - if buffer.filename then filename = filename:iconv('UTF-8', _CHARSET) end - utf8_list[#utf8_list + 1] = filename - end + if not buffer.modify then goto continue end + local filename = buffer.filename or buffer._type or _L['Untitled'] + if buffer.filename then filename = filename:iconv('UTF-8', _CHARSET) end + utf8_list[#utf8_list + 1] = filename + ::continue:: end if #utf8_list == 0 then return end local button = ui.dialogs.msgbox{ @@ -440,10 +439,10 @@ events_connect(events.QUIT, function() if button ~= 2 then return true end -- prevent quit end) --- Keeps track of and switches back to the previous buffer after buffer close. -events_connect( +-- Keeps track of, and switches back to the previous buffer after buffer close. +events.connect( events.BUFFER_BEFORE_SWITCH, function() view._prev_buffer = buffer end) -events_connect(events.BUFFER_DELETED, function() +events.connect(events.BUFFER_DELETED, function() if _BUFFERS[view._prev_buffer] and buffer ~= view._prev_buffer then view:goto_buffer(view._prev_buffer) end @@ -452,19 +451,20 @@ end) -- Properly handle clipboard text between views in curses, enables and disables -- mouse mode, and focuses and resizes views based on mouse events. if CURSES then - local clip_text - events.connect( - events.VIEW_BEFORE_SWITCH, function() clip_text = ui.clipboard_text end) - events.connect( - events.VIEW_AFTER_SWITCH, function() ui.clipboard_text = clip_text end) + events.connect(events.VIEW_BEFORE_SWITCH, function() + ui._clipboard_text = ui.clipboard_text + end) + events.connect(events.VIEW_AFTER_SWITCH, function() + ui.clipboard_text = ui._clipboard_text + end) if not WIN32 then local function enable_mouse() io.stdout:write("\x1b[?1002h"):flush() end local function disable_mouse() io.stdout:write("\x1b[?1002l"):flush() end enable_mouse() - events_connect(events.SUSPEND, disable_mouse) - events_connect(events.RESUME, enable_mouse) - events_connect(events.QUIT, disable_mouse) + events.connect(events.SUSPEND, disable_mouse) + events.connect(events.RESUME, enable_mouse) + events.connect(events.QUIT, disable_mouse) end -- Retrieves the view or split at the given terminal coordinates. @@ -486,7 +486,7 @@ if CURSES then end local resize - events_connect(events.MOUSE, function(event, button, y, x) + events.connect(events.MOUSE, function(event, button, y, x) if event == view.MOUSE_RELEASE or button ~= 1 then return end if event == view.MOUSE_PRESS then local view = get_view(ui.get_split_table(), y - 1, x) -- title is at y = 1 @@ -511,7 +511,7 @@ events.connect(events.INITIALIZED, function() -- Print internal Lua error messages as they are reported. -- Attempt to mimic the Lua interpreter's error message format so tools that -- look for it can recognize these errors too. - events_connect(events.ERROR, function(text) + events.connect(events.ERROR, function(text) if text and text:find(lua_error) then text = 'lua: ' .. text end ui.print(text) end) -- cgit v1.2.3