console.lua: cycle through completions

This commit is contained in:
Guido Cella 2023-11-25 18:30:49 +01:00 committed by Dudemanguy
parent c16f868dd7
commit f886eb5678
2 changed files with 60 additions and 19 deletions

View File

@ -86,7 +86,11 @@ Shift+INSERT
Paste text (uses the primary selection on X11 and Wayland).
TAB and Ctrl+i
Complete the command or property name at the cursor.
Complete the text at the cursor. The first press inserts the longest common
prefix of the completions, and subsequent presses cycle through them.
Shift+TAB
Cycle through the completions backwards.
Ctrl+l
Clear all log messages from the console.

View File

@ -72,6 +72,7 @@ local styles = {
error = '{\\1c&H7a77f2&}',
fatal = '{\\1c&H5791f9&\\b1}',
suggestion = '{\\1c&Hcc99cc&}',
selected_suggestion = '{\\1c&H2fbdfa&\\b1}',
}
local repl_active = false
@ -82,10 +83,13 @@ local cursor = 1
local history = {}
local history_pos = 1
local log_buffer = {}
local suggestion_buffer = {}
local key_bindings = {}
local global_margins = { t = 0, b = 0 }
local suggestion_buffer = {}
local selected_suggestion_index
local completion_start_position
local completion_append
local file_commands = {}
local path_separator = platform == 'windows' and '\\' or '/'
@ -281,7 +285,9 @@ function format_table(list, width_max, rows_max)
local spaces = math.floor((width_max - width_total) / (column_count - 1))
spaces = math.max(spaces_min, math.min(spaces_max, spaces))
local spacing = column_count > 1 and string.format('%' .. spaces .. 's', ' ') or ''
local spacing = column_count > 1
and ass_escape(string.format('%' .. spaces .. 's', ' '))
or ''
local rows = {}
for row = 1, row_count do
@ -292,12 +298,17 @@ function format_table(list, width_max, rows_max)
-- more then 99 leads to 'invalid format (width or precision too long)'
local format_string = column == column_count and '%s'
or '%-' .. math.min(column_widths[column], 99) .. 's'
columns[column] = string.format(format_string, list[i])
columns[column] = ass_escape(string.format(format_string, list[i]))
if i == selected_suggestion_index then
columns[column] = styles.selected_suggestion .. columns[column]
.. '{\\b0}'.. styles.suggestion
end
end
-- first row is at the bottom
rows[row_count - row + 1] = table.concat(columns, spacing)
end
return table.concat(rows, '\n'), row_count
return table.concat(rows, ass_escape('\n')), row_count
end
local function print_to_terminal()
@ -390,7 +401,7 @@ function update()
local width_max = math.ceil(screenx / opts.font_size * get_font_hw_ratio())
local suggestions, rows = format_table(suggestion_buffer, width_max, lines_max)
local suggestion_ass = style .. styles.suggestion .. ass_escape(suggestions)
local suggestion_ass = style .. styles.suggestion .. suggestions
local log_ass = ''
local log_messages = #log_buffer
@ -943,8 +954,29 @@ function max_overlap_length(s1, s2)
return 0
end
local function cycle_through_suggestions(backwards)
selected_suggestion_index = selected_suggestion_index + (backwards and -1 or 1)
if selected_suggestion_index > #suggestion_buffer then
selected_suggestion_index = 1
elseif selected_suggestion_index < 1 then
selected_suggestion_index = #suggestion_buffer
end
local before_cur = line:sub(1, completion_start_position - 1) ..
suggestion_buffer[selected_suggestion_index] .. completion_append
line = before_cur .. line:sub(cursor)
cursor = before_cur:len() + 1
update()
end
-- Complete the option or property at the cursor (TAB)
function complete()
function complete(backwards)
if #suggestion_buffer > 0 then
cycle_through_suggestions(backwards)
return
end
local before_cur = line:sub(1, cursor - 1)
local after_cur = line:sub(cursor)
@ -952,45 +984,49 @@ function complete()
for _, completer in ipairs(build_completers()) do
-- Completer patterns should return the start of the word to be
-- completed as the first capture.
local s, s2 = before_cur:match(completer.pattern)
if not s then
local s2
completion_start_position, s2 = before_cur:match(completer.pattern)
if not completion_start_position then
-- Multiple input commands can be separated by semicolons, so all
-- completions that are anchored at the start of the string with
-- '^' can start from a semicolon as well. Replace ^ with ; and try
-- to match again.
s, s2 = before_cur:match(completer.pattern:gsub('^^', ';'))
completion_start_position, s2 =
before_cur:match(completer.pattern:gsub('^^', ';'))
end
if s then
if completion_start_position then
local hint
if s2 then
hint = s
s = s2
hint = completion_start_position
completion_start_position = s2
end
-- If the completer's pattern found a word, check the completer's
-- list for possible completions
local part = before_cur:sub(s)
local part = before_cur:sub(completion_start_position)
local completions, prefix = complete_match(part, completer.list(hint))
if #completions > 0 then
-- If there was only one full match from the list, add
-- completer.append to the final string. This is normally a
-- space or a quotation mark followed by a space.
local after_cur_index = 1
completion_append = completer.append or ''
if #completions == 1 then
local append = completer.append or ''
prefix = prefix .. append
prefix = prefix .. completion_append
-- calculate offset into after_cur
local prefix_len = common_prefix_length(append, after_cur)
local overlap_size = max_overlap_length(append, after_cur)
local prefix_len = common_prefix_length(completion_append, after_cur)
local overlap_size = max_overlap_length(completion_append, after_cur)
after_cur_index = math.max(prefix_len, overlap_size) + 1
else
table.sort(completions)
suggestion_buffer = completions
selected_suggestion_index = 0
end
-- Insert the completion and update
before_cur = before_cur:sub(1, s - 1) .. prefix
before_cur = before_cur:sub(1, completion_start_position - 1) ..
prefix
cursor = before_cur:len() + 1
line = before_cur .. after_cur:sub(after_cur_index)
update()
@ -1157,6 +1193,7 @@ function get_bindings()
{ 'alt+f', next_word },
{ 'tab', complete },
{ 'ctrl+i', complete },
{ 'shift+tab', function() complete(true) end },
{ 'ctrl+a', go_home },
{ 'home', go_home },
{ 'ctrl+e', go_end },