summaryrefslogtreecommitdiff
path: root/lua/telescope/actions/layout.lua
blob: 0e8b27a968fd5b897a7924a77be1b5bbfa7a6bb9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
---@tag telescope.actions.layout
---@config { ["module"] = "telescope.actions.layout", ["name"] = "ACTIONS_LAYOUT" }

---@brief [[
--- The layout actions are actions to be used to change the layout of a picker.
---@brief ]]

local action_state = require "telescope.actions.state"
local state = require "telescope.state"
local layout_strats = require "telescope.pickers.layout_strategies"

local transform_mod = require("telescope.actions.mt").transform_mod

local action_layout = setmetatable({}, {
  __index = function(_, k)
    error("'telescope.actions.layout' does not have a value: " .. tostring(k))
  end,
})

--- Toggle preview window.
--- - Note: preview window can be toggled even if preview is set to false.
---
--- This action is not mapped by default.
---@param prompt_bufnr number: The prompt bufnr
action_layout.toggle_preview = function(prompt_bufnr)
  local picker = action_state.get_current_picker(prompt_bufnr)
  local status = state.get_status(picker.prompt_bufnr)

  if picker.previewer and status.preview_win then
    picker.hidden_previewer = picker.previewer
    picker.previewer = nil
  elseif picker.hidden_previewer and not status.preview_win then
    picker.previewer = picker.hidden_previewer
    picker.hidden_previewer = nil
  else
    return
  end
  picker:full_layout_update()
end

-- TODO IMPLEMENT (mentored project available, contact @l-kershaw)
action_layout.toggle_padding = function(prompt_bufnr)
  local picker = action_state.get_current_picker(prompt_bufnr)
  -- if padding ~= 0
  --    1. Save `height` and `width` of picker
  --    2. Set both to `{padding = 0}`
  -- else
  --    1. Lookup previous `height` and `width` of picker
  --    2. Set both to previous values
  picker:full_layout_update()
end

--- Toggles the `prompt_position` option between "top" and "bottom".
--- Checks if `prompt_position` is an option for the current layout.
---
--- This action is not mapped by default.
---@param prompt_bufnr number: The prompt bufnr
action_layout.toggle_prompt_position = function(prompt_bufnr)
  local picker = action_state.get_current_picker(prompt_bufnr)
  picker.layout_config = picker.layout_config or {}
  picker.layout_config[picker.layout_strategy] = picker.layout_config[picker.layout_strategy] or {}
  -- flex layout is weird and needs handling separately
  if picker.layout_strategy == "flex" then
    picker.layout_config.flex.horizontal = picker.layout_config.flex.horizontal or {}
    picker.layout_config.flex.vertical = picker.layout_config.flex.vertical or {}
    local old_pos = picker.layout_config.flex[picker.__flex_strategy].prompt_position
    local new_pos = old_pos == "top" and "bottom" or "top"
    picker.layout_config[picker.__flex_strategy].prompt_position = new_pos
    picker.layout_config.flex[picker.__flex_strategy].prompt_position = new_pos
    picker:full_layout_update()
  elseif layout_strats._configurations[picker.layout_strategy].prompt_position then
    if picker.layout_config.prompt_position == "top" then
      picker.layout_config.prompt_position = "bottom"
      picker.layout_config[picker.layout_strategy].prompt_position = "bottom"
    else
      picker.layout_config.prompt_position = "top"
      picker.layout_config[picker.layout_strategy].prompt_position = "top"
    end
    picker:full_layout_update()
  end
end

--- Toggles the `mirror` option between `true` and `false`.
--- Checks if `mirror` is an option for the current layout.
---
--- This action is not mapped by default.
---@param prompt_bufnr number: The prompt bufnr
action_layout.toggle_mirror = function(prompt_bufnr)
  local picker = action_state.get_current_picker(prompt_bufnr)
  -- flex layout is weird and needs handling separately
  if picker.layout_strategy == "flex" then
    picker.layout_config.flex.horizontal = picker.layout_config.flex.horizontal or {}
    picker.layout_config.flex.vertical = picker.layout_config.flex.vertical or {}
    local new_mirror = not picker.layout_config.flex[picker.__flex_strategy].mirror
    picker.layout_config[picker.__flex_strategy].mirror = new_mirror
    picker.layout_config.flex[picker.__flex_strategy].mirror = new_mirror
    picker:full_layout_update()
  elseif layout_strats._configurations[picker.layout_strategy].mirror then
    picker.layout_config = picker.layout_config or {}
    local new_mirror = not picker.layout_config.mirror
    picker.layout_config.mirror = new_mirror
    picker.layout_config[picker.layout_strategy] = picker.layout_config[picker.layout_strategy] or {}
    picker.layout_config[picker.layout_strategy].mirror = new_mirror
    picker:full_layout_update()
  end
end

-- Helper function for `cycle_layout_next` and `cycle_layout_prev`.
local get_cycle_layout = function(dir)
  return function(prompt_bufnr)
    local picker = action_state.get_current_picker(prompt_bufnr)
    if picker.__layout_index then
      picker.__layout_index = ((picker.__layout_index + dir - 1) % #picker.__cycle_layout_list) + 1
    else
      picker.__layout_index = 1
    end
    local new_layout = picker.__cycle_layout_list[picker.__layout_index]
    if type(new_layout) == "string" then
      picker.layout_strategy = new_layout
      picker.layout_config = {}
      picker.previewer = picker.all_previewers and picker.all_previewers[1] or nil
    elseif type(new_layout) == "table" then
      picker.layout_strategy = new_layout.layout_strategy
      picker.layout_config = new_layout.layout_config or {}
      picker.previewer = (new_layout.previewer == nil and picker.all_previewers[picker.current_previewer_index])
        or new_layout.previewer
    else
      error("Not a valid layout setup: " .. vim.inspect(new_layout) .. "\nShould be a string or a table")
    end

    picker:full_layout_update()
  end
end

--- Cycles to the next layout in `cycle_layout_list`.
---
--- This action is not mapped by default.
---@param prompt_bufnr number: The prompt bufnr
action_layout.cycle_layout_next = get_cycle_layout(1)

--- Cycles to the previous layout in `cycle_layout_list`.
---
--- This action is not mapped by default.
---@param prompt_bufnr number: The prompt bufnr
action_layout.cycle_layout_prev = get_cycle_layout(-1)

action_layout = transform_mod(action_layout)
return action_layout