-
-
Notifications
You must be signed in to change notification settings - Fork 65
Expand file tree
/
Copy pathfloating.lua
More file actions
257 lines (225 loc) · 7.73 KB
/
floating.lua
File metadata and controls
257 lines (225 loc) · 7.73 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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
---@mod claude-code.floating Floating window management for claude-code.nvim
---@brief [[
--- This module provides floating window functionality for claude-code.nvim.
--- It handles creating, toggling, and managing floating windows.
---@brief ]]
local M = {}
--- Floating window state management
-- @table ClaudeCodeFloating
-- @field instances table Key-value store of git root to floating window state
-- @field current_instance string|nil Current git root path for active instance
M.floating = {
instances = {},
current_instance = nil,
}
--- Get the current git root or a fallback identifier
--- @param git table The git module
--- @return string identifier Git root path or fallback identifier
local function get_instance_identifier(git)
local git_root = git.get_git_root()
if git_root then
return git_root
else
-- Fallback to current working directory if not in a git repo
return vim.fn.getcwd()
end
end
--- Calculate floating window dimensions and position
--- @param config table Plugin configuration containing floating window settings
--- @return table window_config Window configuration for nvim_open_win
local function get_window_config(config)
local ui = vim.api.nvim_list_uis()[1]
local floating_config = config.window.floating
local width = math.floor(ui.width * floating_config.width)
local height = math.floor(ui.height * floating_config.height)
local row = math.floor((ui.height - height) / 2)
local col = math.floor((ui.width - width) / 2)
return {
relative = 'editor',
width = width,
height = height,
row = row,
col = col,
style = 'minimal',
border = floating_config.border,
title = ' Claude Code ',
title_pos = 'center',
}
end
--- Create or show floating window
--- @param claude_code table The main plugin module
--- @param config table The plugin configuration
--- @param git table The git module
--- @param existing_bufnr number|nil Buffer number of existing buffer to show in the floating window (optional)
--- @return number bufnr Buffer number of the floating window
--- @return number winid Window ID of the floating window
local function create_floating_window(claude_code, config, git, existing_bufnr)
local win_config = get_window_config(config)
-- Create buffer if not provided
local bufnr = existing_bufnr
if not bufnr then
bufnr = vim.api.nvim_create_buf(false, true)
end
-- Create floating window
local winid = vim.api.nvim_open_win(bufnr, true, win_config)
-- Configure buffer and window options
vim.api.nvim_buf_set_option(bufnr, 'bufhidden', 'hide')
-- Use window config settings for floating windows
local hide_numbers = config.window.hide_numbers
local hide_signcolumn = config.window.hide_signcolumn
if hide_numbers then
vim.api.nvim_win_set_option(winid, 'number', false)
vim.api.nvim_win_set_option(winid, 'relativenumber', false)
end
if hide_signcolumn then
vim.api.nvim_win_set_option(winid, 'signcolumn', 'no')
end
return bufnr, winid
end
--- Toggle the Claude Code floating window
--- @param claude_code table The main plugin module
--- @param config table The plugin configuration
--- @param git table The git module
function M.toggle(claude_code, config, git)
-- Determine instance ID based on config
local instance_id
if config.git.multi_instance then
if config.git.use_git_root then
instance_id = get_instance_identifier(git)
else
instance_id = vim.fn.getcwd()
end
else
-- Use a fixed ID for single instance mode
instance_id = 'global'
end
M.floating.current_instance = instance_id
-- Check if this floating instance already exists
local floating_state = M.floating.instances[instance_id]
if floating_state then
local bufnr = floating_state.bufnr
local winid = floating_state.winid
-- Check if window is still valid and visible
if winid and vim.api.nvim_win_is_valid(winid) then
-- Window is visible, close it
vim.api.nvim_win_close(winid, true)
M.floating.instances[instance_id].winid = nil
return
elseif bufnr and vim.api.nvim_buf_is_valid(bufnr) then
-- Buffer exists but window is closed, recreate window
local new_bufnr, new_winid = create_floating_window(claude_code, config, git, bufnr)
M.floating.instances[instance_id].winid = new_winid
-- Force insert mode if configured
local enter_insert = config.window.enter_insert
local start_in_normal_mode = config.window.start_in_normal_mode
if enter_insert and not start_in_normal_mode then
vim.schedule(function()
vim.cmd 'startinsert'
end)
end
return
end
end
-- Create new floating window and terminal
local bufnr, winid = create_floating_window(claude_code, config, git)
-- Determine terminal command
local cmd = config.command
if config.git and config.git.use_git_root then
local git_root = git.get_git_root()
if git_root then
-- Use pushd/popd to change directory
local separator = config.shell.separator
local pushd_cmd = config.shell.pushd_cmd
local popd_cmd = config.shell.popd_cmd
cmd = pushd_cmd
.. ' '
.. git_root
.. ' '
.. separator
.. ' '
.. config.command
.. ' '
.. separator
.. ' '
.. popd_cmd
end
end
-- Start terminal in the floating window
vim.fn.termopen(cmd)
-- Create a unique buffer name
local buffer_name
if config.git.multi_instance then
buffer_name = 'claude-code-floating-' .. instance_id:gsub('[^%w%-_]', '-')
else
buffer_name = 'claude-code-floating'
end
vim.api.nvim_buf_set_name(bufnr, buffer_name)
-- Store the floating window state
M.floating.instances[instance_id] = {
bufnr = bufnr,
winid = winid,
}
-- Set up window closing autocommand
vim.api.nvim_create_autocmd({ 'WinClosed' }, {
buffer = bufnr,
callback = function()
if M.floating.instances[instance_id] then
M.floating.instances[instance_id].winid = nil
end
end,
once = true,
})
-- Automatically enter insert mode if configured
local enter_insert = config.window.enter_insert
local start_in_normal_mode = config.window.start_in_normal_mode
if enter_insert and not start_in_normal_mode then
vim.cmd 'startinsert'
end
end
--- Close floating window if open
--- @param claude_code table The main plugin module
--- @param config table The plugin configuration
--- @param git table The git module
function M.close(claude_code, config, git)
-- Determine instance ID based on config
local instance_id
if config.git.multi_instance then
if config.git.use_git_root then
instance_id = get_instance_identifier(git)
else
instance_id = vim.fn.getcwd()
end
else
instance_id = 'global'
end
local floating_state = M.floating.instances[instance_id]
if
floating_state
and floating_state.winid
and vim.api.nvim_win_is_valid(floating_state.winid)
then
vim.api.nvim_win_close(floating_state.winid, true)
M.floating.instances[instance_id].winid = nil
end
end
--- Check if floating window is currently open
--- @param claude_code table The main plugin module
--- @param config table The plugin configuration
--- @param git table The git module
--- @return boolean is_open Whether the floating window is currently open
function M.is_open(claude_code, config, git)
-- Determine instance ID based on config
local instance_id
if config.git.multi_instance then
if config.git.use_git_root then
instance_id = get_instance_identifier(git)
else
instance_id = vim.fn.getcwd()
end
else
instance_id = 'global'
end
local floating_state = M.floating.instances[instance_id]
return floating_state and floating_state.winid and vim.api.nvim_win_is_valid(floating_state.winid)
end
return M