forked from CopilotC-Nvim/CopilotChat.nvim
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpopup.py
More file actions
164 lines (130 loc) · 5.55 KB
/
popup.py
File metadata and controls
164 lines (130 loc) · 5.55 KB
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
from __future__ import annotations
from copy import deepcopy
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Union
if TYPE_CHECKING:
from CopilotChat.mypynvim.core.nvim import MyNvim
from CopilotChat.mypynvim.ui_components.layout import Layout
from CopilotChat.mypynvim.core.buffer import MyBuffer
from CopilotChat.mypynvim.core.window import MyWindow
from CopilotChat.mypynvim.ui_components.calculator import Calculator
from CopilotChat.mypynvim.ui_components.types import PaddingKeys, PopUpConfiguration, Relative
@dataclass
class Padding:
top: int = 0
right: int = 0
bottom: int = 0
left: int = 0
class PopUp:
def __init__(
self,
nvim: MyNvim,
preset: Optional[PopUpConfiguration] = None,
padding: PaddingKeys = {},
enter: bool = False,
opts={},
**kwargs,
):
self.nvim: MyNvim = nvim
self.calculator: Calculator = Calculator(self.nvim)
self.enter: bool = enter
self.opts: Dict[str, Any] = opts
# preset configuration
if preset is None:
preset = PopUpConfiguration()
for key, value in kwargs.items():
setattr(preset, key, value)
self.original_config: PopUpConfiguration = preset
# main window
self.buffer: MyBuffer = MyBuffer.new(self.nvim)
self._set_default_keymaps()
self._set_default_autocmds()
# padding window
self.pd: Padding = Padding(**padding)
self.pd_buffer: MyBuffer = MyBuffer.new(self.nvim)
def mount(self, controlled: bool = False):
"""
Mounts the PopUp.
Resets the configuration to its original values when PopUp was instantiated.
Then computes the absolute values for the configuration.
Then mutate main window configuration & mounts the padding window if any padding is set.
Then mounts the main window.
"""
# reset config to original
self.config: PopUpConfiguration = deepcopy(self.original_config)
self.pd_config: PopUpConfiguration = PopUpConfiguration()
if controlled:
self._set_controlled_configurations()
else:
self._set_uncontrolled_configurations()
# mount padding window if any padding is set
if self._has_padding():
pd_window = self.nvim.api.open_win(
self.pd_buffer, False, self.pd_config.__dict__
)
self.pd_window = MyWindow(self.nvim, pd_window)
# mount main window
window = self.nvim.api.open_win(self.buffer, self.enter, self.config.__dict__)
self.window = MyWindow(self.nvim, window)
self._set_main_window_options()
def unmount(self):
"""Unmounts the PopUp."""
self.nvim.api.win_close(self.window, True)
if self._has_padding():
self.nvim.api.win_close(self.pd_window, True)
def map(self, mode: str, key: str, rhs: Union[str, Callable]):
"""Maps a key to a function in the main window."""
self.buffer.map(mode, key, rhs)
def focus(self):
"""Make the popup active."""
self.nvim.current.window = self.window
def set_layout(self, layout: Layout):
self.layout = layout
def define_controlled_configurations(
self, width: int, height: int, row: int, col: int, relative: Relative = "editor"
):
self.controlled_config = deepcopy(self.original_config)
self.controlled_config.width = width
self.controlled_config.height = height
self.controlled_config.row = row
self.controlled_config.col = col
self.controlled_config.relative = relative
def _set_main_window_options(self):
for key, value in self.opts.items():
self.window.options[key] = value
def _set_controlled_configurations(self):
"""Mutates the configuration of controlled PopUp."""
self.config = self.controlled_config
if self._has_padding():
self._mutate_configurations_for_padding()
def _set_uncontrolled_configurations(self):
"""Mutates the configuration of uncontrolled PopUp."""
self.config = self.calculator.center(self.config)
if self._has_padding():
self._mutate_configurations_for_padding()
def _has_padding(self) -> bool:
return any([self.pd.top, self.pd.right, self.pd.bottom, self.pd.left])
def _mutate_configurations_for_padding(self):
"""
Mutates the configuration to account for padding.
This is done by making the padding window takes place of the original window.
(Effectively replacing the original window with the padding window)
Then the original window is resized (shrinked) to fit within the padding window.
"""
# set window config for padding window
vars(self.pd_config).update(vars(self.config))
# shrink content window
self.config.title = ""
self.config.width = int(self.config.width) - int(self.pd.left) - self.pd.right
self.config.height = int(self.config.height) - int(self.pd.top) - self.pd.bottom
self.config.row = int(self.config.row) + self.pd.top + 1
self.config.col = int(self.config.col) + self.pd.left + 1
self.config.border = "none"
def _set_default_keymaps(self):
self.buffer.map("n", "q", lambda: self.unmount())
def _set_default_autocmds(self):
self.buffer.autocmd(
"BufEnter",
"update_last_popup_for_Layout",
lambda: self.layout.set_last_popup(self),
)