diff options
Diffstat (limited to 'modules/textadept')
-rw-r--r-- | modules/textadept/bookmarks.lua | 8 | ||||
-rw-r--r-- | modules/textadept/command_entry.lua | 27 | ||||
-rw-r--r-- | modules/textadept/editing.lua | 27 | ||||
-rw-r--r-- | modules/textadept/file_types.lua | 1 | ||||
-rw-r--r-- | modules/textadept/find.lua | 29 | ||||
-rw-r--r-- | modules/textadept/macros.lua | 21 | ||||
-rw-r--r-- | modules/textadept/menu.lua | 4 | ||||
-rw-r--r-- | modules/textadept/run.lua | 24 | ||||
-rw-r--r-- | modules/textadept/session.lua | 25 | ||||
-rw-r--r-- | modules/textadept/snippets.lua | 16 |
10 files changed, 99 insertions, 83 deletions
diff --git a/modules/textadept/bookmarks.lua b/modules/textadept/bookmarks.lua index 47cf751f..29a68c1c 100644 --- a/modules/textadept/bookmarks.lua +++ b/modules/textadept/bookmarks.lua @@ -21,6 +21,7 @@ M.MARK_BOOKMARK = _SCINTILLA.next_marker_number() -- @param line Optional line number to add or remove a bookmark on. -- @name toggle function M.toggle(on, line) + assert_type(line, 'number/nil', 2) if not line then line = buffer:line_from_position(buffer.current_pos) end local f = on and buffer.marker_add or buffer.marker_delete if on == nil then -- toggle @@ -50,10 +51,9 @@ function M.goto_mark(next) local utf8_list, buffers = {}, {} -- List the current buffer's marks, and then all other buffers' marks. for _, current_buffer_first in ipairs{true, false} do - for i = 1, #_BUFFERS do - if current_buffer_first and _BUFFERS[i] == buffer or - not current_buffer_first and _BUFFERS[i] ~= buffer then - local buffer = _BUFFERS[i] + for _, buffer in ipairs(_BUFFERS) do + if current_buffer_first and buffer == _G.buffer or + not current_buffer_first and buffer ~= _G.buffer then local basename = (buffer.filename or ''):match('[^/\\]+$') or buffer._type or _L['Untitled'] if buffer.filename then diff --git a/modules/textadept/command_entry.lua b/modules/textadept/command_entry.lua index b652e9d9..a668516f 100644 --- a/modules/textadept/command_entry.lua +++ b/modules/textadept/command_entry.lua @@ -44,20 +44,18 @@ M.editing_keys = {__index = { -- @name env local env = setmetatable({}, { __index = function(_, k) - local f = buffer[k] - if f and type(f) == 'function' then - f = function(...) return buffer[k](buffer, ...) end - elseif f == nil and type(view[k]) == 'function' then - f = function(...) view[k](view, ...) end -- do not return a value - elseif f == nil then - f = view[k] or ui[k] or _G[k] + if type(buffer[k]) == 'function' then + return function(...) return buffer[k](buffer, ...) end + elseif type(view[k]) == 'function' then + return function(...) view[k](view, ...) end -- do not return a value end - return f + return buffer[k] or view[k] or ui[k] or _G[k] end, __newindex = function(self, k, v) local ok, value = pcall(function() return buffer[k] end) if ok and value ~= nil or not ok and value:find('write-only property') then - buffer[k] = v return + buffer[k] = v + return end if view[k] ~= nil then view[k] = v return end if ui[k] ~= nil then ui[k] = v return end @@ -165,12 +163,15 @@ local lua_mode_keys = {['\t'] = complete_lua} -- @name run function M.run(f, mode_keys, lexer, height) if M:auto_c_active() then M:auto_c_cancel() end -- may happen in curses - if not f and not mode_keys then + if not assert_type(f, 'function/nil', 1) and not mode_keys then f, mode_keys, lexer = run_lua, lua_mode_keys, 'lua' - elseif type(mode_keys) == 'string' then - mode_keys, lexer, height = {}, mode_keys, lexer - elseif not mode_keys then + elseif type(assert_type(mode_keys, 'table/string/nil', 2)) == 'string' then + lexer, height = mode_keys, assert_type(lexer, 'number/nil', 3) mode_keys = {} + else + if not mode_keys then mode_keys = {} end + assert_type(lexer, 'string/nil', 3) + assert_type(height, 'number/nil', 4) end if not mode_keys['esc'] then mode_keys['esc'] = M.focus end -- hide mode_keys['\n'] = mode_keys['\n'] or function() diff --git a/modules/textadept/editing.lua b/modules/textadept/editing.lua index 5ba6bdc6..1c9fbcb3 100644 --- a/modules/textadept/editing.lua +++ b/modules/textadept/editing.lua @@ -125,7 +125,8 @@ M.api_files = setmetatable({}, {__index = function(t, k) return t[k] end}) --- Matches characters specified in auto_pairs. +-- Matches characters specified in auto_pairs, taking multiple selections into +-- account. events.connect(events.CHAR_ADDED, function(code) if M.auto_pairs and M.auto_pairs[code] then buffer:begin_undo_action() @@ -138,7 +139,7 @@ events.connect(events.CHAR_ADDED, function(code) end end) --- Removes matched chars on backspace. +-- Removes matched chars on backspace, taking multiple selections into account. events.connect(events.KEYPRESS, function(code) if not M.auto_pairs or keys.KEYSYMS[code] ~= '\b' then return end buffer:begin_undo_action() @@ -163,7 +164,8 @@ events.connect(events.UPDATE_UI, function(updated) f(pos, match) end) --- Moves over typeover characters when typed. +-- Moves over typeover characters when typed, taking multiple selections into +-- account. events.connect(events.KEYPRESS, function(code) if M.typeover_chars and M.typeover_chars[code] then local handled = false @@ -353,7 +355,7 @@ end -- one. -- @name goto_line function M.goto_line(line) - if not line then + if not assert_type(line, 'number/nil', 1) then local button, value = ui.dialogs.inputbox{ title = _L['Go To'], informative_text = _L['Line Number:'], button1 = _L['OK'], button2 = _L['Cancel'] @@ -409,6 +411,8 @@ end -- @param right The right part of the enclosure. -- @name enclose function M.enclose(left, right) + assert_type(left, 'string', 1) + assert_type(right, 'string', 2) buffer:begin_undo_action() for i = 0, buffer.selections - 1 do local s, e = buffer.selection_n_start[i], buffer.selection_n_end[i] @@ -438,7 +442,7 @@ end -- @name select_enclosed function M.select_enclosed(left, right) local s, e, anchor, pos = -1, -1, buffer.anchor, buffer.current_pos - if left and right then + if assert_type(left, 'string/nil', 1) and assert_type(right, 'string', 2) then if anchor ~= pos then buffer:goto_pos(pos - #right) end buffer:search_anchor() s, e = buffer:search_prev(0, left), buffer:search_next(0, right) @@ -590,6 +594,7 @@ end -- @name filter_through function M.filter_through(command) assert(not (WIN32 and CURSES), 'not implemented in this environment') + assert_type(command, 'string', 1) local s, e = buffer.selection_start, buffer.selection_end if s ~= e then -- Use the selected lines as input. @@ -637,7 +642,7 @@ end -- @name autocomplete -- @see autocompleters function M.autocomplete(name) - if not M.autocompleters[name] then return end + if not M.autocompleters[assert_type(name, 'string', 1)] then return end local len_entered, list = M.autocompleters[name]() if not len_entered or not list or #list == 0 then return end buffer.auto_c_order = buffer.ORDER_PERFORMSORT @@ -656,9 +661,8 @@ M.autocompleters.word = function() local s = buffer:word_start_position(buffer.current_pos, true) if s == buffer.current_pos then return end local word = buffer:text_range(s, buffer.current_pos) - for i = 1, #_BUFFERS do - if _BUFFERS[i] == buffer or M.autocomplete_all_words then - local buffer = _BUFFERS[i] + for _, buffer in ipairs(_BUFFERS) do + if buffer == _G.buffer or M.autocomplete_all_words then buffer.search_flags = buffer.FIND_WORDSTART if not buffer.auto_c_ignore_case then buffer.search_flags = buffer.search_flags + buffer.FIND_MATCHCASE @@ -696,7 +700,7 @@ function M.show_documentation(pos, case_insensitive) if buffer:call_tip_active() then events.emit(events.CALL_TIP_CLICK) return end local lang = buffer:get_lexer(true) if not M.api_files[lang] then return end - if not pos then pos = buffer.current_pos end + if not assert_type(pos, 'number/nil', 1) then pos = buffer.current_pos end local s = buffer:word_start_position(pos, true) local e = buffer:word_end_position(pos, true) local symbol = buffer:text_range(s, e) @@ -710,8 +714,7 @@ function M.show_documentation(pos, case_insensitive) return string.format('[%s%s]', ch:upper(), ch:lower()) end) end - for i = 1, #M.api_files[lang] do - local file = M.api_files[lang][i] + for _, file in ipairs(M.api_files[lang]) do if type(file) == 'function' then file = file() end if file and lfs.attributes(file) then for line in io.lines(file) do diff --git a/modules/textadept/file_types.lua b/modules/textadept/file_types.lua index df35f861..f0ce5bdb 100644 --- a/modules/textadept/file_types.lua +++ b/modules/textadept/file_types.lua @@ -65,6 +65,7 @@ local SETLEXERLANGUAGE = _SCINTILLA.properties.lexer_language[2] local GETERROR = _SCINTILLA.properties.status[1] -- LuaDoc is in core/.buffer.luadoc. local function set_lexer(buffer, lang) + assert_type(lang, 'string/nil', 2) if not lang then lang = detect_language(buffer) end buffer:private_lexer_call(SETDIRECTPOINTER, buffer.direct_pointer) buffer:private_lexer_call(SETLEXERLANGUAGE, lang) diff --git a/modules/textadept/find.lua b/modules/textadept/find.lua index 70a3f7d7..48601ee3 100644 --- a/modules/textadept/find.lua +++ b/modules/textadept/find.lua @@ -124,6 +124,7 @@ end -- internally, and should not be set otherwise. -- @return position of the found text or `-1` local function find(text, next, flags, no_wrap, wrapped) + -- Note: cannot use assert_type(), as event errors are handled silently. if text == '' then return end if not flags then flags = get_flags() end if flags >= 0x1000000 then M.find_in_files() return end -- not performed here @@ -193,7 +194,7 @@ end -- caret position instead of the position where the incremental search began. -- Only the `match_case` find option is recognized. Normal command entry -- functionality is unavailable until the search is finished or by pressing --- `Esc` (`⎋` on Mac OSX | `Esc` in curses). +-- `Esc`. -- @param text The text to incrementally search for, or `nil` to begin an -- incremental search. -- @param next Flag indicating whether or not the search direction is forward. @@ -201,6 +202,7 @@ end -- the caret position. The default value is `false`. -- @name find_incremental function M.find_incremental(text, next, anchor) + assert_type(text, 'string/nil', 1) if text then find_incremental(text, next, anchor) return end incremental_start = buffer.current_pos ui.command_entry:set_text('') @@ -251,17 +253,20 @@ end}) -- @see find_in_files_filters -- @name find_in_files function M.find_in_files(dir, filter) - dir = dir or ui.dialogs.fileselect{ - title = _L['Select Directory'], select_only_directories = true, - with_directory = io.get_project_root() or - (buffer.filename or ''):match('^.+[/\\]') or - lfs.currentdir() - } - if not dir then return end + if not assert_type(dir, 'string/nil', 1) then + dir = ui.dialogs.fileselect{ + title = _L['Select Directory'], select_only_directories = true, + with_directory = io.get_project_root() or + (buffer.filename or ''):match('^.+[/\\]') or + lfs.currentdir() + } + if not dir then return end + end if buffer._type ~= _L['[Files Found Buffer]'] then preferred_view = view end ui.silent_print = false - ui._print(_L['[Files Found Buffer]'], _L['Find:']..' '..M.find_entry_text) + ui._print(_L['[Files Found Buffer]'], + _L['Find:']:gsub('_', '')..' '..M.find_entry_text) buffer.indicator_current = M.INDIC_FIND local ff_buffer = buffer @@ -273,8 +278,8 @@ function M.find_in_files(dir, filter) buffer:clear_all() buffer:empty_undo_buffer() local f = io.open(filename, 'rb') - while f:read(0) do buffer:append_text(f:read(1048576)) end - --buffer:set_text(f:read('a')) + while f:read(0) do buffer:append_text(f:read(1048576)) end -- TODO: why? + --buffer:set_text(f:read('a')) -- TODO: why not? f:close() local binary = nil -- determine lazily for performance reasons buffer:target_whole_document() @@ -402,7 +407,7 @@ function M.goto_file_found(line_num, next) if ff_view then ui.goto_view(ff_view) else view:goto_buffer(ff_buf) end -- If no line was given, find the next search result. - if not line_num and next ~= nil then + if not assert_type(line_num, 'number/nil', 1) and next ~= nil then if next then buffer:line_end() else buffer:home() end buffer:search_anchor() local f = buffer['search_'..(next and 'next' or 'prev')] diff --git a/modules/textadept/macros.lua b/modules/textadept/macros.lua index 123c0392..a965b254 100644 --- a/modules/textadept/macros.lua +++ b/modules/textadept/macros.lua @@ -87,10 +87,12 @@ end -- @name save function M.save(filename) if recording or not macro then return end - filename = filename or ui.dialogs.filesave{ - title = _L['Save Macro'], with_directory = _USERHOME, with_extension = 'm' - } - if not filename then return end + if not assert_type(filename, 'string/nil', 1) then + filename = ui.dialogs.filesave{ + title = _L['Save Macro'], with_directory = _USERHOME, with_extension = 'm' + } + if not filename then return end + end local f = assert(io.open(filename, 'w')) f:write('return {\n') for i = 1, #macro do @@ -113,10 +115,13 @@ end -- @name load function M.load(filename) if recording then return end - filename = filename or ui.dialogs.fileselect{ - title = _L['Load Macro'], with_directory = _USERHOME, with_extension = 'm' - } - if filename then macro = assert(loadfile(filename, 't', {}))() end + if not assert_type(filename, 'string/nil', 1) then + filename = ui.dialogs.fileselect{ + title = _L['Load Macro'], with_directory = _USERHOME, with_extension = 'm' + } + if not filename then return end + end + macro = assert(loadfile(filename, 't', {}))() end return M diff --git a/modules/textadept/menu.lua b/modules/textadept/menu.lua index 25341bbe..9684516b 100644 --- a/modules/textadept/menu.lua +++ b/modules/textadept/menu.lua @@ -22,9 +22,7 @@ local menu_buffer_functions = { 'select_all', 'upper_case', 'lower_case', 'move_selected_lines_up', 'move_selected_lines_down', 'zoom_in', 'zoom_out' } -for i = 1, #menu_buffer_functions do - buffer[menu_buffer_functions[i]] = buffer[menu_buffer_functions[i]] -end +for _, f in ipairs(menu_buffer_functions) do buffer[f] = buffer[f] end -- Commonly used functions in menu commands. local sel_enc = textadept.editing.select_enclosed diff --git a/modules/textadept/run.lua b/modules/textadept/run.lua index 52471ed7..f23babd7 100644 --- a/modules/textadept/run.lua +++ b/modules/textadept/run.lua @@ -169,7 +169,7 @@ local function compile_or_run(filename, commands) -- Replace macros in the command. local dirname, basename = '', filename if filename:find('[/\\]') then - dirname, basename = filename:match('^(.+[/\\])([^/\\]+)$') + dirname, basename = filename:match('^(.+)[/\\]([^/\\]+)$') end local basename_no_ext = basename:match('^(.+)%.') command = command:gsub('%%([pdfe])', { @@ -182,7 +182,7 @@ local function compile_or_run(filename, commands) local ext_or_lexer = commands[ext] and ext or lexer local function emit(output) events.emit(event, output, ext_or_lexer) end -- Run the command. - cwd = working_dir or dirname + cwd = (working_dir or dirname):gsub('[/\\]$', '') if cwd ~= dirname then events.emit(event, '> cd '..cwd..'\n') end events.emit(event, '> '..command:iconv('UTF-8', _CHARSET)..'\n') proc = assert(os.spawn(command, cwd, emit, emit, function(status) @@ -219,8 +219,9 @@ M.compile_commands = {actionscript='mxmlc "%f"',ada='gnatmake "%f"',ansi_c='gcc -- @see _G.events -- @name compile function M.compile(filename) - if not filename and not buffer.filename then return end - compile_or_run(filename or buffer.filename, M.compile_commands) + if assert_type(filename, 'string/nil', 1) or buffer.filename then + compile_or_run(filename or buffer.filename, M.compile_commands) + end end events.connect(events.COMPILE_OUTPUT, print_output) @@ -252,8 +253,9 @@ M.run_commands = {actionscript=WIN32 and 'start "" "%e.swf"' or OSX and 'open "f -- @see _G.events -- @name run function M.run(filename) - if not filename and not buffer.filename then return end - compile_or_run(filename or buffer.filename, M.run_commands) + if assert_type(filename, 'string/nil', 1) or buffer.filename then + compile_or_run(filename or buffer.filename, M.run_commands) + end end events.connect(events.RUN_OUTPUT, print_output) @@ -280,8 +282,10 @@ M.build_commands = {--[[Ant]]['build.xml']='ant',--[[Dockerfile]]Dockerfile='doc -- @see _G.events -- @name build function M.build(root_directory) - if not root_directory then root_directory = io.get_project_root() end - if not root_directory then return end + if not assert_type(root_directory, 'string/nil', 1) then + root_directory = io.get_project_root() + if not root_directory then return end + end for i = 1, #_BUFFERS do _BUFFERS[i]:annotation_clear_all() end -- Determine command. local command = M.build_commands[root_directory] @@ -304,7 +308,7 @@ function M.build(root_directory) preferred_view = view local function emit(output) events.emit(events.BUILD_OUTPUT, output) end -- Run the command. - cwd = working_dir or root_directory + cwd = (working_dir or root_directory):gsub('[/\\]$', '') events.emit(events.BUILD_OUTPUT, '> cd '..cwd..'\n') events.emit(events.BUILD_OUTPUT, '> '..command:iconv('UTF-8', _CHARSET)..'\n') proc = assert(os.spawn(command, cwd, emit, emit, function(status) @@ -374,7 +378,7 @@ function M.goto_error(line, next) if msg_view then ui.goto_view(msg_view) else view:goto_buffer(msg_buf) end -- If no line was given, find the next warning or error marker. - if not line and next ~= nil then + if not assert_type(line, 'number/nil', 1) and next ~= nil then local f = buffer['marker_'..(next and 'next' or 'previous')] line = buffer:line_from_position(buffer.current_pos) local wrapped = false diff --git a/modules/textadept/session.lua b/modules/textadept/session.lua index ef85c9a2..972f3cbb 100644 --- a/modules/textadept/session.lua +++ b/modules/textadept/session.lua @@ -32,10 +32,12 @@ local session_file = _USERHOME..(not CURSES and '/session' or '/session_term') -- @name load function M.load(filename) local dir, name = session_file:match('^(.-[/\\]?)([^/\\]+)$') - filename = filename or ui.dialogs.fileselect{ - title = _L['Load Session'], with_directory = dir, with_file = name - } - if not filename then return end + if not assert_type(filename, 'string/nil', 1) then + filename = ui.dialogs.fileselect{ + title = _L['Load Session'], with_directory = dir, with_file = name + } + if not filename then return end + end local not_found = {} local f = io.open(filename, 'rb') if not f or not io.close_all_buffers() then return false end @@ -121,18 +123,19 @@ events.connect(events.ARG_NONE, load_default_session) -- @name save function M.save(filename) local dir, name = session_file:match('^(.-[/\\]?)([^/\\]+)$') - filename = filename or ui.dialogs.filesave{ - title = _L['Save Session'], with_directory = dir, - with_file = name:iconv('UTF-8', _CHARSET) - } - if not filename then return end + if not assert_type(filename, 'string/nil', 1) then + filename = ui.dialogs.filesave{ + title = _L['Save Session'], with_directory = dir, + with_file = name:iconv('UTF-8', _CHARSET) + } + if not filename then return end + end local session = {} local buffer_line = 'buffer: %d %d %d %s' -- anchor, cursor, line, filename local split_line = '%ssplit%d: %s %d' -- level, number, type, size local view_line = '%sview%d: %d' -- level, number, doc index -- Write out opened buffers. - for i = 1, #_BUFFERS do - local buffer = _BUFFERS[i] + for _, buffer in ipairs(_BUFFERS) do local filename = buffer.filename or buffer._type if filename then local current = buffer == view.buffer diff --git a/modules/textadept/snippets.lua b/modules/textadept/snippets.lua index 7bdfab7e..e59bc223 100644 --- a/modules/textadept/snippets.lua +++ b/modules/textadept/snippets.lua @@ -309,12 +309,6 @@ local function new_snippet(text, trigger) end placeholder.position = #snapshot.text if placeholder.default then - -- Execute any embedded code first. - placeholder.default = placeholder.default:gsub('%%%b<>', function(s) - return snippet:execute_code{lua_code = s:sub(3, -2)} - end):gsub('%%%b[]', function(s) - return snippet:execute_code{sh_code = s:sub(3, -2)} - end) if placeholder.default:find('%%%d+') then -- Parses out embedded placeholders, adding them to this snippet's -- snapshot. @@ -595,8 +589,11 @@ snippet_mt = { -- @name insert function M.insert(text) local trigger - if not text then trigger, text = find_snippet(trigger) end - if type(text) == 'function' and not trigger:find('^_') then text = text() end + if not assert_type(text, 'string/nil', 1) then + trigger, text = find_snippet(trigger) + if type(text) == 'function' and not trigger:find('^_') then text = text() end + assert_type(text, 'string/nil', trigger or '?') + end local snippet = type(text) == 'string' and new_snippet(text, trigger) or snippet_stack[#snippet_stack] if snippet then snippet:next() else return false end @@ -633,8 +630,7 @@ function M.select() all_snippets[#all_snippets + 1], all_snippets[trigger] = trigger, snippet end table.sort(all_snippets) - for i = 1, #all_snippets do - local trigger = all_snippets[i] + for _, trigger in ipairs(all_snippets) do items[#items + 1], items[#items + 2] = trigger, all_snippets[trigger] end local button, i = ui.dialogs.filteredlist{ |