From 996f69465ed51856aa18093d88795fae2b8565f4 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Fri, 4 Sep 2020 00:36:28 -0400 Subject: [PATCH] feat: vertical layouts. see 'layout_strategy' --- lua/telescope/builtin.lua | 1 + lua/telescope/config.lua | 25 ++++ lua/telescope/pickers.lua | 79 +++++-------- lua/telescope/pickers/layout_strategies.lua | 121 ++++++++++++++++++++ 4 files changed, 177 insertions(+), 49 deletions(-) create mode 100644 lua/telescope/config.lua create mode 100644 lua/telescope/pickers/layout_strategies.lua diff --git a/lua/telescope/builtin.lua b/lua/telescope/builtin.lua index 0430d09..7f4c72d 100644 --- a/lua/telescope/builtin.lua +++ b/lua/telescope/builtin.lua @@ -200,6 +200,7 @@ end builtin.grep_string = function(opts) opts = opts or {} + -- TODO: This should probably check your visual selection as well, if you've got one local search = opts.search or vim.fn.expand("") pickers.new(opts, { diff --git a/lua/telescope/config.lua b/lua/telescope/config.lua new file mode 100644 index 0000000..6139d36 --- /dev/null +++ b/lua/telescope/config.lua @@ -0,0 +1,25 @@ +local get_default = require('telescope.utils').get_default + + +-- TODO: Add other major configuration points here. +-- border +-- borderchars +-- selection_strategy + +-- TODO: use `require('telescope').setup { }` + +_TelescopeConfigurationValues = _TelescopeConfigurationValues or {} + +_TelescopeConfigurationValues.default_layout_strategy = get_default( + _TelescopeConfigurationValues.default_layout_strategy, + 'horizontal' +) + +-- TODO: this should probably be more complicated than just a number. +-- If you're going to allow a bunch of layout strats, they should have nested info or something +_TelescopeConfigurationValues.default_window_width = get_default( + _TelescopeConfigurationValues.default_window_width, + 0.75 +) + +return _TelescopeConfigurationValues diff --git a/lua/telescope/pickers.lua b/lua/telescope/pickers.lua index f109db7..c747927 100644 --- a/lua/telescope/pickers.lua +++ b/lua/telescope/pickers.lua @@ -2,6 +2,8 @@ local a = vim.api local popup = require('popup') local actions = require('telescope.actions') +local config = require('telescope.config') +local layout_strategies = require('telescope.pickers.layout_strategies') local log = require('telescope.log') local mappings = require('telescope.mappings') local state = require('telescope.state') @@ -66,6 +68,10 @@ Picker.__index = Picker function Picker:new(opts) opts = opts or {} + if opts.layout_strategy and opts.get_window_options then + error("layout_strategy and get_window_options are not compatible keys") + end + return setmetatable({ prompt = opts.prompt, default_text = opts.default_text, @@ -88,12 +94,17 @@ function Picker:new(opts) -- mappings = get_default(opts.mappings, default_mappings), attach_mappings = opts.attach_mappings, + layout_strategy = opts.layout_strategy, get_window_options = opts.get_window_options, selection_strategy = opts.selection_strategy, window = { -- TODO: This won't account for different layouts... + -- TODO: If it's between 0 and 1, it's a percetnage. + -- TODO: If its's a single number, it's always that many columsn + -- TODO: If it's a list, of length 2, then it's a range of min to max? height = get_default(opts.height, 0.8), + width = get_default(opts.width, config.default_window_width), preview_width = get_default(opts.preview_width, 0.8), results_width = get_default(opts.results_width, 0.8), @@ -106,7 +117,7 @@ function Picker:new(opts) }, Picker) end -function Picker:get_window_options(max_columns, max_lines, prompt_title) +function Picker:_get_initial_window_options(prompt_title) local popup_border = self.window.border local popup_borderchars = self.window.borderchars @@ -130,60 +141,28 @@ function Picker:get_window_options(max_columns, max_lines, prompt_title) enter = true } - -- TODO: Test with 120 width terminal - - local width_padding = 10 - if not self.previewer or max_columns < self.preview_cutoff then - width_padding = 2 - preview.width = 0 - elseif max_columns < 150 then - width_padding = 5 - preview.width = math.floor(max_columns * 0.4) - elseif max_columns < 200 then - preview.width = 80 - else - preview.width = 120 - end - - local other_width = max_columns - preview.width - (2 * width_padding) - results.width = other_width - prompt.width = other_width - - local base_height - if max_lines < 40 then - base_height = math.min(math.floor(max_lines * 0.8), max_lines - 8) - else - base_height = math.floor(max_lines * 0.8) - end - results.height = base_height - results.minheight = results.height - prompt.height = 1 - prompt.minheight = prompt.height - - if self.previewer then - preview.height = results.height + prompt.height + 2 - preview.minheight = preview.height - else - preview.height = 0 - end - - results.col = width_padding - prompt.col = width_padding - preview.col = results.col + results.width + 2 - - -- TODO: Center this in the page a bit better. - local height_padding = math.max(math.floor(0.95 * max_lines), 2) - results.line = max_lines - height_padding - prompt.line = results.line + results.height + 2 - preview.line = results.line - return { - preview = preview.width > 0 and preview, + preview = preview, results = results, prompt = prompt, } end +function Picker:get_window_options(max_columns, max_lines, prompt_title) + local layout_strategy = self.layout_strategy + if not layout_strategy then + layout_strategy = config.default_layout_strategy + end + + local getter = layout_strategies[layout_strategy] + + if not getter then + error("Not a valid layout strategy: ", layout_strategy) + end + + return getter(self, max_columns, max_lines, prompt_title) +end + function Picker:find() self:reset_selection() @@ -651,5 +630,7 @@ function pickers.on_close_prompt(prompt_bufnr) end end +pickers._Picker = Picker + return pickers diff --git a/lua/telescope/pickers/layout_strategies.lua b/lua/telescope/pickers/layout_strategies.lua new file mode 100644 index 0000000..10c9613 --- /dev/null +++ b/lua/telescope/pickers/layout_strategies.lua @@ -0,0 +1,121 @@ + +local layout_strategies = {} + +layout_strategies.horizontal = function(self, max_columns, max_lines, prompt_title) + local initial_options = self:_get_initial_window_options(prompt_title) + local preview = initial_options.preview + local results = initial_options.results + local prompt = initial_options.prompt + + -- TODO: Test with 120 width terminal + -- TODO: Test with self.width. + + local width_padding = 10 + if not self.previewer or max_columns < self.preview_cutoff then + width_padding = 2 + preview.width = 0 + elseif max_columns < 150 then + width_padding = 5 + preview.width = math.floor(max_columns * 0.4) + elseif max_columns < 200 then + preview.width = 80 + else + preview.width = 120 + end + + local other_width = max_columns - preview.width - (2 * width_padding) + results.width = other_width + prompt.width = other_width + + local base_height + if max_lines < 40 then + base_height = math.min(math.floor(max_lines * 0.8), max_lines - 8) + else + base_height = math.floor(max_lines * 0.8) + end + results.height = base_height + results.minheight = results.height + prompt.height = 1 + prompt.minheight = prompt.height + + if self.previewer then + preview.height = results.height + prompt.height + 2 + preview.minheight = preview.height + else + preview.height = 0 + end + + results.col = width_padding + prompt.col = width_padding + preview.col = results.col + results.width + 2 + + -- TODO: Center this in the page a bit better. + local height_padding = math.max(math.floor(0.95 * max_lines), 2) + results.line = max_lines - height_padding + prompt.line = results.line + results.height + 2 + preview.line = results.line + + return { + preview = preview.width > 0 and preview, + results = results, + prompt = prompt, + } +end + +layout_strategies.vertical = function(self, max_columns, max_lines, prompt_title) + local initial_options = self:_get_initial_window_options(prompt_title) + + local preview = initial_options.preview + local results = initial_options.results + local prompt = initial_options.prompt + + local width_padding = math.ceil((1 - self.window.width) * 0.5 * max_columns) + local width = max_columns - width_padding * 2 + if not self.previewer then + preview.width = 0 + else + preview.width = width + end + results.width = width + prompt.width = width + + -- Height + local height_padding = 3 + + results.height = 10 + results.minheight = 10 + prompt.height = 1 + prompt.minheight = 1 + + -- The last 2 * 2 is for the extra borders + if self.previewer then + preview.height = max_lines - results.height - prompt.height - 2 * 2 - height_padding * 2 + preview.minheight = preview.height + else + results.height = max_lines - prompt.height - 2 - height_padding * 2 + results.minheight = results.height + end + + results.col, preview.col, prompt.col = width_padding, width_padding, width_padding + + if self.previewer then + preview.line = height_padding + results.line = preview.line + preview.height + 2 + prompt.line = results.line + results.height + 2 + else + results.line = height_padding + prompt.line = results.line + results.height + 2 + end + + return { + preview = preview.width > 0 and preview, + results = results, + prompt = prompt + } +end + +-- TODO: Add "flex" +-- If you don't have enough width, use the height one +-- etc. + +return layout_strategies