Skip to content

Commit 224beb1

Browse files
committed
Implement the kitty strategy
The strategy adds support for :Make/:Dispatch and :Start/:Spawn task execution using Kitty windows and tabs. :Make/:Dispatch tasks use kitty's get-text[^1] feature to avoid piping command outputs. This allows interactive debugging sessions and complex TUIs to function. It also allows outputs to display in color during execution and capture the output without ANSI codes. Environment isolation is implemented using the `--copy-env` and `--env` flags. Environment variables are copied over except the ones set by (neo)vim itself. [^1]: https://sw.kovidgoyal.net/kitty/remote-control/#kitten-get-text
1 parent a2ff28a commit 224beb1

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

autoload/dispatch/kitty.vim

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
" dispatch.vim kitty strategy
2+
"
3+
" This handler requires you to enable kitty's remote control feature.
4+
" See https://sw.kovidgoyal.net/kitty/remote-control/
5+
6+
if exists('g:autoloaded_dispatch_kitty')
7+
finish
8+
endif
9+
let g:autoloaded_dispatch_kitty = 1
10+
11+
let s:waiting = {}
12+
13+
" -----------------------------------------------------------------------------
14+
" Public handler interface
15+
16+
function! dispatch#kitty#handle(request) abort
17+
if empty($KITTY_LISTEN_ON) || !executable('kitten')
18+
return 0
19+
endif
20+
21+
if a:request.action ==# 'make'
22+
return s:make(a:request)
23+
elseif a:request.action ==# 'start'
24+
return s:start(a:request)
25+
endif
26+
endfunction
27+
28+
function! dispatch#kitty#activate(pid) abort
29+
call system('kitten @ focus-window --match pid:' . a:pid)
30+
return !v:shell_error
31+
endfunction
32+
33+
" -----------------------------------------------------------------------------
34+
" Private implementation of the "kitty" handler
35+
36+
" Handle: :Start, :Spawn
37+
function! s:start(request) abort
38+
let cmd = s:kitty_launch_cmd('tab', a:request, dispatch#prepare_start(a:request))
39+
40+
call system(cmd)
41+
return 1
42+
endfunction
43+
44+
" Handle: :Dispatch, :Make
45+
function! s:make(request) abort
46+
let qf_height = get(g:, 'dispatch_quickfix_height', 10)
47+
if get(a:request, 'background', 0) || (qf_height <= 0 && dispatch#has_callback())
48+
let type = 'tab'
49+
else
50+
let type = 'window'
51+
endif
52+
53+
let cmd_with_capturing = a:request.expanded .
54+
\ '; echo ' . dispatch#status_var() . ' > ' . a:request.file . '.complete' .
55+
\ '; kitten @ get-text --match=id:$KITTY_WINDOW_ID --ansi=no --extent all > ' . a:request.file
56+
57+
let cmd = s:kitty_launch_cmd(type, a:request, dispatch#prepare_start(a:request, cmd_with_capturing, 'make'))
58+
let output = system(cmd)
59+
let window_id = matchstr(output, '^\d\+$')
60+
61+
if !empty(window_id)
62+
let s:waiting[window_id] = a:request
63+
return 1
64+
endif
65+
endfunction
66+
67+
" https://sw.kovidgoyal.net/kitty/launch/
68+
function! s:kitty_launch_cmd(type, request, command) abort
69+
let cmd = 'kitten @ launch'
70+
let cmd .= ' --cwd=' . shellescape(a:request.directory)
71+
let cmd .= ' --copy-env --env SHLVL --env PWD --env VIM --env VIMRUNTIME --env MYVIMRC --env NVIM_LOG_FILE'
72+
73+
if a:request.background || a:request.action ==# 'make'
74+
let cmd .= ' --keep-focus'
75+
endif
76+
77+
if a:type ==# 'tab'
78+
let cmd .= ' --type=tab --tab-title=' . shellescape(a:request.title)
79+
else
80+
let cmd .= ' --type=window --location=hsplit --window-title=' . shellescape(a:request.title)
81+
let bias = get(g:, 'dispatch_kitty_bias', 0)
82+
if bias != 0
83+
let cmd .= ' --bias=' . bias
84+
endif
85+
endif
86+
87+
return cmd . ' sh -c ' . shellescape(a:command)
88+
endfunction
89+
90+
" Section: Without callback - polling
91+
92+
function! s:poll() abort
93+
if empty(s:waiting)
94+
return
95+
endif
96+
97+
for [window_id, request] in items(s:waiting)
98+
if !s:kitty_win_exists(window_id)
99+
call remove(s:waiting, window_id)
100+
call dispatch#complete(request)
101+
endif
102+
endfor
103+
endfunction
104+
105+
function! s:kitty_win_exists(wid) abort
106+
call system('kitten @ ls --match id:' . a:wid)
107+
return !v:shell_error
108+
endfunction
109+
110+
augroup dispatch_kitty
111+
autocmd!
112+
autocmd VimResized * nested if !dispatch#has_callback() | call s:poll() | endif
113+
augroup END

plugin/dispatch.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ endfunction
8787
if !exists('g:dispatch_handlers')
8888
let g:dispatch_handlers = [
8989
\ 'tmux',
90+
\ 'kitty',
9091
\ 'job',
9192
\ 'screen',
9293
\ 'terminal',

0 commit comments

Comments
 (0)