diff options
author | 2014-05-23 23:32:24 -0400 | |
---|---|---|
committer | 2014-05-23 23:32:24 -0400 | |
commit | 59cc2a760aab8a2eb279d79b75a2a7e020e10801 (patch) | |
tree | 8bfacb6aa1f6d5ac7d2a1e58ae9fd446d8f05264 /modules | |
parent | 113137d4fe3f71fa13f2d3387bb2f8801134de26 (diff) | |
download | textadept-59cc2a760aab8a2eb279d79b75a2a7e020e10801.tar.gz textadept-59cc2a760aab8a2eb279d79b75a2a7e020e10801.zip |
Renamed `textadept.editing.autocomplete_word()` and added `AUTOCOMPLETE_ALL`.
The new `textadept.editing.autocomplete()` is a generic function for a new
autocompletion framework that will replace Adeptsense. The framework involves
individual autocompletion functions, such as one for autocompleting words.
Also added new `AUTOCOMPLETE_ALL` setting for searching all buffers for word
completions.
Diffstat (limited to 'modules')
-rw-r--r-- | modules/textadept/editing.lua | 126 | ||||
-rw-r--r-- | modules/textadept/keys.lua | 4 | ||||
-rw-r--r-- | modules/textadept/menu.lua | 2 |
3 files changed, 70 insertions, 62 deletions
diff --git a/modules/textadept/editing.lua b/modules/textadept/editing.lua index 1619456d..81ad1d34 100644 --- a/modules/textadept/editing.lua +++ b/modules/textadept/editing.lua @@ -27,6 +27,10 @@ local M = {} -- @field STRIP_TRAILING_SPACES (bool) -- Strip trailing whitespace before saving files. -- The default value is `false`. +-- @field AUTOCOMPLETE_ALL (bool) +-- Autocomplete the current word using words from all open buffers. +-- If `true`, performance may be slow when many buffers are open. +-- The default value is `false`. -- @field INDIC_BRACEMATCH (number) -- The matching brace highlight indicator number. -- @field INDIC_HIGHLIGHT (number) @@ -38,6 +42,7 @@ M.HIGHLIGHT_BRACES = true M.TYPEOVER_CHARS = true M.AUTOINDENT = true M.STRIP_TRAILING_SPACES = false +M.AUTOCOMPLETE_ALL = false M.INDIC_BRACEMATCH = _SCINTILLA.next_indic_number() M.INDIC_HIGHLIGHT = _SCINTILLA.next_indic_number() @@ -86,6 +91,17 @@ M.braces = {[40] = 1, [41] = 1, [91] = 1, [93] = 1, [123] = 1, [125] = 1} -- @see TYPEOVER_CHARS M.typeover_chars = {[41] = 1, [93] = 1, [125] = 1, [39] = 1, [34] = 1} +--- +-- Map of autocompleter names to autocompletion functions. +-- Autocompletion functions must return two values: the number of characters +-- behind the caret that are used as the prefix of the entity to autocomplete, +-- and a list of completions to show. Autocompletion lists are automatically +-- sorted. +-- @class table +-- @name autocompleters +-- @see autocomplete +M.autocompleters = {} + -- Matches characters specified in char_matches. events.connect(events.CHAR_ADDED, function(c) if not M.AUTOPAIR then return end @@ -202,65 +218,6 @@ function M.match_brace(select) end --- --- Displays an autocompletion list for the word behind the caret, returning --- `true` if completions were found. --- The displayed list is built from existing words in the buffer and the set of --- words in string *words*. --- @param words Optional list of words considered to be in the buffer, --- even if they are not. Words may contain [registered images][]. --- --- [registered images]: buffer.html#register_image --- @return `true` if there were completions to show; `false` otherwise. --- @see buffer.word_chars --- @name autocomplete_word -function M.autocomplete_word(words) - local buffer = buffer - local pos, length = buffer.current_pos, buffer.length - local completions, c_list = {}, {} - 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(words or {}) do - if word:match('^'..root) then - c_list[#c_list + 1], completions[word:match('^(.-)%??%d*$')] = word, true - end - end - local patt = '^['..buffer.word_chars..']+' - buffer.target_start, buffer.target_end = 0, buffer.length - buffer.search_flags = buffer.FIND_WORDSTART - if not buffer.auto_c_ignore_case then - buffer.search_flags = buffer.search_flags + buffer.FIND_MATCHCASE - end - local match_pos = buffer:search_in_target(root) - while match_pos ~= -1 do - local s, e = buffer_text:find(patt, match_pos + 1) - local match = buffer_text:sub(s, e) - if not completions[match] and #match > #root then - c_list[#c_list + 1], completions[match] = match, true - end - buffer.target_start, buffer.target_end = match_pos + 1, buffer.length - match_pos = buffer:search_in_target(root) - end - if not buffer.auto_c_ignore_case then - table.sort(c_list) - else - table.sort(c_list, function(a, b) return a:upper() < b:upper() end) - end - if #c_list > 0 then - if not buffer.auto_c_choose_single or #c_list ~= 1 then - buffer.auto_c_order = 0 -- pre-sorted - buffer:auto_c_show(#root, table.concat(c_list, ' ')) - else - -- Scintilla does not emit AUTO_C_SELECTION in this case. This is - -- necessary for autocompletion with multiple selections. - local text = c_list[1]:match('^(.-)%??%d*$') - events.emit(events.AUTO_C_SELECTION, text, pos - #root) - end - return true - end -end - ---- -- Comments or uncomments the selected lines based on the current language. -- As long as any part of a line is selected, the entire line is eligible for -- commenting/uncommenting. @@ -562,4 +519,55 @@ function M.filter_through(command) os.remove(tmpfile) end +--- +-- Displays an autocompletion list provided by the autocompleter function +-- associated with string *name*, and returns `true` if completions were found. +-- @param name The name of an autocompleter function in the `autocompleters` +-- table to use for providing autocompletions. +-- @name autocomplete +-- @see autocompleters +function M.autocomplete(name) + if not M.autocompleters[name] then return end + local len_entered, list = M.autocompleters[name]() + if not len_entered or not list or #list == 0 then return end + if not buffer.auto_c_choose_single or #list ~= 1 then + buffer.auto_c_order = buffer.ORDER_PERFORMSORT + buffer:auto_c_show(len_entered, table.concat(list, ' ')) + else + -- Scintilla does not emit AUTO_C_SELECTION in this case. This is + -- necessary for autocompletion with multiple selections. + local text = list[1]:match('^(.-)%??%d*$') + events.emit(events.AUTO_C_SELECTION, text, buffer.current_pos - len_entered) + end + return true +end + +-- Returns for the word behind the caret a list of completions constructed from +-- the current buffer or all open buffers (depending on `M.AUTOCOMPLETE_ALL`). +-- @see buffer.word_chars +-- @see autocomplete +M.autocompleters.word = function() + local list, ignore_case = {}, buffer.auto_c_ignore_case + local line, pos = buffer:get_cur_line() + local word_char = '['..buffer.word_chars:gsub('(%p)', '%%%1')..']' + local word = line:sub(1, pos):match(word_char..'*$') + if word == '' then return nil end + if ignore_case then word = word:lower() end + for i = 1, #_BUFFERS do + if _BUFFERS[i] == buffer or M.AUTOCOMPLETE_ALL then + local text = _BUFFERS[i]:get_text() + -- Frontier pattern (%f) is too slow, so check prior char after a match. + local patt = '()('..word:gsub('(%p)', '%%%1')..word_char..'+)' + local nonword_char = '^[^'..buffer.word_chars:gsub('(%p)', '%%%1')..']' + for i, word in (not ignore_case and text or text:lower()):gmatch(patt) do + if (i == 1 or text:find(nonword_char, i - 1)) and not list[word] then + list[#list + 1], list[word] = word, true + end + end + end + end + if #list == 0 then return nil end + return #word, list +end + return M diff --git a/modules/textadept/keys.lua b/modules/textadept/keys.lua index e8315246..781d8860 100644 --- a/modules/textadept/keys.lua +++ b/modules/textadept/keys.lua @@ -261,7 +261,7 @@ M.utils = { events.emit(events.UPDATE_UI) -- for updating statusbar end, set_encoding = function(encoding) - io.set_buffer_encoding(encoding) + buffer:set_encoding(encoding) events.emit(events.UPDATE_UI) -- for updating statusbar end, set_eol_mode = function(mode) @@ -388,7 +388,7 @@ keys[not OSX and (not CURSES and 'adel' or 'mdel') keys[not OSX and not CURSES and 'ca' or 'ma'] = buffer.select_all keys[not CURSES and 'cm' or 'mm'] = editing.match_brace keys[not OSX and (not CURSES and 'c\n' or 'cmj') - or 'cesc'] = editing.autocomplete_word + or 'cesc'] = {editing.autocomplete, 'word'} if CURSES and WIN32 then keys['c\r'] = keys['cmj'] end if not CURSES then keys[not OSX and 'caH' or 'mH'] = editing.highlight_word diff --git a/modules/textadept/menu.lua b/modules/textadept/menu.lua index c6d5d5af..6dc3bc1b 100644 --- a/modules/textadept/menu.lua +++ b/modules/textadept/menu.lua @@ -47,7 +47,7 @@ local menubar = { {_L['Select _All'], buffer.select_all}, SEPARATOR, {_L['_Match Brace'], editing.match_brace}, - {_L['Complete _Word'], editing.autocomplete_word}, + {_L['Complete _Word'], {editing.autocomplete, 'word'}}, {_L['_Highlight Word'], editing.highlight_word}, {_L['Toggle _Block Comment'], editing.block_comment}, {_L['T_ranspose Characters'], editing.transpose_chars}, |