Improve `CommandView` and `autocomplete` scroll behavior (#1732)
* Make command palette item scrolling more natural Also add a config option for the maximum number of visible entries in the command palette. * Make `autocomplete` item scrolling more natural
This commit is contained in:
parent
ece51922a3
commit
27ae51762b
|
@ -1,5 +1,6 @@
|
||||||
local core = require "core"
|
local core = require "core"
|
||||||
local common = require "core.common"
|
local common = require "core.common"
|
||||||
|
local config = require "core.config"
|
||||||
local style = require "core.style"
|
local style = require "core.style"
|
||||||
local Doc = require "core.doc"
|
local Doc = require "core.doc"
|
||||||
local DocView = require "core.docview"
|
local DocView = require "core.docview"
|
||||||
|
@ -20,8 +21,6 @@ local CommandView = DocView:extend()
|
||||||
|
|
||||||
CommandView.context = "application"
|
CommandView.context = "application"
|
||||||
|
|
||||||
local max_suggestions = 10
|
|
||||||
|
|
||||||
local noop = function() end
|
local noop = function() end
|
||||||
|
|
||||||
---@class core.commandview.state
|
---@class core.commandview.state
|
||||||
|
@ -50,6 +49,7 @@ local default_state = {
|
||||||
function CommandView:new()
|
function CommandView:new()
|
||||||
CommandView.super.new(self, SingleLineDoc())
|
CommandView.super.new(self, SingleLineDoc())
|
||||||
self.suggestion_idx = 1
|
self.suggestion_idx = 1
|
||||||
|
self.suggestions_offset = 1
|
||||||
self.suggestions = {}
|
self.suggestions = {}
|
||||||
self.suggestions_height = 0
|
self.suggestions_height = 0
|
||||||
self.last_change_id = 0
|
self.last_change_id = 0
|
||||||
|
@ -128,6 +128,24 @@ function CommandView:move_suggestion_idx(dir)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function get_suggestions_offset()
|
||||||
|
local max_visible = math.min(config.max_visible_commands, #self.suggestions)
|
||||||
|
if dir > 0 then
|
||||||
|
if self.suggestions_offset + max_visible < self.suggestion_idx + 1 then
|
||||||
|
return self.suggestion_idx - max_visible + 1
|
||||||
|
elseif self.suggestions_offset > self.suggestion_idx then
|
||||||
|
return self.suggestion_idx
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if self.suggestions_offset > self.suggestion_idx then
|
||||||
|
return self.suggestion_idx
|
||||||
|
elseif self.suggestions_offset + max_visible < self.suggestion_idx + 1 then
|
||||||
|
return self.suggestion_idx - max_visible + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self.suggestions_offset
|
||||||
|
end
|
||||||
|
|
||||||
if self.state.show_suggestions then
|
if self.state.show_suggestions then
|
||||||
local n = self.suggestion_idx + dir
|
local n = self.suggestion_idx + dir
|
||||||
self.suggestion_idx = overflow_suggestion_idx(n, #self.suggestions)
|
self.suggestion_idx = overflow_suggestion_idx(n, #self.suggestions)
|
||||||
|
@ -151,6 +169,8 @@ function CommandView:move_suggestion_idx(dir)
|
||||||
self.last_change_id = self.doc:get_change_id()
|
self.last_change_id = self.doc:get_change_id()
|
||||||
self.state.suggest(self:get_text())
|
self.state.suggest(self:get_text())
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.suggestions_offset = get_suggestions_offset()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -261,6 +281,7 @@ function CommandView:update_suggestions()
|
||||||
end
|
end
|
||||||
self.suggestions = res
|
self.suggestions = res
|
||||||
self.suggestion_idx = 1
|
self.suggestion_idx = 1
|
||||||
|
self.suggestions_offset = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -300,11 +321,11 @@ function CommandView:update()
|
||||||
|
|
||||||
-- update suggestions box height
|
-- update suggestions box height
|
||||||
local lh = self:get_suggestion_line_height()
|
local lh = self:get_suggestion_line_height()
|
||||||
local dest = self.state.show_suggestions and math.min(#self.suggestions, max_suggestions) * lh or 0
|
local dest = self.state.show_suggestions and math.min(#self.suggestions, config.max_visible_commands) * lh or 0
|
||||||
self:move_towards("suggestions_height", dest, nil, "commandview")
|
self:move_towards("suggestions_height", dest, nil, "commandview")
|
||||||
|
|
||||||
-- update suggestion cursor offset
|
-- update suggestion cursor offset
|
||||||
local dest = math.min(self.suggestion_idx, max_suggestions) * self:get_suggestion_line_height()
|
local dest = (self.suggestion_idx - self.suggestions_offset + 1) * self:get_suggestion_line_height()
|
||||||
self:move_towards("selection_offset", dest, nil, "commandview")
|
self:move_towards("selection_offset", dest, nil, "commandview")
|
||||||
|
|
||||||
-- update size based on whether this is the active_view
|
-- update size based on whether this is the active_view
|
||||||
|
@ -340,6 +361,7 @@ local function draw_suggestions_box(self)
|
||||||
local h = math.ceil(self.suggestions_height)
|
local h = math.ceil(self.suggestions_height)
|
||||||
local rx, ry, rw, rh = self.position.x, self.position.y - h - dh, self.size.x, h
|
local rx, ry, rw, rh = self.position.x, self.position.y - h - dh, self.size.x, h
|
||||||
|
|
||||||
|
core.push_clip_rect(rx, ry, rw, rh)
|
||||||
-- draw suggestions background
|
-- draw suggestions background
|
||||||
if #self.suggestions > 0 then
|
if #self.suggestions > 0 then
|
||||||
renderer.draw_rect(rx, ry, rw, rh, style.background3)
|
renderer.draw_rect(rx, ry, rw, rh, style.background3)
|
||||||
|
@ -349,14 +371,12 @@ local function draw_suggestions_box(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- draw suggestion text
|
-- draw suggestion text
|
||||||
local offset = math.max(self.suggestion_idx - max_suggestions, 0)
|
local first = math.max(self.suggestions_offset, 1)
|
||||||
local last = math.min(offset + max_suggestions, #self.suggestions)
|
local last = math.min(self.suggestions_offset + config.max_visible_commands, #self.suggestions)
|
||||||
core.push_clip_rect(rx, ry, rw, rh)
|
|
||||||
local first = 1 + offset
|
|
||||||
for i=first, last do
|
for i=first, last do
|
||||||
local item = self.suggestions[i]
|
local item = self.suggestions[i]
|
||||||
local color = (i == self.suggestion_idx) and style.accent or style.text
|
local color = (i == self.suggestion_idx) and style.accent or style.text
|
||||||
local y = self.position.y - (i - offset) * lh - dh
|
local y = self.position.y - (i - first + 1) * lh - dh
|
||||||
common.draw_text(self:get_font(), color, item.text, nil, x, y, 0, lh)
|
common.draw_text(self:get_font(), color, item.text, nil, x, y, 0, lh)
|
||||||
|
|
||||||
if item.info then
|
if item.info then
|
||||||
|
|
|
@ -112,6 +112,12 @@ config.max_undos = 10000
|
||||||
---@type number
|
---@type number
|
||||||
config.max_tabs = 8
|
config.max_tabs = 8
|
||||||
|
|
||||||
|
---The maximum number of entries shown at a time in the command palette.
|
||||||
|
---
|
||||||
|
---The default is 10.
|
||||||
|
---@type integer
|
||||||
|
config.max_visible_commands = 10
|
||||||
|
|
||||||
---Shows/hides the tab bar when there is only one tab open.
|
---Shows/hides the tab bar when there is only one tab open.
|
||||||
---
|
---
|
||||||
---The tab bar is always shown by default.
|
---The tab bar is always shown by default.
|
||||||
|
|
|
@ -282,12 +282,14 @@ end)
|
||||||
|
|
||||||
|
|
||||||
local partial = ""
|
local partial = ""
|
||||||
|
local suggestions_offset = 1
|
||||||
local suggestions_idx = 1
|
local suggestions_idx = 1
|
||||||
local suggestions = {}
|
local suggestions = {}
|
||||||
local last_line, last_col
|
local last_line, last_col
|
||||||
|
|
||||||
|
|
||||||
local function reset_suggestions()
|
local function reset_suggestions()
|
||||||
|
suggestions_offset = 1
|
||||||
suggestions_idx = 1
|
suggestions_idx = 1
|
||||||
suggestions = {}
|
suggestions = {}
|
||||||
|
|
||||||
|
@ -369,6 +371,7 @@ local function update_suggestions()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
suggestions_idx = 1
|
suggestions_idx = 1
|
||||||
|
suggestions_offset = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_partial_symbol()
|
local function get_partial_symbol()
|
||||||
|
@ -581,8 +584,8 @@ local function draw_suggestions_box(av)
|
||||||
local font = av:get_font()
|
local font = av:get_font()
|
||||||
local lh = font:get_height() + style.padding.y
|
local lh = font:get_height() + style.padding.y
|
||||||
local y = ry + style.padding.y / 2
|
local y = ry + style.padding.y / 2
|
||||||
local show_count = #suggestions <= ah and #suggestions or ah
|
local show_count = math.min(#suggestions, ah)
|
||||||
local start_index = suggestions_idx > ah and (suggestions_idx-(ah-1)) or 1
|
local start_index = suggestions_offset
|
||||||
local hide_info = config.plugins.autocomplete.hide_info
|
local hide_info = config.plugins.autocomplete.hide_info
|
||||||
|
|
||||||
for i=start_index, start_index+show_count-1, 1 do
|
for i=start_index, start_index+show_count-1, 1 do
|
||||||
|
@ -848,7 +851,7 @@ command.add(predicate, {
|
||||||
local current_partial = get_partial_symbol()
|
local current_partial = get_partial_symbol()
|
||||||
local sz = #current_partial
|
local sz = #current_partial
|
||||||
|
|
||||||
for idx, line1, col1, line2, col2 in doc:get_selections(true) do
|
for _, line1, col1, line2, _ in doc:get_selections(true) do
|
||||||
local n = col1 - 1
|
local n = col1 - 1
|
||||||
local line = doc.lines[line1]
|
local line = doc.lines[line1]
|
||||||
for i = 1, sz + 1 do
|
for i = 1, sz + 1 do
|
||||||
|
@ -869,10 +872,24 @@ command.add(predicate, {
|
||||||
|
|
||||||
["autocomplete:previous"] = function()
|
["autocomplete:previous"] = function()
|
||||||
suggestions_idx = (suggestions_idx - 2) % #suggestions + 1
|
suggestions_idx = (suggestions_idx - 2) % #suggestions + 1
|
||||||
|
|
||||||
|
local ah = math.min(config.plugins.autocomplete.max_height, #suggestions)
|
||||||
|
if suggestions_offset > suggestions_idx then
|
||||||
|
suggestions_offset = suggestions_idx
|
||||||
|
elseif suggestions_offset + ah < suggestions_idx + 1 then
|
||||||
|
suggestions_offset = suggestions_idx - ah + 1
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["autocomplete:next"] = function()
|
["autocomplete:next"] = function()
|
||||||
suggestions_idx = (suggestions_idx % #suggestions) + 1
|
suggestions_idx = (suggestions_idx % #suggestions) + 1
|
||||||
|
|
||||||
|
local ah = math.min(config.plugins.autocomplete.max_height, #suggestions)
|
||||||
|
if suggestions_offset + ah < suggestions_idx + 1 then
|
||||||
|
suggestions_offset = suggestions_idx - ah + 1
|
||||||
|
elseif suggestions_offset > suggestions_idx then
|
||||||
|
suggestions_offset = suggestions_idx
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["autocomplete:cycle"] = function()
|
["autocomplete:cycle"] = function()
|
||||||
|
|
Loading…
Reference in New Issue