Compare commits

..

8 Commits

Author SHA1 Message Date
Jason Swank
1f444be37a convert to vim9 2026-01-03 01:59:33 +00:00
Jason Swank
e285163442 bat + new zsh functions 2025-12-28 18:38:38 +00:00
Jason Swank
5b27f75da8 new apps 2025-12-28 05:28:46 +00:00
Jason Swank
1669c95044 vim + zk setup 2025-12-27 20:12:44 +00:00
Jason Swank
56530d7f39 wip 2025-12-27 17:24:17 +00:00
Jason Swank
f25f2e5364 update 2025-12-27 05:12:16 +00:00
Jason Swank
0b996ee0de add copilot 2025-12-27 04:53:31 +00:00
Jason Swank
139f71edb6 use vim 2025-12-27 04:46:27 +00:00
120 changed files with 313927 additions and 55 deletions

12
.gitmodules vendored
View File

@@ -13,3 +13,15 @@
[submodule "nvim/.config/nvim/pack/bundle/start/vim-go"]
path = nvim/.config/nvim/pack/bundle/start/vim-go
url = https://github.com/fatih/vim-go.git
[submodule "vim/.vim/pack/plugins/start/fzf.vim"]
path = vim/.vim/pack/plugins/start/fzf.vim
url = https://github.com/junegunn/fzf.vim.git
[submodule "vim/.vim/pack/plugins/start/copilot.vim"]
path = vim/.vim/pack/plugins/start/copilot.vim
url = https://github.com/github/copilot.vim.git
[submodule "vim/vim/pack/plugins/start/lsp"]
path = vim/vim/pack/plugins/start/lsp
url = https://github.com/yegappan/lsp.git
[submodule "vim/.config/vim/pack/plugins/start/lsp"]
path = vim/.config/vim/pack/plugins/start/lsp
url = https://github.com/yegappan/lsp.git

View File

@@ -3,7 +3,8 @@
# set API keys via environment variables, like CLAUDE_API_KEY
# environment variables for aichat can be set at ~/.config/aichat/.env
model: claude:claude-sonnet-4-5-20250929
#model: claude:claude-sonnet-4-5-20250929
model: gemini:gemini-3-flash-preview
keybindings: vi
repl_prelude: role:cloudops
clients:

View File

@@ -203,6 +203,22 @@ list:
max_batch_size: 100
- provider: gemini
models:
- name: gemini-3-flash-preview
type: chat
max_input_tokens: 1048576
input_price: 0.0
output_price: 0.0
max_output_tokens: 65536
supports_vision: true
supports_function_calling: true
- name: gemini-3-pro-preview
type: chat
max_input_tokens: 1048576
input_price: 0.0
output_price: 0.0
max_output_tokens: 65536
supports_vision: true
supports_function_calling: true
- name: gemini-2.5-flash
type: chat
max_input_tokens: 1048576

View File

@@ -0,0 +1,5 @@
I want you to act as a Linux shell expert and senior software engineer.
Explanations should be terse. Do not include emojis in responses.
If relevant, include fenced code blocks as part of your response.

View File

@@ -0,0 +1,3 @@
I'll be asking you questions about the text editor VIM v9.
My configuration is located in $XDG_CONFIG_HOME/vim.

28
bat/.config/bat/config Normal file
View File

@@ -0,0 +1,28 @@
# This is `bat`s configuration file. Each line either contains a comment or
# a command-line option that you want to pass to `bat` by default. You can
# run `bat --help` to get a list of all possible configuration options.
# Specify desired highlighting theme (e.g. "TwoDark"). Run `bat --list-themes`
# for a list of all available themes
--theme="ansi"
#--theme="base16"
# Enable this to use italic text on the terminal. This is not supported on all
# terminal emulators (like tmux, by default):
#--italic-text=always
# Uncomment the following line to disable automatic paging:
#--paging=never
# Uncomment the following line if you are using less version >= 551 and want to
# enable mouse scrolling support in `bat` when running inside tmux. This might
# disable text selection, unless you press shift.
#--pager="less --RAW-CONTROL-CHARS --quit-if-one-screen --mouse"
# Syntax mappings: map a certain filename pattern to a language.
# Example 1: use the C++ syntax for Arduino .ino files
# Example 2: Use ".gitignore"-style highlighting for ".ignore" files
#--map-syntax "*.ino:C++"
#--map-syntax ".ignore:Git Ignore"
--style="plain"

View File

@@ -30,7 +30,7 @@ fi
# install general dotfiles
for dir in \
git \
nvim \
vim \
sh \
ssh \
tmux \

View File

@@ -5,4 +5,4 @@ export PAGER=less
export LESS=RX # R for ANSI color sequences, X to not clear screen on exit
export TMPDIR=/var/tmp
export PS1="\w $ "
export PATH=${PATH}:~/bin
export PATH=${PATH}:~/.local/bin

View File

@@ -8,6 +8,7 @@ Host tuulikki.scalene.net
Host tonttu.scalene.net
User jswank
Port 22024
Host www.scalene.net
User scalene

View File

@@ -0,0 +1,3 @@
let g:netrw_dirhistmax =10
let g:netrw_dirhistcnt =1
let g:netrw_dirhist_1='/home/cli'

View File

@@ -0,0 +1,139 @@
hi clear
if exists("syntax_on")
syntax reset
endif
let g:colors_name = "aomi-grayscale"
" TODO: cterm colors
" Colors abbrev
let s:vmode = "gui"
let s:none = "NONE"
let s:black = "#0d1117"
let s:deep = "#171a1f"
let s:dull = "#40444a"
let s:gray = "#78808a"
let s:semiwhite = "#aeb9c2"
let s:white = "#e4ecf3"
if &background == 'light'
let s:black = "#ffffff"
let s:deep = "#e9eff5"
let s:dull = "#c7cfd6"
let s:gray = "#9097a3"
let s:semiwhite = "#6e7781"
let s:white = "#06070a"
endif
let s:bg_none = " " .s:vmode ."bg=" .s:none
let s:bg_black = " " .s:vmode ."bg=" .s:black
let s:bg_deep = " " .s:vmode ."bg=" .s:deep
let s:bg_dull = " " .s:vmode ."bg=" .s:dull
let s:bg_gray = " " .s:vmode ."bg=" .s:gray
let s:bg_semiwhite = " " .s:vmode ."bg=" .s:semiwhite
let s:bg_white = " " .s:vmode ."bg=" .s:white
let s:fg_none = " " .s:vmode ."fg=" .s:none
let s:fg_black = " " .s:vmode ."fg=" .s:black
let s:fg_deep = " " .s:vmode ."fg=" .s:deep
let s:fg_dull = " " .s:vmode ."fg=" .s:dull
let s:fg_gray = " " .s:vmode ."fg=" .s:gray
let s:fg_semiwhite = " " .s:vmode ."fg=" .s:semiwhite
let s:fg_white = " " .s:vmode ."fg=" .s:white
" Format abbrev
let s:none = "NONE"
let s:t_none = "NONE"
let s:n = "NONE"
let s:c = ",undercurl"
let s:r = ",reverse"
let s:s = ",standout"
let s:b = ",bold"
let s:u = ",underline"
let s:i = ",italic"
let s:vmode = "cterm"
let s:fmt_none = " " .s:vmode."=NONE". " term=NONE"
let s:fmt_bold = " " .s:vmode."=NONE".s:b. " term=NONE".s:b
let s:fmt_bldi = " " .s:vmode."=NONE".s:b. " term=NONE".s:b
let s:fmt_undr = " " .s:vmode."=NONE".s:u. " term=NONE".s:u
let s:fmt_undb = " " .s:vmode."=NONE".s:u.s:b. " term=NONE".s:u.s:b
let s:fmt_undi = " " .s:vmode."=NONE".s:u. " term=NONE".s:u
let s:fmt_curl = " " .s:vmode."=NONE".s:c. " term=NONE".s:c
let s:fmt_ital = " " .s:vmode."=NONE".s:i. " term=NONE".s:i
let s:fmt_stnd = " " .s:vmode."=NONE".s:s. " term=NONE".s:s
let s:fmt_revr = " " .s:vmode."=NONE".s:r. " term=NONE".s:r
let s:fmt_revb = " " .s:vmode."=NONE".s:r.s:b. " term=NONE".s:r.s:b
" Main colors
let s:normal = s:fmt_none .s:fg_white .s:bg_black
let s:keyword = s:fmt_none .s:fg_semiwhite .s:bg_none
let s:comment = s:fmt_none .s:fg_gray .s:bg_none
let s:attention = s:fmt_undr .s:fg_white .s:bg_none
" Basic highlights
exe "hi Normal" .s:normal
exe "hi Comment" .s:comment
exe "hi Constant" .s:normal
exe "hi String" .s:keyword
exe "hi Character" .s:keyword
exe "hi Identifier" .s:normal
exe "hi Statement" .s:keyword
exe "hi PreProc" .s:keyword
exe "hi Type" .s:normal
exe "hi Special" .s:normal
exe "hi Underlined" .s:fmt_undr .s:fg_white .s:bg_none
exe "hi Ignore" .s:fmt_none .s:fg_none .s:bg_none
exe "hi Error" .s:attention
exe "hi Todo" .s:fmt_bold .s:fg_white .s:bg_deep
exe "hi SpecialKey" .s:fmt_none .s:fg_dull .s:bg_none
exe "hi NonText" .s:fmt_none .s:fg_dull .s:bg_none
exe "hi StatusLine" .s:fmt_none .s:fg_white .s:bg_dull
exe "hi StatusLineNC" .s:fmt_none .s:fg_gray .s:bg_deep
exe "hi StatusLineTerm" .s:fmt_none .s:fg_white .s:bg_dull
exe "hi StatusLineTermNC" .s:fmt_none .s:fg_gray .s:bg_deep
exe "hi Visual" .s:fmt_none .s:fg_none .s:bg_dull
exe "hi Directory" .s:keyword
exe "hi ErrorMsg" .s:attention
exe "hi IncSearch" .s:fmt_revr .s:fg_gray .s:bg_black
exe "hi Search" .s:fmt_revr .s:fg_white .s:bg_black
exe "hi MoreMsg" .s:normal
exe "hi ModeMsg" .s:normal
exe "hi LineNr" .s:fmt_none .s:fg_dull .s:bg_none
exe "hi CursorLineNr" .s:fmt_none .s:fg_white .s:bg_none
exe "hi Question" .s:attention
exe "hi VertSplit" .s:fmt_none .s:fg_deep .s:bg_none
exe "hi Title" .s:normal
exe "hi VisualNOS" .s:fmt_none .s:fg_none .s:bg_dull
exe "hi WarningMsg" .s:attention
exe "hi WildMenu" .s:fmt_none .s:fg_white .s:bg_dull
exe "hi Folded" .s:fmt_none .s:fg_gray .s:bg_deep
exe "hi FoldColumn" .s:fmt_none .s:fg_white .s:bg_deep
" TODO: Diff
exe "hi SignColumn" .s:normal
exe "hi Conceal" .s:fmt_none
exe "hi SpellBad" .s:fmt_undr
exe "hi SpellCap" .s:fmt_undr
exe "hi SpellRare" .s:fmt_undr
exe "hi SpellLocal" .s:fmt_undr
exe "hi PMenu" .s:fmt_none .s:fg_white .s:bg_deep
exe "hi PMenuSel" .s:fmt_none .s:fg_white .s:bg_dull
exe "hi PMenuSbar" .s:fmt_none .s:fg_gray .s:bg_deep
exe "hi PMenuThumb" .s:fmt_none .s:fg_gray .s:bg_gray
exe "hi TabLine" .s:fmt_undr .s:fg_gray .s:bg_deep
exe "hi TabLineFill" .s:fmt_undr .s:fg_gray .s:bg_deep
exe "hi TabLineSel" .s:fmt_undr .s:fg_semiwhite .s:bg_deep
exe "hi CursorLine" .s:fmt_none .s:fg_none .s:bg_deep
exe "hi CursorColumn" .s:fmt_none .s:fg_none .s:bg_deep
exe "hi Cursor" .s:fmt_none .s:fg_none .s:bg_dull
exe "hi MatchParen" .s:fmt_none .s:fg_none .s:bg_dull
" Links
hi link CtrlPMatch Visual
hi link LspErrorVirtualText Comment
if &background == 'light'
exe "hi Visual" .s:fmt_none .s:fg_none .s:bg_deep
endif

View File

@@ -0,0 +1,54 @@
" vim color file
" Maintainer: Brian Nelson <nelsonbc@gmail.com>
" Last Change: $Revision: 1.1 $ $Date: 2003/12/15 17:25:08 $
"
" Less is More - A minimal color scheme.
" Disigned to work equally well on 8 or 16 colors, terminal or gui.
hi clear
set background=dark
if exists("syntax_on")
syntax reset
endif
let g:colors_name = "less"
hi Normal term=none ctermfg=none ctermbg=none gui=none guifg=LightGray guibg=black
hi Directory term=bold cterm=bold ctermfg=blue guifg=Blue
hi Search term=reverse ctermfg=white ctermbg=blue guifg=white guibg=Blue
hi MoreMsg term=bold cterm=bold ctermfg=darkgreen gui=bold guifg=DarkGreen
hi ModeMsg term=bold cterm=bold gui=bold guifg=White guibg=Blue
hi LineNr term=underline cterm=bold ctermfg=darkcyan guifg=DarkCyan
hi Question term=standout cterm=bold ctermfg=darkgreen gui=bold guifg=DarkGreen
hi Comment term=bold cterm=none ctermfg=10 gui=none guifg=DarkGray
hi Constant term=bold cterm=none ctermfg=7 gui=none guifg=LightGray
hi Special term=bold cterm=none ctermfg=3 gui=none guifg=Orange
hi Identifier term=none cterm=none ctermfg=7 gui=none guifg=LightGray
hi PreProc term=underline cterm=bold ctermfg=7 gui=bold guifg=White
hi Error term=reverse cterm=bold ctermfg=7 ctermbg=1 gui=bold guifg=Black guibg=Red
hi Todo term=standout cterm=none ctermfg=0 ctermbg=7 guifg=Black guibg=White
hi String term=none cterm=none ctermfg=3 gui=none guifg=LightYellow
hi Function term=bold cterm=bold ctermfg=3 gui=none guifg=Yellow
hi Statement term=bold cterm=bold ctermfg=7 gui=bold guifg=White
hi Include term=bold cterm=bold ctermfg=4 gui=none guifg=LightBlue
hi StorageClass term=bold cterm=bold ctermfg=5 gui=none guifg=LightMagenta
hi Type term=none cterm=none ctermfg=7 gui=none guifg=LightGray
hi Defined term=bold cterm=bold ctermfg=6 gui=none guifg=LightCyan
hi link Character String
hi link Number Constant
hi link Boolean Constant
hi link Float Number
hi link Conditional Statement
hi link Repeat Statement
hi link Label Statement
hi link Operator Statement
hi link Keyword Statement
hi link Exception Statement
hi link Macro Include
hi link PreCondit PreProc
hi link Structure Type
hi link Typedef Type
hi link Tag Special
hi link SpecialChar Special
hi link Delimiter Special
hi link SpecialComment Special
hi link Debug Special

View File

@@ -0,0 +1,276 @@
" Vim color file
"
" Author: Tomas Restrepo <tomas@winterdom.com>
" https://github.com/tomasr/molokai
"
" Note: Based on the Monokai theme for TextMate
" by Wimer Hazenberg and its darker variant
" by Hamish Stuart Macpherson
"
hi clear
if version > 580
" no guarantees for version 5.8 and below, but this makes it stop
" complaining
hi clear
if exists("syntax_on")
syntax reset
endif
endif
let g:colors_name="molokai"
if exists("g:molokai_original")
let s:molokai_original = g:molokai_original
else
let s:molokai_original = 0
endif
hi Boolean guifg=#AE81FF
hi Character guifg=#E6DB74
hi Number guifg=#AE81FF
hi String guifg=#E6DB74
hi Conditional guifg=#F92672 gui=bold
hi Constant guifg=#AE81FF gui=bold
hi Cursor guifg=#000000 guibg=#F8F8F0
hi iCursor guifg=#000000 guibg=#F8F8F0
hi Debug guifg=#BCA3A3 gui=bold
hi Define guifg=#66D9EF
hi Delimiter guifg=#8F8F8F
hi DiffAdd guibg=#13354A
hi DiffChange guifg=#89807D guibg=#4C4745
hi DiffDelete guifg=#960050 guibg=#1E0010
hi DiffText guibg=#4C4745 gui=italic,bold
hi Directory guifg=#A6E22E gui=bold
hi Error guifg=#E6DB74 guibg=#1E0010
hi ErrorMsg guifg=#F92672 guibg=#232526 gui=bold
hi Exception guifg=#A6E22E gui=bold
hi Float guifg=#AE81FF
hi FoldColumn guifg=#465457 guibg=#000000
hi Folded guifg=#465457 guibg=#000000
hi Function guifg=#A6E22E
hi Identifier guifg=#FD971F
hi Ignore guifg=#808080 guibg=bg
hi IncSearch guifg=#C4BE89 guibg=#000000
hi Keyword guifg=#F92672 gui=bold
hi Label guifg=#E6DB74 gui=none
hi Macro guifg=#C4BE89 gui=italic
hi SpecialKey guifg=#66D9EF gui=italic
hi MatchParen guifg=#000000 guibg=#FD971F gui=bold
hi ModeMsg guifg=#E6DB74
hi MoreMsg guifg=#E6DB74
hi Operator guifg=#F92672
" complete menu
hi Pmenu guifg=#66D9EF guibg=#000000
hi PmenuSel guibg=#808080
hi PmenuSbar guibg=#080808
hi PmenuThumb guifg=#66D9EF
hi PreCondit guifg=#A6E22E gui=bold
hi PreProc guifg=#A6E22E
hi Question guifg=#66D9EF
hi Repeat guifg=#F92672 gui=bold
hi Search guifg=#000000 guibg=#FFE792
" marks
hi SignColumn guifg=#A6E22E guibg=#232526
hi SpecialChar guifg=#F92672 gui=bold
hi SpecialComment guifg=#7E8E91 gui=bold
hi Special guifg=#66D9EF guibg=bg gui=italic
if has("spell")
hi SpellBad guisp=#FF0000 gui=undercurl
hi SpellCap guisp=#7070F0 gui=undercurl
hi SpellLocal guisp=#70F0F0 gui=undercurl
hi SpellRare guisp=#FFFFFF gui=undercurl
endif
hi Statement guifg=#F92672 gui=bold
hi StatusLine guifg=#455354 guibg=fg
hi StatusLineNC guifg=#808080 guibg=#080808
hi StorageClass guifg=#FD971F gui=italic
hi Structure guifg=#66D9EF
hi Tag guifg=#F92672 gui=italic
hi Title guifg=#ef5939
hi Todo guifg=#FFFFFF guibg=bg gui=bold
hi Typedef guifg=#66D9EF
hi Type guifg=#66D9EF gui=none
hi Underlined guifg=#808080 gui=underline
hi VertSplit guifg=#808080 guibg=#080808 gui=bold
hi VisualNOS guibg=#403D3D
hi Visual guibg=#403D3D
hi WarningMsg guifg=#FFFFFF guibg=#333333 gui=bold
hi WildMenu guifg=#66D9EF guibg=#000000
hi TabLineFill guifg=#1B1D1E guibg=#1B1D1E
hi TabLine guibg=#1B1D1E guifg=#808080 gui=none
if s:molokai_original == 1
hi Normal guifg=#F8F8F2 guibg=#272822
hi Comment guifg=#75715E
hi CursorLine guibg=#3E3D32
hi CursorLineNr guifg=#FD971F gui=none
hi CursorColumn guibg=#3E3D32
hi ColorColumn guibg=#3B3A32
hi LineNr guifg=#8F908A guibg=#272822
hi NonText guifg=#75715E
hi SpecialKey guifg=#75715E
else
hi Normal guifg=#F8F8F2 guibg=#1B1D1E
hi Comment guifg=#7E8E91
hi CursorLine guibg=#293739
hi CursorLineNr guifg=#FD971F gui=none
hi CursorColumn guibg=#293739
hi ColorColumn guibg=#232526
hi LineNr guifg=#465457 guibg=#232526
hi NonText guifg=#465457
hi SpecialKey guifg=#465457
end
"
" Support for 256-color terminal
"
if &t_Co > 255
if s:molokai_original == 1
hi Normal ctermbg=234
hi CursorLine ctermbg=235 cterm=none
hi CursorLineNr ctermfg=208 cterm=none
else
hi Normal ctermfg=252 ctermbg=233
hi CursorLine ctermbg=234 cterm=none
hi CursorLineNr ctermfg=208 cterm=none
endif
hi Boolean ctermfg=135
hi Character ctermfg=144
hi Number ctermfg=135
hi String ctermfg=144
hi Conditional ctermfg=161 cterm=bold
hi Constant ctermfg=135 cterm=bold
hi Cursor ctermfg=16 ctermbg=253
hi Debug ctermfg=225 cterm=bold
hi Define ctermfg=81
hi Delimiter ctermfg=241
hi DiffAdd ctermbg=24
hi DiffChange ctermfg=181 ctermbg=239
hi DiffDelete ctermfg=162 ctermbg=53
hi DiffText ctermbg=102 cterm=bold
hi Directory ctermfg=118 cterm=bold
hi Error ctermfg=219 ctermbg=89
hi ErrorMsg ctermfg=199 ctermbg=16 cterm=bold
hi Exception ctermfg=118 cterm=bold
hi Float ctermfg=135
hi FoldColumn ctermfg=67 ctermbg=16
hi Folded ctermfg=67 ctermbg=16
hi Function ctermfg=118
hi Identifier ctermfg=208 cterm=none
hi Ignore ctermfg=244 ctermbg=232
hi IncSearch ctermfg=193 ctermbg=16
hi keyword ctermfg=161 cterm=bold
hi Label ctermfg=229 cterm=none
hi Macro ctermfg=193
hi SpecialKey ctermfg=81
hi MatchParen ctermfg=233 ctermbg=208 cterm=bold
hi ModeMsg ctermfg=229
hi MoreMsg ctermfg=229
hi Operator ctermfg=161
" complete menu
hi Pmenu ctermfg=81 ctermbg=16
hi PmenuSel ctermfg=255 ctermbg=242
hi PmenuSbar ctermbg=232
hi PmenuThumb ctermfg=81
hi PreCondit ctermfg=118 cterm=bold
hi PreProc ctermfg=118
hi Question ctermfg=81
hi Repeat ctermfg=161 cterm=bold
hi Search ctermfg=0 ctermbg=222 cterm=NONE
" marks column
hi SignColumn ctermfg=118 ctermbg=235
hi SpecialChar ctermfg=161 cterm=bold
hi SpecialComment ctermfg=245 cterm=bold
hi Special ctermfg=81
if has("spell")
hi SpellBad ctermbg=52
hi SpellCap ctermbg=17
hi SpellLocal ctermbg=17
hi SpellRare ctermfg=none ctermbg=none cterm=reverse
endif
hi Statement ctermfg=161 cterm=bold
hi StatusLine ctermfg=238 ctermbg=253
hi StatusLineNC ctermfg=244 ctermbg=232
hi StorageClass ctermfg=208
hi Structure ctermfg=81
hi Tag ctermfg=161
hi Title ctermfg=166
hi Todo ctermfg=231 ctermbg=232 cterm=bold
hi Typedef ctermfg=81
hi Type ctermfg=81 cterm=none
hi Underlined ctermfg=244 cterm=underline
hi VertSplit ctermfg=244 ctermbg=232 cterm=bold
hi VisualNOS ctermbg=238
hi Visual ctermbg=235
hi WarningMsg ctermfg=231 ctermbg=238 cterm=bold
hi WildMenu ctermfg=81 ctermbg=16
hi Comment ctermfg=59
hi CursorColumn ctermbg=236
hi ColorColumn ctermbg=236
hi LineNr ctermfg=250 ctermbg=236
hi NonText ctermfg=59
hi SpecialKey ctermfg=59
if exists("g:rehash256") && g:rehash256 == 1
hi Normal ctermfg=252 ctermbg=234
hi CursorLine ctermbg=236 cterm=none
hi CursorLineNr ctermfg=208 cterm=none
hi Boolean ctermfg=141
hi Character ctermfg=222
hi Number ctermfg=141
hi String ctermfg=222
hi Conditional ctermfg=197 cterm=bold
hi Constant ctermfg=141 cterm=bold
hi DiffDelete ctermfg=125 ctermbg=233
hi Directory ctermfg=154 cterm=bold
hi Error ctermfg=222 ctermbg=233
hi Exception ctermfg=154 cterm=bold
hi Float ctermfg=141
hi Function ctermfg=154
hi Identifier ctermfg=208
hi Keyword ctermfg=197 cterm=bold
hi Operator ctermfg=197
hi PreCondit ctermfg=154 cterm=bold
hi PreProc ctermfg=154
hi Repeat ctermfg=197 cterm=bold
hi Statement ctermfg=197 cterm=bold
hi Tag ctermfg=197
hi Title ctermfg=203
hi Visual ctermbg=238
hi Comment ctermfg=244
hi LineNr ctermfg=239 ctermbg=235
hi NonText ctermfg=239
hi SpecialKey ctermfg=239
endif
end
" Must be at the end, because of ctermbg=234 bug.
" https://groups.google.com/forum/#!msg/vim_dev/afPqwAFNdrU/nqh6tOM87QUJ
set background=dark

View File

@@ -0,0 +1,315 @@
" Name: plain.vim
" Version: 0.1
" Maintainer: github.com/andreypopp
" License: The MIT License (MIT)
"
" Based on
"
" https://github.com/pbrisbin/vim-colors-off (MIT License)
"
" which in turn based on
"
" https://github.com/reedes/vim-colors-pencil (MIT License)
"
"""
hi clear
if exists('syntax on')
syntax reset
endif
let g:colors_name='plain'
let s:none = {"cterm": "NONE"}
let s:dark_black = {"cterm": "0"}
let s:black = {"cterm": "8"}
let s:dark_red = {"cterm": "1"}
let s:red = {"cterm": "9"}
let s:dark_green = {"cterm": "2"}
let s:green = {"cterm": "10"}
let s:dark_yellow = {"cterm": "3"}
let s:yellow = {"cterm": "11"}
let s:dark_blue = {"cterm": "4"}
let s:blue = {"cterm": "12"}
let s:dark_magenta = {"cterm": "5"}
let s:magenta = {"cterm": "13"}
let s:dark_cyan = {"cterm": "6"}
let s:cyan = {"cterm": "14"}
let s:dark_white = {"cterm": "7"}
let s:white = {"cterm": "15"}
let s:always_dark_black = {"cterm": "16"}
let s:always_black = {"cterm": "17"}
let s:always_dark_white = {"cterm": "18"}
let s:always_white = {"cterm": "19"}
let s:bg = s:none
let s:bg_subtle = s:dark_white
let s:norm = s:none
let s:norm_subtle = s:black
let s:visual = s:cyan
let s:visual_fg = s:white
let s:cursor_line = {"cterm": "none"}
let s:constant = s:cyan
let s:comment = s:black
let s:selection = s:yellow
let s:selection_fg = s:always_dark_black
let s:ok = s:green
let s:warning = s:dark_yellow
let s:error = s:dark_red
" https://github.com/noahfrederick/vim-hemisu/
function! s:h(group, style)
execute "highlight" a:group
\ "ctermfg=" (has_key(a:style, "fg") ? a:style.fg.cterm : "NONE")
\ "ctermbg=" (has_key(a:style, "bg") ? a:style.bg.cterm : "NONE")
\ "cterm=" (has_key(a:style, "cterm") ? a:style.cterm : "NONE")
\ "guisp=" (has_key(a:style, "guisp") ? a:style.guisp : "NONE")
\ "guifg=NONE"
\ "guibg=NONE"
\ "gui=NONE"
endfunction
" __Normal__
if has("gui")
call s:h("Normal", {"fg": s:norm, "bg": s:bg})
call s:h("Cursor", {"fg": s:bg, "bg": s:norm})
else
call s:h("Normal", {"fg": s:norm})
hi! link Cursor Identifier
endif
hi! link Identifier Normal
hi! link Function Identifier
hi! link Type Normal
hi! link StorageClass Type
hi! link Structure Type
hi! link Typedef Type
hi! link Special Normal
hi! link SpecialChar Special
hi! link Tag Special
hi! link Delimiter Special
hi! link SpecialComment Special
hi! link Debug Special
hi! link VertSplit Normal
hi! link PreProc Normal
hi! link Define PreProc
hi! link Macro PreProc
hi! link PreCondit PreProc
" __Operator__
call s:h("Noise", {"fg": s:norm_subtle})
hi! link Operator Noise
hi! link LineNr Noise
hi! link CursorLineNr LineNr
hi! link FoldColumn LineNr
hi! link SignColumn LineNr
" __Comment__
call s:h("Comment", {"fg": s:comment, "cterm": "none"})
" __Constant__
call s:h("Constant", {"fg": s:constant})
hi! link Character Constant
hi! link Number Constant
hi! link Boolean Constant
hi! link Float Constant
hi! link String Constant
hi! link Directory Constant
hi! link Title Constant
" __Statement__
call s:h("Statement", {"fg": s:norm, "cterm": "bold"})
hi! link Include Statement
hi! link Conditonal Statement
hi! link Repeat Statement
hi! link Label Statement
hi! link Keyword Statement
hi! link Exception Statement
" __Underlined__
call s:h("Underlined", {"fg": s:norm, "cterm": "underline"})
" __ExtraWhitespace__
call s:h("ExtraWhitespace", {"bg": s:error})
" __ErrorMsg__
call s:h("ErrorMsg", {"fg": s:error})
hi! link Error ErrorMsg
hi! link Question ErrorMsg
" __WarningMsg__
call s:h("WarningMsg", {"fg": s:warning})
" __InfoMsg__
call s:h("InfoMsg", {"fg": s:dark_magenta, "cterm": "bold"})
" __MoreMsg__
call s:h("MoreMsg", {"fg": s:norm_subtle, "cterm": "bold"})
hi! link ModeMsg MoreMsg
" __NonText__
call s:h("NonText", {"fg": s:norm_subtle})
hi! link Folded NonText
hi! link qfLineNr NonText
" __Visual__
call s:h("Visual", {"bg": s:visual, "fg": s:visual_fg})
" __VisualNOS__
call s:h("VisualNOS", {"bg": s:bg_subtle, "fg": s:visual_fg})
call s:h("Ignore", {"fg": s:bg})
" __DiffAdd__
call s:h("DiffAdd", {"fg": s:dark_green})
" __DiffDelete__
call s:h("DiffDelete", {"fg": s:dark_red})
" __DiffChange__
call s:h("DiffChange", {"fg": s:dark_yellow})
" __DiffText__
call s:h("DiffText", {"fg": s:constant})
if has("gui_running")
call s:h("SpellBad", {"sp": s:dark_red})
call s:h("SpellCap", {"sp": s:ok})
call s:h("SpellRare", {"sp": s:error})
call s:h("SpellLocal", {"sp": s:ok})
else
call s:h("SpellBad", {"cterm": "underline", "fg": s:dark_red})
call s:h("SpellCap", {"cterm": "underline", "fg": s:ok})
call s:h("SpellRare", {"cterm": "underline", "fg": s:error})
call s:h("SpellLocal", {"cterm": "underline", "fg": s:ok})
endif
hi! link helpHyperTextEntry Title
hi! link helpHyperTextJump String
call s:h("StatusLine", {
\"cterm": "bold,underline",
\"bg": s:bg,
\"fg": s:norm
\})
call s:h("StatusLineNC", {
\"cterm": "bold,underline",
\"bg": s:bg,
\"fg": s:bg_subtle
\})
" Semantic status line highlights
call s:h("StatusLineOk", {
\"cterm": "bold,underline",
\"bg": s:bg,
\"fg": s:ok
\})
call s:h("StatusLineError", {
\"cterm": "bold,underline",
\"bg": s:bg,
\"fg": s:error
\})
call s:h("StatusLineWarning", {
\"cterm": "bold,underline",
\"bg": s:bg,
\"fg": s:warning
\})
call s:h("WildMenu", {"cterm": "underline,bold", "bg": s:bg, "fg": s:norm})
" __Pmenu__
call s:h("Pmenu", {"fg": s:norm, "bg": s:cursor_line})
hi! link PmenuSbar Pmenu
hi! link PmenuThumb Pmenu
" __PmenuSel__
call s:h("PmenuSel", {"fg": s:norm, "bg": s:cursor_line, "cterm": "bold"})
hi! link TabLine Normal
hi! link TabLineSel Keyword
hi! link TabLineFill Normal
" __CursorLine__
call s:h("CursorLine", {"bg": s:cursor_line, "cterm": "underline"})
" __CursorColumn__
call s:h("ColorColumn", {"bg": s:cursor_line})
" __MatchParen__
call s:h("MatchParen", {"bg": s:yellow, "fg": s:always_dark_black})
hi! link htmlH1 Normal
hi! link htmlH2 Normal
hi! link htmlH3 Normal
hi! link htmlH4 Normal
hi! link htmlH5 Normal
hi! link htmlH6 Normal
hi link diffRemoved DiffDelete
hi link diffAdded DiffAdd
" Signify, git-gutter
hi link SignifySignAdd LineNr
hi link SignifySignDelete LineNr
hi link SignifySignChange LineNr
hi link GitGutterAdd LineNr
hi link GitGutterDelete LineNr
hi link GitGutterChange LineNr
hi link GitGutterChangeDelete LineNr
hi link jsFlowTypeKeyword Statement
hi link jsFlowImportType Statement
hi link jsFunction Statement
hi link jsGlobalObjects Normal
hi link jsGlobalNodeObjects Normal
hi link jsArrowFunction Noise
hi link StorageClass Statement
hi link xmlTag Constant
hi link xmlTagName xmlTag
hi link xmlEndTag xmlTag
hi link xmlAttrib xmlTag
hi link markdownH1 Statement
hi link markdownH2 Statement
hi link markdownH3 Statement
hi link markdownH4 Statement
hi link markdownH5 Statement
hi link markdownH6 Statement
hi link markdownListMarker Constant
hi link markdownCode Constant
hi link markdownCodeBlock Constant
hi link markdownCodeDelimiter Constant
hi link markdownHeadingDelimiter Constant
hi link yamlBlockMappingKey Statement
hi link pythonOperator Statement
hi link ALEWarning WarningMsg
hi link ALEWarningSign WarningMsg
hi link ALEError ErrorMsg
hi link ALEErrorSign ErrorMsg
hi link ALEInfo InfoMsg
hi link ALEInfoSign InfoMsg
hi link sqlStatement Statement
hi link sqlKeyword Keyword
hi link wikiHeader1 Statement
hi link wikiHeader2 Statement
hi link wikiHeader3 Statement
hi link wikiHeader4 Statement
hi link wikiHeader5 Statement
hi link wikiHeader6 Statement
hi link wikiList Statement
hi link wikiPre Constant
hi link wikiCode Constant
hi link tsxTag Constant
hi link tsxTagName Constant
hi link tsxCloseTagName Constant
hi link tsxAttrib Constant
" __Search__ (make sure it comes after everything else)
call s:h("Search", {"bg": s:selection, "fg": s:selection_fg})
hi! link IncSearch Search

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
" UnixZoo Vim Theme
"
" Copyright (c) 2012, Edd Barrett <vext01@gmail.com>
"
" Permission to use, copy, modify, and/or distribute this software for any
" purpose with or without fee is hereby granted, provided that the above
" copyright notice and this permission notice appear in all copies.
"
" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
hi clear
let g:colors_name="theunixzoo"
" Base Colours
hi Normal guibg=#242429 guifg=#d48130 ctermfg=None ctermbg=None
" Vim Features
hi Cursor guibg=yellow guifg=black ctermbg=None ctermfg=None cterm=None
hi VertSplit guibg=#46464e guifg=grey60 ctermbg=gray ctermfg=None cterm=None
hi Folded guibg=fg guifg=bg ctermbg=None ctermfg=None cterm=None
hi LineNr guifg=grey30 guibg=black ctermbg=None ctermfg=None cterm=None
hi NonText guifg=fg guibg=#19191e ctermbg=None ctermfg=None cterm=None
hi Search guibg=fg guifg=black ctermbg=yellow ctermfg=blue cterm=None
hi IncSearch guibg=bg guifg=#ded032 ctermbg=blue ctermfg=yellow cterm=None
hi StatusLine guibg=black guifg=gray80 ctermbg=gray ctermfg=black cterm=None
hi StatusLineNC guibg=black guifg=gray20 ctermbg=gray ctermfg=black cterm=None
hi Visual guifg=lightblue guibg=#001146 gui=None ctermbg=None ctermfg=None cterm=inverse
hi ErrorMsg guifg=bg guibg=fg ctermbg=None ctermfg=None cterm=None
hi WarningMsg guifg=bg guibg=fg ctermbg=None ctermfg=None cterm=None
hi Error guifg=fg guibg=gray30 ctermbg=red ctermfg=None cterm=None
hi SpecialKey guifg=fg guibg=bg ctermbg=None ctermfg=None cterm=None
hi Directory guifg=fg guibg=bg gui=bold ctermbg=None ctermfg=None cterm=None
hi ModeMsg guifg=fg guibg=bg gui=bold ctermbg=None ctermfg=None cterm=None
hi CursorLine guibg=bg ctermbg=None ctermfg=None cterm=underline
hi Pmenu guifg=seagreen guibg=black ctermbg=gray ctermfg=black cterm=None
hi PmenuSel guifg=skyblue guibg=gray30 ctermbg=yellow ctermfg=black cterm=None
hi Question guifg=seagreen guibg=bg ctermbg=None ctermfg=None cterm=None
hi MoreMsg guifg=seagreen guibg=bg ctermbg=None ctermfg=None cterm=None
hi DiffDelete guifg=gray20 guibg=gray5 ctermbg=None ctermfg=None cterm=None
hi DiffChange guifg=fg guibg=gray30 ctermbg=None ctermfg=None cterm=None
hi DiffAdd guifg=fg guibg=bg ctermbg=None ctermfg=None cterm=None
hi DiffText guifg=black guibg=seagreen gui=None ctermbg=None ctermfg=None cterm=None
hi FoldColumn guifg=fg guibg=bg ctermbg=None ctermfg=None cterm=None
hi Title guifg=fg guibg=bg gui=bold ctermfg=None ctermbg=None cterm=bold
hi VimHiGroup guifg=fg guibg=bg gui=None ctermbg=None ctermfg=None cterm=None
hi VimHiLink guifg=fg guibg=bg gui=None ctermbg=None ctermfg=None cterm=None
hi VimGroup guifg=fg guibg=bg gui=None ctermbg=None ctermfg=None cterm=None
hi Underlined guifg=lightblue guibg=bg gui=bold ctermbg=None ctermfg=None cterm=underline
hi SpellBad guibg=bg gui=undercurl guisp=red ctermbg=red ctermfg=yellow term=None
hi SpellCap guibg=bg gui=undercurl guisp=red ctermbg=red ctermfg=yellow term=None
hi SpellRare guibg=bg gui=undercurl guisp=red ctermbg=red ctermfg=yellow term=None
hi SpellLocal guibg=bg gui=undercurl guisp=red ctermbg=red ctermfg=yellow term=None
hi HelpStar guibg=bg guifg=fg gui=None ctermbg=None ctermfg=None cterm=None
" Language Features
hi Identifier guifg=fg guibg=bg ctermfg=None ctermbg=None cterm=bold
hi Function guifg=fg guibg=bg ctermfg=None ctermbg=None cterm=bold
hi Comment guifg=seagreen guibg=bg ctermfg=10 ctermbg=None cterm=None
hi javaCOmmentTitle guifg=seagreen guibg=bg ctermfg=red ctermbg=None cterm=None
hi Constant guifg=fg guibg=bg ctermfg=None ctermbg=None cterm=None
hi Statement guifg=#f5593f guibg=bg gui=None ctermfg=None ctermbg=None cterm=bold
hi PreProc guifg=fg gui=bold guibg=bg ctermfg=None ctermbg=None cterm=bold
hi Type guifg=fg guibg=bg gui=None ctermfg=None ctermbg=None cterm=None
hi Special gui=None guifg=#deb032 guibg=bg ctermfg=None ctermbg=None cterm=None
hi Todo guibg=#330088 guifg=seagreen ctermfg=black ctermbg=cyan cterm=None
hi cTodo guibg=#330088 guifg=seagreen ctermfg=black ctermbg=cyan cterm=None
hi ColorColumn guibg=gray20 guifg=fg ctermfg=magenta ctermbg=None cterm=None
hi cPreCondit guifg=#cb4b16 ctermfg=None ctermbg=None cterm=None
hi texMathZoneW guibg=bg guifg=fg ctermfg=None ctermbg=None cterm=None
hi texMathOper guibg=bg guifg=fg ctermfg=None ctermbg=None cterm=None
hi Delimiter guifg=#f5593f guibg=bg gui=None ctermfg=None ctermbg=None cterm=bold
" File Manager
hi netrwMarkFile guifg=fg guibg=seagreen ctermfg=None ctermbg=None cterm=inverse

View File

@@ -0,0 +1,425 @@
" Vim color file
" Maintainer: Jani Nurminen <slinky@iki.fi>
" Last Change: $Id: zenburn.vim,v 2.16 2010/10/24 10:55:30 slinky Exp slinky $
" URL: http://slinky.imukuppi.org/zenburnpage/
" License: GNU GPL <http://www.gnu.org/licenses/gpl.html>
"
" Nothing too fancy, just some alien fruit salad to keep you in the zone.
" This syntax file was designed to be used with dark environments and
" low light situations. Of course, if it works during a daybright office, go
" ahead :)
"
" Owes heavily to other Vim color files! With special mentions
" to "BlackDust", "Camo" and "Desert".
"
" To install, copy to ~/.vim/colors directory.
"
" Alternatively, you can use Vimball installation:
" vim zenburn.vba
" :so %
" :q
"
" For details, see :help vimball
"
" After installation, use it with :colorscheme zenburn.
" See also :help syntax
"
" Credits:
" - Jani Nurminen - original Zenburn, maintainer
" - Steve Hall & Cream posse - higher-contrast Visual selection
" - Kurt Maier - 256 color console coloring, low and high contrast toggle,
" bug fixing
" - Charlie - spotted too bright StatusLine in non-high contrast mode
" - Pablo Castellazzi - CursorLine fix for 256 color mode
" - Tim Smith - force dark background
" - John Gabriele - spotted bad Ignore-group handling
" - Zac Thompson - spotted invisible NonText in low contrast mode
" - Christophe-Marie Duquesne - suggested making a Vimball
" - Andrew Wagner - noted the CursorColumn bug (guifg was unintentionally set),
" unify CursorColumn colour
" - Martin Langasek - clarify the license, whitespace fixes
" - Marcin Szamotulski - support autocomplete for Zenburn configuration
" parameters
"
" CONFIGURABLE PARAMETERS:
"
" You can use the default (don't set any parameters), or you can
" set some parameters to tweak the Zenburn colours.
"
" To use them, put them into your .vimrc file before loading the color scheme,
" example:
" let g:zenburn_high_Contrast=1
" colors zenburn
"
" You can also do ":let g:zenburn" then hit Ctrl-d or Tab to scroll through the
" list of configurable parameters.
"
" * You can now set a darker background for bright environments. To activate, use:
" contrast Zenburn, use:
"
" let g:zenburn_high_Contrast = 1
"
" * For example, Vim help files uses the Ignore-group for the pipes in tags
" like "|somelink.txt|". By default, the pipes are not visible, as they
" map to Ignore group. If you wish to enable coloring of the Ignore group,
" set the following parameter to 1. Warning, it might make some syntax files
" look strange.
"
" let g:zenburn_color_also_Ignore = 1
"
" * To get more contrast to the Visual selection, use
"
" let g:zenburn_alternate_Visual = 1
"
" * To use alternate colouring for Error message, use
"
" let g:zenburn_alternate_Error = 1
"
" * The new default for Include is a duller orange. To use the original
" colouring for Include, use
"
" let g:zenburn_alternate_Include = 1
"
" * Work-around to a Vim bug, it seems to misinterpret ctermfg and 234 and 237
" as light values, and sets background to light for some people. If you have
" this problem, use:
"
" let g:zenburn_force_dark_Background = 1
"
" * By default the CursorColumn is of a lighter colour. I find it more readable
" that way, but some people may want to align it with the darker CursorLine
" color, for visual uniformity. To do so, use:
"
" let g:zenburn_unified_CursorColumn = 1
"
" Note: you can ignore this unless you use
" ":set cursorline cursorcolumn", since otherwise the effect won't be
" seen.
"
" NOTE:
"
" * To turn the parameter(s) back to defaults, use UNLET or set them to 0:
"
" unlet g:zenburn_alternate_Include
" or
" let g:zenburn_alternate_Include = 0
"
"
" That's it, enjoy!
"
" TODO
" - Visual alternate color is broken? Try GVim >= 7.0.66 if you have trouble
" - IME colouring (CursorIM)
" Set defaults, but keep any parameters already set by the user
if ! exists("g:zenburn_high_Contrast")
let g:zenburn_high_Contrast = 0
endif
if ! exists("g:zenburn_color_also_Ignore")
let g:zenburn_color_also_Ignore = 0
endif
if ! exists("g:zenburn_alternate_Error")
let g:zenburn_alternate_Error = 0
endif
if ! exists("g:zenburn_force_dark_Background")
let g:zenburn_force_dark_Background = 0
endif
if ! exists("g:zenburn_alternate_Visual")
let g:zenburn_alternate_Visual = 0
endif
if ! exists("g:zenburn_alternate_Include")
let g:zenburn_alternate_Include = 0
endif
if ! exists("g:zenburn_unified_CursorColumn")
let g:zenburn_unified_CursorColumn = 0
endif
" -----------------------------------------------
set background=dark
hi clear
if exists("syntax_on")
syntax reset
endif
let g:colors_name="zenburn"
hi Boolean guifg=#dca3a3
hi Character guifg=#dca3a3 gui=bold
hi Comment guifg=#7f9f7f gui=italic
hi Conditional guifg=#f0dfaf gui=bold
hi Constant guifg=#dca3a3 gui=bold
hi Cursor guifg=#000d18 guibg=#8faf9f gui=bold
hi Debug guifg=#bca3a3 gui=bold
hi Define guifg=#ffcfaf gui=bold
hi Delimiter guifg=#8f8f8f
hi DiffAdd guifg=#709080 guibg=#313c36 gui=bold
hi DiffChange guibg=#333333
hi DiffDelete guifg=#333333 guibg=#464646
hi DiffText guifg=#ecbcbc guibg=#41363c gui=bold
hi Directory guifg=#dcdccc gui=bold
hi ErrorMsg guifg=#80d4aa guibg=#2f2f2f gui=bold
hi Exception guifg=#c3bf9f gui=bold
hi Float guifg=#c0bed1
hi FoldColumn guifg=#93b3a3 guibg=#3f4040
hi Folded guifg=#93b3a3 guibg=#3f4040
hi Function guifg=#efef8f
hi Identifier guifg=#efdcbc
hi IncSearch guibg=#f8f893 guifg=#385f38
hi Keyword guifg=#f0dfaf gui=bold
hi Label guifg=#dfcfaf gui=underline
hi LineNr guifg=#9fafaf guibg=#262626
hi Macro guifg=#ffcfaf gui=bold
hi ModeMsg guifg=#ffcfaf gui=none
hi MoreMsg guifg=#ffffff gui=bold
hi Number guifg=#8cd0d3
hi Operator guifg=#f0efd0
hi PreCondit guifg=#dfaf8f gui=bold
hi PreProc guifg=#ffcfaf gui=bold
hi Question guifg=#ffffff gui=bold
hi Repeat guifg=#ffd7a7 gui=bold
hi Search guifg=#ffffe0 guibg=#284f28
hi SpecialChar guifg=#dca3a3 gui=bold
hi SpecialComment guifg=#82a282 gui=bold
hi Special guifg=#cfbfaf
hi SpecialKey guifg=#9ece9e
hi Statement guifg=#e3ceab gui=none
hi StatusLine guifg=#313633 guibg=#ccdc90
hi StatusLineNC guifg=#2e3330 guibg=#88b090
hi StorageClass guifg=#c3bf9f gui=bold
hi String guifg=#cc9393
hi Structure guifg=#efefaf gui=bold
hi Tag guifg=#e89393 gui=bold
hi Title guifg=#efefef gui=bold
hi Todo guifg=#dfdfdf guibg=bg gui=bold
hi Typedef guifg=#dfe4cf gui=bold
hi Type guifg=#dfdfbf gui=bold
hi Underlined guifg=#dcdccc gui=underline
hi VertSplit guifg=#2e3330 guibg=#688060
hi VisualNOS guifg=#333333 guibg=#f18c96 gui=bold,underline
hi WarningMsg guifg=#ffffff guibg=#333333 gui=bold
hi WildMenu guibg=#2c302d guifg=#cbecd0 gui=underline
hi SpellBad guisp=#bc6c4c guifg=#dc8c6c
hi SpellCap guisp=#6c6c9c guifg=#8c8cbc
hi SpellRare guisp=#bc6c9c guifg=#bc8cbc
hi SpellLocal guisp=#7cac7c guifg=#9ccc9c
" Entering Kurt zone
if &t_Co > 255
hi Boolean ctermfg=181
hi Character ctermfg=181 cterm=bold
hi Comment ctermfg=108
hi Conditional ctermfg=223 cterm=bold
hi Constant ctermfg=181 cterm=bold
hi Cursor ctermfg=233 ctermbg=109 cterm=bold
hi Debug ctermfg=181 cterm=bold
hi Define ctermfg=223 cterm=bold
hi Delimiter ctermfg=245
hi DiffAdd ctermfg=66 ctermbg=237 cterm=bold
hi DiffChange ctermbg=236
hi DiffDelete ctermfg=236 ctermbg=238
hi DiffText ctermfg=217 ctermbg=237 cterm=bold
hi Directory ctermfg=188 cterm=bold
hi ErrorMsg ctermfg=115 ctermbg=236 cterm=bold
hi Exception ctermfg=249 cterm=bold
hi Float ctermfg=251
hi FoldColumn ctermfg=109 ctermbg=238
hi Folded ctermfg=109 ctermbg=238
hi Function ctermfg=228
hi Identifier ctermfg=223
hi IncSearch ctermbg=228 ctermfg=238
hi Keyword ctermfg=223 cterm=bold
hi Label ctermfg=187 cterm=underline
hi LineNr ctermfg=248 ctermbg=235
hi Macro ctermfg=223 cterm=bold
hi ModeMsg ctermfg=223 cterm=none
hi MoreMsg ctermfg=15 cterm=bold
hi Number ctermfg=116
hi Operator ctermfg=230
hi PreCondit ctermfg=180 cterm=bold
hi PreProc ctermfg=223 cterm=bold
hi Question ctermfg=15 cterm=bold
hi Repeat ctermfg=223 cterm=bold
hi Search ctermfg=230 ctermbg=236
hi SpecialChar ctermfg=181 cterm=bold
hi SpecialComment ctermfg=108 cterm=bold
hi Special ctermfg=181
hi SpecialKey ctermfg=151
hi Statement ctermfg=187 ctermbg=234 cterm=none
hi StatusLine ctermfg=236 ctermbg=186
hi StatusLineNC ctermfg=235 ctermbg=108
hi StorageClass ctermfg=249 cterm=bold
hi String ctermfg=174
hi Structure ctermfg=229 cterm=bold
hi Tag ctermfg=181 cterm=bold
hi Title ctermfg=7 ctermbg=234 cterm=bold
hi Todo ctermfg=108 ctermbg=234 cterm=bold
hi Typedef ctermfg=253 cterm=bold
hi Type ctermfg=187 cterm=bold
hi Underlined ctermfg=188 ctermbg=234 cterm=bold
hi VertSplit ctermfg=236 ctermbg=65
hi VisualNOS ctermfg=236 ctermbg=210 cterm=bold
hi WarningMsg ctermfg=15 ctermbg=236 cterm=bold
hi WildMenu ctermbg=236 ctermfg=194 cterm=bold
" spellchecking, always "bright" background
hi SpellLocal ctermfg=14 ctermbg=237
hi SpellBad ctermfg=9 ctermbg=237
hi SpellCap ctermfg=12 ctermbg=237
hi SpellRare ctermfg=13 ctermbg=237
" pmenu
hi PMenu ctermfg=248 ctermbg=0
hi PMenuSel ctermfg=223 ctermbg=235
if exists("g:zenburn_high_Contrast") && g:zenburn_high_Contrast
hi Normal ctermfg=188 ctermbg=234
hi NonText ctermfg=238
if exists("g:zenburn_color_also_Ignore") && g:zenburn_color_also_Ignore
hi Ignore ctermfg=238
endif
" hc mode, darker CursorLine, default 236
hi CursorLine ctermbg=233 cterm=none
if exists("g:zenburn_unified_CursorColumn") && g:zenburn_unified_CursorColumn
hi CursorColumn ctermbg=233 cterm=none
else
hi CursorColumn ctermbg=235 cterm=none
endif
else
hi Normal ctermfg=188 ctermbg=237
hi Cursor ctermbg=109
hi diffadd ctermbg=237
hi diffdelete ctermbg=238
hi difftext ctermbg=237
hi errormsg ctermbg=237
hi foldcolumn ctermbg=238
hi folded ctermbg=238
hi incsearch ctermbg=228
hi linenr ctermbg=238
hi search ctermbg=238
hi statement ctermbg=237
hi statusline ctermbg=144
hi statuslinenc ctermbg=108
hi title ctermbg=237
hi todo ctermbg=237
hi underlined ctermbg=237
hi vertsplit ctermbg=65
hi visualnos ctermbg=210
hi warningmsg ctermbg=236
hi wildmenu ctermbg=236
hi NonText ctermfg=240
if exists("g:zenburn_color_also_Ignore") && g:zenburn_color_also_Ignore
hi Ignore ctermfg=240
endif
" normal mode, lighter CursorLine
hi CursorLine ctermbg=238 cterm=none
if exists("g:zenburn_unified_CursorColumn") && g:zenburn_unified_CursorColumn
hi CursorColumn ctermbg=238 cterm=none
else
hi CursorColumn ctermbg=239 cterm=none
endif
endif
if exists("g:zenburn_alternate_Error") && g:zenburn_alternate_Error
" use more jumpy Error
hi Error ctermfg=210 ctermbg=52 gui=bold
else
" default is something more zenburn-compatible
hi Error ctermfg=228 ctermbg=95 gui=bold
endif
endif
if exists("g:zenburn_force_dark_Background") && g:zenburn_force_dark_Background
" Force dark background, because of a bug in VIM: VIM sets background
" automatically during "hi Normal ctermfg=X"; it misinterprets the high
" value (234 or 237 above) as a light color, and wrongly sets background to
" light. See ":help highlight" for details.
set background=dark
endif
if exists("g:zenburn_high_Contrast") && g:zenburn_high_Contrast
" use new darker background
hi Normal guifg=#dcdccc guibg=#1f1f1f
hi CursorLine guibg=#121212 gui=bold
if exists("g:zenburn_unified_CursorColumn") && g:zenburn_unified_CursorColumn
hi CursorColumn guibg=#121212 gui=bold
else
hi CursorColumn guibg=#2b2b2b
endif
hi Pmenu guibg=#242424 guifg=#ccccbc
hi PMenuSel guibg=#353a37 guifg=#ccdc90 gui=bold
hi PmenuSbar guibg=#2e3330 guifg=#000000
hi PMenuThumb guibg=#a0afa0 guifg=#040404
hi MatchParen guifg=#f0f0c0 guibg=#383838 gui=bold
hi SignColumn guifg=#9fafaf guibg=#181818 gui=bold
hi TabLineFill guifg=#cfcfaf guibg=#181818 gui=bold
hi TabLineSel guifg=#efefef guibg=#1c1c1b gui=bold
hi TabLine guifg=#b6bf98 guibg=#181818 gui=bold
hi NonText guifg=#404040 gui=bold
else
" Original, lighter background
hi Normal guifg=#dcdccc guibg=#3f3f3f
hi CursorLine guibg=#434443
if exists("g:zenburn_unified_CursorColumn") && g:zenburn_unified_CursorColumn
hi CursorColumn guibg=#434343
else
hi CursorColumn guibg=#4f4f4f
endif
hi Pmenu guibg=#2c2e2e guifg=#9f9f9f
hi PMenuSel guibg=#242424 guifg=#d0d0a0 gui=bold
hi PmenuSbar guibg=#2e3330 guifg=#000000
hi PMenuThumb guibg=#a0afa0 guifg=#040404
hi MatchParen guifg=#b2b2a0 guibg=#2e2e2e gui=bold
hi SignColumn guifg=#9fafaf guibg=#343434 gui=bold
hi TabLineFill guifg=#cfcfaf guibg=#353535 gui=bold
hi TabLineSel guifg=#efefef guibg=#3a3a39 gui=bold
hi TabLine guifg=#b6bf98 guibg=#353535 gui=bold
hi NonText guifg=#5b605e gui=bold
endif
if exists("g:zenburn_alternate_Visual") && g:zenburn_alternate_Visual
" Visual with more contrast, thanks to Steve Hall & Cream posse
" gui=none fixes weird highlight problem in at least GVim 7.0.66, thanks to Kurt Maier
hi Visual guifg=#000000 guibg=#71d3b4 gui=none
hi VisualNOS guifg=#000000 guibg=#71d3b4 gui=none
else
" use default visual
hi Visual guifg=#233323 guibg=#71d3b4 gui=none
hi VisualNOS guifg=#233323 guibg=#71d3b4 gui=none
endif
if exists("g:zenburn_alternate_Error") && g:zenburn_alternate_Error
" use more jumpy Error
hi Error guifg=#e37170 guibg=#664040 gui=bold
else
" default is something more zenburn-compatible
hi Error guifg=#e37170 guibg=#3d3535 gui=none
endif
if exists("g:zenburn_alternate_Include") && g:zenburn_alternate_Include
" original setting
hi Include guifg=#ffcfaf gui=bold
else
" new, less contrasted one
hi Include guifg=#dfaf8f gui=bold
endif
if exists("g:zenburn_color_also_Ignore") && g:zenburn_color_also_Ignore
" color the Ignore groups
" note: if you get strange coloring for your files, turn this off (unlet)
hi Ignore guifg=#545a4f
endif
" TODO check for more obscure syntax groups that they're ok

View File

@@ -0,0 +1 @@
autocmd BufNewFile,BufRead *.tofu setlocal filetype=terraform

View File

@@ -0,0 +1,2 @@
*.vim eol=lf
/copilot-language-server/** -whitespace -diff

View File

@@ -0,0 +1 @@
At the moment we are not accepting contributions to the repository.

View File

@@ -0,0 +1,20 @@
name: Auto-close PR
on:
pull_request_target:
types: [opened, reopened]
jobs:
close:
name: Run
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- run: |
gh pr close ${{ github.event.pull_request.number }} --comment \
"At the moment we are not accepting contributions to the repository.
Feedback for Copilot.vim can be given in the [feedback forum](https://github.com/github/copilot.vim/issues)."
env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -0,0 +1 @@
/doc/tags

View File

@@ -0,0 +1,4 @@
GitHub Copilot is offered under the [GitHub Terms of
Service](https://docs.github.com/en/site-policy/github-terms/github-terms-for-additional-products-and-features#github-copilot).
Copyright (C) 2023 GitHub, Inc. - All Rights Reserved.

View File

@@ -0,0 +1,63 @@
# GitHub Copilot for Vim and Neovim
GitHub Copilot is an AI pair programmer tool that helps you write code faster
and smarter. Trained on billions of lines of public code, GitHub Copilot turns
natural language prompts including comments and method names into coding
suggestions across dozens of languages.
Copilot.vim is a Vim/Neovim plugin for GitHub Copilot.
To learn more, visit
[https://github.com/features/copilot](https://github.com/features/copilot).
## Getting access to GitHub Copilot
To access GitHub Copilot, an active GitHub Copilot subscription is required.
Sign up for [GitHub Copilot Free](https://github.com/settings/copilot), or
request access from your enterprise admin.
## Getting started
1. Install [Neovim][] or the latest patch of [Vim][] (9.0.0185 or newer).
2. Install [Node.js][]. If you use a package manager, make sure to install
NPM as well (e.g., `apt install nodejs npm` on Debian/Ubuntu).
3. Install `github/copilot.vim` using vim-plug, lazy.nvim, or any other
plugin manager. Or to install manually, run one of the following
commands:
* Vim, Linux/macOS:
git clone --depth=1 https://github.com/github/copilot.vim.git \
~/.vim/pack/github/start/copilot.vim
* Neovim, Linux/macOS:
git clone --depth=1 https://github.com/github/copilot.vim.git \
~/.config/nvim/pack/github/start/copilot.vim
* Vim, Windows (PowerShell command):
git clone --depth=1 https://github.com/github/copilot.vim.git `
$HOME/vimfiles/pack/github/start/copilot.vim
* Neovim, Windows (PowerShell command):
git clone --depth=1 https://github.com/github/copilot.vim.git `
$HOME/AppData/Local/nvim/pack/github/start/copilot.vim
4. Start Vim/Neovim and invoke `:Copilot setup`.
[Node.js]: https://nodejs.org/en/download/
[Neovim]: https://github.com/neovim/neovim/releases/latest
[Vim]: https://github.com/vim/vim
Suggestions are displayed inline and can be accepted by pressing the tab key.
See `:help copilot` for more information.
## Troubleshooting
Wed love to get your help in making GitHub Copilot better! If you have
feedback or encounter any problems, please reach out on our [feedback
forum](https://github.com/github/copilot.vim/issues).

View File

@@ -0,0 +1,4 @@
If you discover a security issue in this repo, please submit it through the
[GitHub Security Bug Bounty](https://hackerone.com/github).
Thanks for helping make GitHub Copilot safe for everyone.

View File

@@ -0,0 +1,859 @@
scriptencoding utf-8
let s:has_nvim_ghost_text = has('nvim-0.8')
let s:vim_minimum_version = '9.0.0185'
let s:has_vim_ghost_text = has('patch-' . s:vim_minimum_version) && has('textprop')
let s:has_ghost_text = s:has_nvim_ghost_text || s:has_vim_ghost_text
let s:hlgroup = 'CopilotSuggestion'
let s:annot_hlgroup = 'CopilotAnnotation'
if s:has_vim_ghost_text && empty(prop_type_get(s:hlgroup))
call prop_type_add(s:hlgroup, {'highlight': s:hlgroup})
endif
if s:has_vim_ghost_text && empty(prop_type_get(s:annot_hlgroup))
call prop_type_add(s:annot_hlgroup, {'highlight': s:annot_hlgroup})
endif
function! s:Echo(msg) abort
if has('nvim') && &cmdheight == 0
call v:lua.vim.notify(a:msg, v:null, {'title': 'GitHub Copilot'})
else
echo a:msg
endif
endfunction
function! copilot#Init(...) abort
call copilot#util#Defer({ -> exists('s:client') || s:Start() })
endfunction
function! s:Running() abort
return exists('s:client.job') || exists('s:client.client_id')
endfunction
function! s:Start() abort
if s:Running() || exists('s:client.startup_error')
return
endif
let s:client = copilot#client#New()
endfunction
function! s:Stop() abort
if exists('s:client')
let client = remove(s:, 'client')
call client.Close()
endif
endfunction
function! copilot#Client() abort
call s:Start()
return s:client
endfunction
function! copilot#RunningClient() abort
if s:Running()
return s:client
else
return v:null
endif
endfunction
if has('nvim-0.8') && !has(luaeval('vim.version().api_prerelease') ? 'nvim-0.9.1' : 'nvim-0.9.0')
let s:editor_warning = 'Neovim 0.8 support is deprecated and will be dropped in a future release of copilot.vim.'
endif
if has('vim_starting') && exists('s:editor_warning')
call copilot#logger#Warn(s:editor_warning)
endif
function! s:EditorVersionWarning() abort
if exists('s:editor_warning')
echohl WarningMsg
echo 'Warning: ' . s:editor_warning
echohl None
endif
endfunction
function! copilot#Request(method, params, ...) abort
let client = copilot#Client()
return call(client.Request, [a:method, a:params] + a:000)
endfunction
function! copilot#Call(method, params, ...) abort
let client = copilot#Client()
return call(client.Call, [a:method, a:params] + a:000)
endfunction
function! copilot#Notify(method, params, ...) abort
let client = copilot#Client()
return call(client.Notify, [a:method, a:params] + a:000)
endfunction
function! copilot#NvimNs() abort
return nvim_create_namespace('github-copilot')
endfunction
function! copilot#Clear() abort
if exists('g:_copilot_timer')
call timer_stop(remove(g:, '_copilot_timer'))
endif
if exists('b:_copilot')
call copilot#client#Cancel(get(b:_copilot, 'first', {}))
call copilot#client#Cancel(get(b:_copilot, 'cycling', {}))
endif
call s:UpdatePreview()
unlet! b:_copilot
return ''
endfunction
function! copilot#Dismiss() abort
call copilot#Clear()
call s:UpdatePreview()
return ''
endfunction
let s:filetype_defaults = {
\ 'gitcommit': 0,
\ 'gitrebase': 0,
\ 'hgcommit': 0,
\ 'svn': 0,
\ 'cvs': 0,
\ '.': 0}
function! s:BufferDisabled() abort
if &buftype =~# '^\%(help\|prompt\|quickfix\|terminal\)$'
return 5
endif
if exists('b:copilot_disabled')
return empty(b:copilot_disabled) ? 0 : 3
endif
if exists('b:copilot_enabled')
return empty(b:copilot_enabled) ? 4 : 0
endif
let short = empty(&l:filetype) ? '.' : split(&l:filetype, '\.', 1)[0]
let config = {}
if type(get(g:, 'copilot_filetypes')) == v:t_dict
let config = g:copilot_filetypes
endif
if has_key(config, &l:filetype)
return empty(config[&l:filetype])
elseif has_key(config, short)
return empty(config[short])
elseif has_key(config, '*')
return empty(config['*'])
else
return get(s:filetype_defaults, short, 1) == 0 ? 2 : 0
endif
endfunction
function! copilot#Enabled() abort
return get(g:, 'copilot_enabled', 1)
\ && empty(s:BufferDisabled())
endfunction
let s:inline_invoked = 1
let s:inline_automatic = 2
function! copilot#Complete(...) abort
if exists('g:_copilot_timer')
call timer_stop(remove(g:, '_copilot_timer'))
endif
let target = [bufnr(''), getbufvar('', 'changedtick'), line('.'), col('.')]
if !exists('b:_copilot.target') || b:_copilot.target !=# target
if exists('b:_copilot.first')
call copilot#client#Cancel(b:_copilot.first)
endif
if exists('b:_copilot.cycling')
call copilot#client#Cancel(b:_copilot.cycling)
endif
let params = {
\ 'textDocument': {'uri': bufnr('')},
\ 'position': copilot#util#AppendPosition(),
\ 'formattingOptions': {'insertSpaces': &expandtab ? v:true : v:false, 'tabSize': shiftwidth()},
\ 'context': {'triggerKind': s:inline_automatic}}
let b:_copilot = {
\ 'target': target,
\ 'params': params,
\ 'first': copilot#Request('textDocument/inlineCompletion', params)}
let g:_copilot_last = b:_copilot
endif
let completion = b:_copilot.first
if !a:0
return completion.Await()
else
call copilot#client#Result(completion, function(a:1, [b:_copilot]))
if a:0 > 1
call copilot#client#Error(completion, function(a:2, [b:_copilot]))
endif
endif
endfunction
function! s:HideDuringCompletion() abort
return get(g:, 'copilot_hide_during_completion', 1)
endfunction
function! s:SuggestionTextWithAdjustments() abort
let empty = ['', 0, '', {}]
try
if mode() !~# '^[iR]' || (s:HideDuringCompletion() && pumvisible()) || !exists('b:_copilot.suggestions')
return empty
endif
let choice = get(b:_copilot.suggestions, b:_copilot.choice, {})
if !has_key(choice, 'range') || choice.range.start.line != line('.') - 1 || type(choice.insertText) !=# v:t_string
return empty
endif
let line = getline('.')
let offset = col('.') - 1
let byte_offset = copilot#util#UTF16ToByteIdx(line, choice.range.start.character)
let choice_text = strpart(line, 0, byte_offset) .
\ substitute(substitute(choice.insertText, '\r\n\=', '\n', 'g'), '\n*$', '', '')
let typed = strpart(line, 0, offset)
let end_offset = copilot#util#UTF16ToByteIdx(line, choice.range.end.character)
if end_offset < 0
let end_offset = len(line)
endif
let delete = strpart(line, offset, end_offset - offset)
if typed =~# '^\s*$'
let leading = strpart(matchstr(choice_text, '^\s\+'), 0, len(typed))
let unindented = strpart(choice_text, len(leading))
if strpart(typed, 0, len(leading)) ==# leading && unindented !=# delete
return [unindented, len(typed) - len(leading), delete, choice]
endif
elseif typed ==# strpart(choice_text, 0, offset)
return [strpart(choice_text, offset), 0, delete, choice]
endif
catch
call copilot#logger#Exception()
endtry
return empty
endfunction
function! s:Advance(count, context, ...) abort
if a:context isnot# get(b:, '_copilot', {})
return
endif
let a:context.choice += a:count
if a:context.choice < 0
let a:context.choice += len(a:context.suggestions)
endif
let a:context.choice %= len(a:context.suggestions)
call s:UpdatePreview()
endfunction
function! s:GetSuggestionsCyclingCallback(context, result) abort
let callbacks = remove(a:context, 'cycling_callbacks')
let seen = {}
for suggestion in a:context.suggestions
let seen[suggestion.insertText] = 1
endfor
for suggestion in get(a:result, 'items', [])
if !has_key(seen, suggestion.insertText)
call add(a:context.suggestions, suggestion)
let seen[suggestion.insertText] = 1
endif
endfor
for Callback in callbacks
call Callback(a:context)
endfor
endfunction
function! s:GetSuggestionsCycling(callback) abort
if exists('b:_copilot.cycling_callbacks')
call add(b:_copilot.cycling_callbacks, a:callback)
elseif exists('b:_copilot.cycling')
call a:callback(b:_copilot)
elseif exists('b:_copilot.suggestions')
let params = deepcopy(b:_copilot.first.params)
let params.context.triggerKind = s:inline_invoked
let b:_copilot.cycling_callbacks = [a:callback]
let b:_copilot.cycling = copilot#Request('textDocument/inlineCompletion',
\ params,
\ function('s:GetSuggestionsCyclingCallback', [b:_copilot]),
\ function('s:GetSuggestionsCyclingCallback', [b:_copilot]),
\ )
call s:UpdatePreview()
endif
return ''
endfunction
function! copilot#Next() abort
return s:GetSuggestionsCycling(function('s:Advance', [1]))
endfunction
function! copilot#Previous() abort
return s:GetSuggestionsCycling(function('s:Advance', [-1]))
endfunction
function! copilot#GetDisplayedSuggestion() abort
let [text, outdent, delete, item] = s:SuggestionTextWithAdjustments()
return {
\ 'item': item,
\ 'text': text,
\ 'outdentSize': outdent,
\ 'deleteSize': strchars(delete),
\ 'deleteChars': delete}
endfunction
function! s:ClearPreview() abort
if s:has_nvim_ghost_text
call nvim_buf_del_extmark(0, copilot#NvimNs(), 1)
elseif s:has_vim_ghost_text
call prop_remove({'type': s:hlgroup, 'all': v:true})
call prop_remove({'type': s:annot_hlgroup, 'all': v:true})
endif
endfunction
function! s:UpdatePreview() abort
try
let [text, outdent, delete_chars, item] = s:SuggestionTextWithAdjustments()
let delete = strchars(delete_chars)
let text = split(text, "\r\n\\=\\|\n", 1)
if empty(text[-1])
call remove(text, -1)
endif
if empty(text) || !s:has_ghost_text
return s:ClearPreview()
endif
if exists('b:_copilot.cycling_callbacks')
let annot = '(1/…)'
elseif exists('b:_copilot.cycling')
let annot = '(' . (b:_copilot.choice + 1) . '/' . len(b:_copilot.suggestions) . ')'
else
let annot = ''
endif
call s:ClearPreview()
if s:has_nvim_ghost_text
let data = {'id': 1}
let data.virt_text_pos = 'overlay'
let append = strpart(getline('.'), col('.') - 1 + delete)
let data.virt_text = [[text[0] . append . repeat(' ', delete - len(text[0])), s:hlgroup]]
if len(text) > 1
let data.virt_lines = map(text[1:-1], { _, l -> [[l, s:hlgroup]] })
if !empty(annot)
let data.virt_lines[-1] += [[' '], [annot, s:annot_hlgroup]]
endif
elseif len(annot)
let data.virt_text += [[' '], [annot, s:annot_hlgroup]]
endif
let data.hl_mode = 'combine'
call nvim_buf_set_extmark(0, copilot#NvimNs(), line('.')-1, col('.')-1, data)
elseif s:has_vim_ghost_text
let new_suffix = text[0]
let current_suffix = getline('.')[col('.') - 1 :]
let inset = ''
while delete > 0 && !empty(new_suffix)
let last_char = matchstr(new_suffix, '.$')
let new_suffix = matchstr(new_suffix, '^.\{-\}\ze.$')
if last_char ==# matchstr(current_suffix, '.$')
if !empty(inset)
call prop_add(line('.'), col('.') + len(current_suffix), {'type': s:hlgroup, 'text': inset})
let inset = ''
endif
let current_suffix = matchstr(current_suffix, '^.\{-\}\ze.$')
let delete -= 1
else
let inset = last_char . inset
endif
endwhile
if !empty(new_suffix . inset)
call prop_add(line('.'), col('.'), {'type': s:hlgroup, 'text': new_suffix . inset})
endif
for line in text[1:]
call prop_add(line('.'), 0, {'type': s:hlgroup, 'text_align': 'below', 'text': line})
endfor
if !empty(annot)
call prop_add(line('.'), col('$'), {'type': s:annot_hlgroup, 'text': ' ' . annot})
endif
endif
call copilot#Notify('textDocument/didShowCompletion', {'item': item})
catch
return copilot#logger#Exception()
endtry
endfunction
function! s:HandleTriggerResult(state, result) abort
let a:state.suggestions = type(a:result) == type([]) ? a:result : get(empty(a:result) ? {} : a:result, 'items', [])
let a:state.choice = 0
if get(b:, '_copilot') is# a:state
call s:UpdatePreview()
endif
endfunction
function! s:HandleTriggerError(state, result) abort
let a:state.suggestions = []
let a:state.choice = 0
let a:state.error = a:result
if get(b:, '_copilot') is# a:state
call s:UpdatePreview()
endif
endfunction
function! copilot#Suggest() abort
if !s:Running()
return ''
endif
try
call copilot#Complete(function('s:HandleTriggerResult'), function('s:HandleTriggerError'))
catch
call copilot#logger#Exception()
endtry
return ''
endfunction
function! s:Trigger(bufnr, timer) abort
let timer = get(g:, '_copilot_timer', -1)
if a:bufnr !=# bufnr('') || a:timer isnot# timer || mode() !=# 'i'
return
endif
unlet! g:_copilot_timer
return copilot#Suggest()
endfunction
function! copilot#Schedule() abort
if !s:has_ghost_text || !s:Running() || !copilot#Enabled()
call copilot#Clear()
return
endif
call s:UpdatePreview()
let delay = get(g:, 'copilot_idle_delay', 45)
call timer_stop(get(g:, '_copilot_timer', -1))
let g:_copilot_timer = timer_start(delay, function('s:Trigger', [bufnr('')]))
endfunction
function! s:Attach(bufnr, ...) abort
try
return copilot#Client().Attach(a:bufnr)
catch
call copilot#logger#Exception()
endtry
endfunction
function! copilot#OnFileType() abort
if empty(s:BufferDisabled()) && &l:modifiable && &l:buflisted
call copilot#util#Defer(function('s:Attach'), bufnr(''))
endif
endfunction
function! s:Focus(bufnr, ...) abort
if s:Running() && copilot#Client().IsAttached(a:bufnr)
call copilot#Client().Notify('textDocument/didFocus', {'textDocument': {'uri': copilot#Client().Attach(a:bufnr).uri}})
endif
endfunction
function! copilot#OnBufEnter() abort
let bufnr = bufnr('')
call copilot#util#Defer(function('s:Focus'), bufnr)
endfunction
function! copilot#OnInsertLeavePre() abort
call copilot#Clear()
call s:ClearPreview()
endfunction
function! copilot#OnInsertEnter() abort
return copilot#Schedule()
endfunction
function! copilot#OnCompleteChanged() abort
if s:HideDuringCompletion()
return copilot#Clear()
else
return copilot#Schedule()
endif
endfunction
function! copilot#OnCursorMovedI() abort
return copilot#Schedule()
endfunction
function! copilot#OnBufUnload() abort
endfunction
function! copilot#OnVimLeavePre() abort
endfunction
function! copilot#TextQueuedForInsertion() abort
try
return remove(s:, 'suggestion_text')
catch
return ''
endtry
endfunction
function! copilot#Accept(...) abort
let s = copilot#GetDisplayedSuggestion()
if !empty(s.text)
unlet! b:_copilot
let text = ''
if a:0 > 1
let text = substitute(matchstr(s.text, "\n*" . '\%(' . a:2 .'\)'), "\n*$", '', '')
endif
if empty(text)
let text = s.text
endif
let delete_chars = s.deleteChars
let leftover = strpart(s.text, strlen(text))
let idx = strridx(leftover, matchstr(delete_chars, '.$'))
while !empty(delete_chars) && idx != -1
let delete_chars = substitute(delete_chars, '.$', '', '')
let idx = strridx(leftover, matchstr(delete_chars, '.$'), idx - 1)
endwhile
if text ==# s.text && has_key(s.item, 'command')
call copilot#Request('workspace/executeCommand', s.item.command)
else
let line_text = strpart(getline('.'), 0, col('.') - 1) . text
call copilot#Notify('textDocument/didPartiallyAcceptCompletion', {
\ 'item': s.item,
\ 'acceptedLength': copilot#util#UTF16Width(line_text) - s.item.range.start.character})
endif
call s:ClearPreview()
let s:suggestion_text = text
let recall = text =~# "\n" ? "\<C-R>\<C-O>=" : "\<C-R>\<C-R>="
return repeat("\<Left>\<Del>", s.outdentSize) . repeat("\<Del>", strchars(delete_chars)) .
\ recall . "copilot#TextQueuedForInsertion()\<CR>" . (a:0 > 1 ? '' : "\<End>")
endif
let default = get(g:, 'copilot_tab_fallback', pumvisible() ? "\<C-N>" : "\t")
if !a:0
return default
elseif type(a:1) == v:t_string
return a:1
elseif type(a:1) == v:t_func
try
return call(a:1, [])
catch
return default
endtry
else
return default
endif
endfunction
function! copilot#AcceptWord(...) abort
return copilot#Accept(a:0 ? a:1 : '', '\%(\k\@!.\)*\k*')
endfunction
function! copilot#AcceptLine(...) abort
return copilot#Accept(a:0 ? a:1 : "\r", "[^\n]\\+")
endfunction
function! copilot#Browser() abort
if type(get(g:, 'copilot_browser')) == v:t_list
let cmd = copy(g:copilot_browser)
elseif type(get(g:, 'open_command')) == v:t_list
let cmd = copy(g:open_command)
elseif has('win32')
let cmd = ['rundll32', 'url.dll,FileProtocolHandler']
elseif has('mac')
let cmd = ['open']
elseif executable('wslview')
return ['wslview']
elseif executable('xdg-open')
return ['xdg-open']
else
return []
endif
if executable(get(cmd, 0, ''))
return cmd
else
return []
endif
endfunction
let s:commands = {}
function! s:EnabledStatusMessage() abort
let buf_disabled = s:BufferDisabled()
if !s:has_ghost_text
if has('nvim')
return "Neovim 0.6 required to support ghost text"
else
return "Vim " . s:vim_minimum_version . " required to support ghost text"
endif
elseif !get(g:, 'copilot_enabled', 1)
return 'Disabled globally by :Copilot disable'
elseif buf_disabled is# 5
return 'Disabled for current buffer by buftype=' . &buftype
elseif buf_disabled is# 4
return 'Disabled for current buffer by b:copilot_enabled'
elseif buf_disabled is# 3
return 'Disabled for current buffer by b:copilot_disabled'
elseif buf_disabled is# 2
return 'Disabled for filetype=' . &filetype . ' by internal default'
elseif buf_disabled
return 'Disabled for filetype=' . &filetype . ' by g:copilot_filetypes'
elseif !copilot#Enabled()
return 'BUG: Something is wrong with enabling/disabling'
else
return ''
endif
endfunction
function! s:VerifySetup() abort
let error = copilot#Client().StartupError()
if !empty(error)
echo 'Copilot: ' . error
return
endif
if exists('s:client.status.kind') && s:client.status.kind ==# 'Error'
echo 'Copilot: Error: ' . get(s:client.status, 'message', 'unknown')
return
endif
return 1
endfunction
function! s:commands.status(opts) abort
if !s:VerifySetup()
return
endif
if exists('s:client.status.kind') && s:client.status.kind ==# 'Warning'
echo 'Copilot: Warning: ' . get(s:client.status, 'message', 'unknown')
return
endif
let status = s:EnabledStatusMessage()
if !empty(status)
echo 'Copilot: ' . status
return
endif
echo 'Copilot: Ready'
call s:EditorVersionWarning()
endfunction
function! s:commands.signout(opts) abort
echo 'Copilot: Signed out'
call copilot#Call('signOut', {})
endfunction
function! s:commands.setup(opts) abort
let startup_error = copilot#Client().StartupError()
if !empty(startup_error)
echo 'Copilot: ' . startup_error
return
endif
let data = copilot#Call('signIn', {})
if has_key(data, 'verificationUri')
let uri = data.verificationUri
if has('clipboard')
try
let @+ = data.userCode
catch
endtry
try
let @* = data.userCode
catch
endtry
endif
let codemsg = "First copy your one-time code: " . data.userCode . "\n"
try
if len(&mouse)
let mouse = &mouse
set mouse=
endif
if get(a:opts, 'bang')
call s:Echo(codemsg . "In your browser, visit " . uri)
let request = copilot#Request('signInConfirm', {})
else
call input(codemsg . "Press ENTER to open GitHub in your browser\n")
let request = copilot#Request('workspace/executeCommand', data.command)
endif
call s:Echo("Waiting for " . data.userCode . " at " . uri . " (could take up to 5 seconds)")
call request.Wait()
finally
if exists('mouse')
let &mouse = mouse
endif
endtry
if request.status ==# 'error'
return 'echoerr ' . string('Copilot: Authentication failure: ' . request.error.message)
else
let data = request.result
endif
elseif get(data, 'status', '') isnot# 'AlreadySignedIn'
return 'echoerr ' . string('Copilot: Something went wrong')
endif
let user = get(data, 'user', '<unknown>')
echo 'Copilot: Authenticated as GitHub user ' . user
endfunction
let s:commands.auth = s:commands.setup
let s:commands.signin = s:commands.setup
function! s:commands.help(opts) abort
return a:opts.mods . ' help ' . (len(a:opts.arg) ? ':Copilot_' . a:opts.arg : 'copilot')
endfunction
function! s:commands.version(opts) abort
echo 'copilot.vim ' .copilot#client#EditorPluginInfo().version
let editorInfo = copilot#client#EditorInfo()
echo editorInfo.name . ' ' . editorInfo.version
if s:Running()
let versions = s:client.Request('getVersion', {})
if exists('s:client.serverInfo.version')
echo s:client.serverInfo.name . ' ' . s:client.serverInfo.version
else
echo 'GitHub Copilot Language Server ' . versions.Await().version
endif
if exists('s:client.node_version')
echo 'Node.js ' . s:client.node_version
else
echo 'Node.js ' . substitute(get(versions.Await(), 'runtimeVersion', '?'), '^node/', '', 'g')
endif
else
echo 'Not running'
if exists('s:client.node_version')
echo 'Node.js ' . s:client.node_version
endif
endif
if has('win32')
echo 'Windows'
elseif has('macunix')
echo 'macOS'
elseif !has('unix')
echo 'Unknown OS'
elseif isdirectory('/sys/kernel')
echo 'Linux'
else
echo 'UNIX'
endif
call s:EditorVersionWarning()
endfunction
function! s:commands.restart(opts) abort
call s:Stop()
echo 'Copilot: Restarting language server'
call s:Start()
endfunction
function! s:AfterUpgrade(old_version, client) abort
if exists('a:client.serverInfo.version')
call s:Echo('Copilot: Upgraded language server to ' . a:client.serverInfo.version)
let g:copilot_version = '^' . a:client.serverInfo.version
else
call s:Echo('Copilot: Failed to upgrade language server. Check log for details')
let g:copilot_version = a:old_version
if a:old_version is v:null
unlet g:copilot_version
endif
call s:Start()
endif
endfunction
function! s:commands.upgrade(opts) abort
if exists('s:client.serverInfo.version')
echo 'Copilot: Upgrading language server from version ' . s:client.serverInfo.version
else
echo 'Copilot: Upgrading language server'
endif
let old_version = get(g:, 'copilot_version', v:null)
let g:copilot_version = 'latest'
call s:Stop()
call s:Start()
call s:client.AfterInitialized(function('s:AfterUpgrade', [old_version]))
endfunction
function! s:commands.disable(opts) abort
let g:copilot_enabled = 0
endfunction
function! s:commands.enable(opts) abort
let g:copilot_enabled = 1
endfunction
function! s:commands.panel(opts) abort
if s:VerifySetup()
return copilot#panel#Open(a:opts)
endif
endfunction
function! s:FmtModel(model) abort
return a:model.modelName . ' (' . a:model.id . ')'
endfunction
function! s:commands.model(opts) abort
if !s:VerifySetup()
return
endif
let client = copilot#Client()
let response = client.Request('copilot/models', {}).Wait()
if response.status ==# 'error'
return 'echoerr ' . string('Copilot: Error retrieving completions models: ' . response.error.message)
endif
let models = filter(response.result, { _, m -> index(m.scopes, 'completion') >= 0 })
if len(models) == 0
echo 'Copilot: Could not retrieve completions models'
elseif len(models) == 1
echo 'Copilot: Current/only completions model is ' . s:FmtModel(models[0])
else
let choices = map(copy(models), { i, m -> (i + 1) . '. ' . s:FmtModel(m) })
let choice = inputlist(['Select a completions model:'] + choices)
if choice < 1 || choice > len(models)
return
endif
let model = models[choice - 1]
if type(get(g:, 'copilot_settings')) != v:t_dict
let g:copilot_settings = {}
endif
let g:copilot_settings.selectedCompletionModel = model.id
redraw
echo 'Copilot: Set completions model to ' . s:FmtModel(model)
call client.DidChangeConfiguration()
endif
endfunction
function! s:commands.log(opts) abort
return a:opts.mods . ' split +$ copilot:///log'
endfunction
function! copilot#CommandComplete(arg, lead, pos) abort
let args = matchstr(strpart(a:lead, 0, a:pos), 'C\%[opilot][! ] *\zs.*')
if args !~# ' '
return sort(filter(map(keys(s:commands), { k, v -> tr(v, '_', '-') }),
\ { k, v -> strpart(v, 0, len(a:arg)) ==# a:arg }))
else
return []
endif
endfunction
function! copilot#Command(line1, line2, range, bang, mods, arg) abort
let cmd = matchstr(a:arg, '^\%(\\.\|\S\)\+')
let arg = matchstr(a:arg, '\s\zs\S.*')
if !empty(cmd) && !has_key(s:commands, tr(cmd, '-', '_'))
return 'echoerr ' . string('Copilot: unknown command ' . string(cmd))
endif
try
if empty(cmd)
if !s:Running()
let cmd = 'restart'
else
try
let opts = copilot#Call('checkStatus', {'options': {'localChecksOnly': v:true}})
if opts.status !=# 'OK' && opts.status !=# 'MaybeOK'
let cmd = 'setup'
else
let cmd = 'status'
endif
catch
call copilot#logger#Exception()
let cmd = 'log'
endtry
endif
endif
let opts = {'line1': a:line1, 'line2': a:line2, 'range': a:range, 'bang': a:bang, 'mods': a:mods, 'arg': arg}
let retval = s:commands[tr(cmd, '-', '_')](opts)
if type(retval) == v:t_string
return retval
else
return ''
endif
catch /^Copilot:/
return 'echoerr ' . string(v:exception)
endtry
endfunction

View File

@@ -0,0 +1,848 @@
scriptencoding utf-8
let s:plugin_version = copilot#version#String()
let s:error_canceled = {'code': -32800, 'message': 'Canceled'}
let s:error_exit = {'code': -32097, 'message': 'Process exited'}
let s:error_connection_inactive = {'code': -32096, 'message': 'Connection inactive'}
let s:root = expand('<sfile>:h:h:h')
if !exists('s:instances')
let s:instances = {}
endif
" allow sourcing this file to reload the Lua file too
if has('nvim')
lua package.loaded._copilot = nil
endif
function! s:Warn(msg) abort
if !empty(get(g:, 'copilot_no_startup_warnings'))
return
endif
echohl WarningMsg
echomsg 'Copilot: ' . a:msg
echohl NONE
endfunction
function! s:VimClose() dict abort
if !has_key(self, 'job')
return
endif
let job = self.job
if has_key(self, 'kill')
call job_stop(job, 'kill')
call copilot#logger#Warn('Process forcefully terminated')
return
endif
let self.kill = v:true
let self.shutdown = self.Request('shutdown', {}, function(self.Notify, ['exit']))
call timer_start(2000, { _ -> job_stop(job, 'kill') })
call copilot#logger#Debug('Process shutdown initiated')
endfunction
function! s:LogSend(request, line) abort
return '--> ' . a:line
endfunction
function! s:RejectRequest(request, error) abort
if a:request.status !=# 'running'
return
endif
let a:request.waiting = {}
call remove(a:request, 'resolve')
let reject = remove(a:request, 'reject')
let a:request.status = 'error'
let a:request.error = deepcopy(a:error)
for Cb in reject
let a:request.waiting[timer_start(0, function('s:Callback', [a:request, 'error', Cb]))] = 1
endfor
if index([s:error_canceled.code, s:error_connection_inactive.code], a:error.code) != -1
return
endif
let msg = 'Method ' . a:request.method . ' errored with E' . a:error.code . ': ' . json_encode(a:error.message)
if empty(reject)
call copilot#logger#Error(msg)
else
call copilot#logger#Debug(msg)
endif
endfunction
function! s:AfterInitialized(fn, ...) dict abort
call add(self.after_initialized, function(a:fn, [self] + a:000))
endfunction
function! s:AlreadyInitialized(fn, ...) dict abort
return copilot#util#Defer(function(a:fn, [self] + a:000))
endfunction
function! s:Send(instance, request) abort
if !has_key(a:instance, 'job')
return v:false
endif
try
call ch_sendexpr(a:instance.job, a:request)
return v:true
catch /^Vim\%((\a\+)\)\=:E906:/
let a:instance.kill = v:true
let job = remove(a:instance, 'job')
call job_stop(job)
call timer_start(2000, { _ -> job_stop(job, 'kill') })
call copilot#logger#Warn('Terminating process after failed write')
return v:false
catch /^Vim\%((\a\+)\)\=:E631:/
return v:false
endtry
endfunction
function! s:VimNotify(method, params) dict abort
let request = {'method': a:method, 'params': a:params}
call self.AfterInitialized(function('s:Send'), request)
endfunction
function! s:RequestWait() dict abort
while self.status ==# 'running'
sleep 1m
endwhile
while !empty(get(self, 'waiting', {}))
sleep 1m
endwhile
return self
endfunction
function! s:RequestAwait() dict abort
call self.Wait()
if has_key(self, 'result')
return self.result
endif
throw 'Copilot:E' . self.error.code . ': ' . self.error.message
endfunction
function! s:RequestClient() dict abort
return get(s:instances, self.client_id, v:null)
endfunction
if !exists('s:id')
let s:id = 0
endif
if !exists('s:progress_token_id')
let s:progress_token_id = 0
endif
function! s:SetUpRequest(instance, id, method, params, progress, ...) abort
let request = {
\ 'client_id': a:instance.id,
\ 'id': a:id,
\ 'method': a:method,
\ 'params': a:params,
\ 'Client': function('s:RequestClient'),
\ 'Wait': function('s:RequestWait'),
\ 'Await': function('s:RequestAwait'),
\ 'Cancel': function('s:RequestCancel'),
\ 'resolve': [],
\ 'reject': [],
\ 'progress': a:progress,
\ 'status': 'running'}
let args = a:000[2:-1]
if len(args)
if !empty(a:1)
call add(request.resolve, { v -> call(a:1, [v] + args)})
endif
if !empty(a:2)
call add(request.reject, { v -> call(a:2, [v] + args)})
endif
return request
endif
if a:0 && !empty(a:1)
call add(request.resolve, a:1)
endif
if a:0 > 1 && !empty(a:2)
call add(request.reject, a:2)
endif
return request
endfunction
function! s:UrlEncode(str) abort
return substitute(iconv(a:str, 'latin1', 'utf-8'),'[^A-Za-z0-9._~!$&''()*+,;=:@/-]','\="%".printf("%02X",char2nr(submatch(0)))','g')
endfunction
let s:slash = exists('+shellslash') ? '\' : '/'
function! s:UriFromBufnr(bufnr) abort
let absolute = tr(bufname(a:bufnr), s:slash, '/')
if absolute !~# '^\a\+:\|^/\|^$' && getbufvar(a:bufnr, 'buftype') =~# '^\%(nowrite\)\=$'
let absolute = substitute(tr(getcwd(), s:slash, '/'), '/\=$', '/', '') . absolute
endif
return s:UriFromPath(absolute)
endfunction
function! s:UriFromPath(absolute) abort
let absolute = a:absolute
if has('win32') && absolute =~# '^\a://\@!'
return 'file:///' . strpart(absolute, 0, 2) . s:UrlEncode(strpart(absolute, 2))
elseif absolute =~# '^/'
return 'file://' . s:UrlEncode(absolute)
elseif absolute =~# '^\a[[:alnum:].+-]*:\|^$'
return absolute
else
return ''
endif
endfunction
function! s:BufferText(bufnr) abort
return join(getbufline(a:bufnr, 1, '$'), "\n") . "\n"
endfunction
let s:valid_request_key = '^\%(id\|method\|params\)$'
function! s:SendRequest(instance, request, ...) abort
if !has_key(a:instance, 'job') || get(a:instance, 'shutdown', a:request) isnot# a:request
return s:RejectRequest(a:request, s:error_connection_inactive)
endif
let json = filter(copy(a:request), 'v:key =~# s:valid_request_key')
if empty(s:Send(a:instance, json)) && has_key(a:request, 'id') && has_key(a:instance.requests, a:request.id)
call s:RejectRequest(remove(a:instance.requests, a:request.id), {'code': -32099, 'message': 'Write failed'})
endif
endfunction
function! s:RegisterWorkspaceFolderForBuffer(instance, buf) abort
let root = getbufvar(a:buf, 'workspace_folder')
if type(root) != v:t_string
return
endif
let root = s:UriFromPath(substitute(root, '[\/]$', '', ''))
if empty(root) || has_key(a:instance.workspaceFolders, root)
return
endif
let a:instance.workspaceFolders[root] = v:true
call a:instance.Notify('workspace/didChangeWorkspaceFolders', {'event': {'added': [{'uri': root, 'name': fnamemodify(root, ':t')}], 'removed': []}})
endfunction
function! s:PreprocessParams(instance, params) abort
let bufnr = v:null
for doc in filter([get(a:params, 'textDocument', {})], 'type(get(v:val, "uri", "")) == v:t_number')
let bufnr = doc.uri
call s:RegisterWorkspaceFolderForBuffer(a:instance, bufnr)
call extend(doc, a:instance.Attach(bufnr))
endfor
let progress_tokens = []
for key in keys(a:params)
if key =~# 'Token$' && type(a:params[key]) == v:t_func
let s:progress_token_id += 1
let a:instance.progress[s:progress_token_id] = a:params[key]
call add(progress_tokens, s:progress_token_id)
let a:params[key] = s:progress_token_id
endif
endfor
return [bufnr, progress_tokens]
endfunction
function! s:VimAttach(bufnr) dict abort
if !bufloaded(a:bufnr)
return {'uri': '', 'version': 0}
endif
let bufnr = a:bufnr
let doc = {
\ 'uri': s:UriFromBufnr(bufnr),
\ 'version': getbufvar(bufnr, 'changedtick', 0),
\ 'languageId': getbufvar(bufnr, '&filetype'),
\ }
if has_key(self.open_buffers, bufnr) && (
\ self.open_buffers[bufnr].uri !=# doc.uri ||
\ self.open_buffers[bufnr].languageId !=# doc.languageId)
call self.Notify('textDocument/didClose', {'textDocument': {'uri': self.open_buffers[bufnr].uri}})
call remove(self.open_buffers, bufnr)
endif
if !has_key(self.open_buffers, bufnr)
call self.Notify('textDocument/didOpen', {'textDocument': extend({'text': s:BufferText(bufnr)}, doc)})
let self.open_buffers[bufnr] = doc
else
call self.Notify('textDocument/didChange', {
\ 'textDocument': {'uri': doc.uri, 'version': doc.version},
\ 'contentChanges': [{'text': s:BufferText(bufnr)}]})
let self.open_buffers[bufnr].version = doc.version
endif
return doc
endfunction
function! s:VimIsAttached(bufnr) dict abort
return bufloaded(a:bufnr) && has_key(self.open_buffers, a:bufnr) ? v:true : v:false
endfunction
function! s:VimRequest(method, params, ...) dict abort
let s:id += 1
let params = deepcopy(a:params)
let [_, progress] = s:PreprocessParams(self, params)
let request = call('s:SetUpRequest', [self, s:id, a:method, params, progress] + a:000)
call self.AfterInitialized(function('s:SendRequest'), request)
let self.requests[s:id] = request
return request
endfunction
function! s:Call(method, params, ...) dict abort
let request = call(self.Request, [a:method, a:params] + a:000)
if a:0
return request
endif
return request.Await()
endfunction
function! s:Cancel(request) dict abort
if has_key(self.requests, get(a:request, 'id', ''))
call self.Notify('$/cancelRequest', {'id': a:request.id})
call s:RejectRequest(remove(self.requests, a:request.id), s:error_canceled)
endif
endfunction
function! s:RequestCancel() dict abort
let instance = self.Client()
if !empty(instance)
call instance.Cancel(self)
elseif get(self, 'status', '') ==# 'running'
call s:RejectRequest(self, s:error_canceled)
endif
return self
endfunction
function! s:DispatchMessage(instance, method, handler, id, params, ...) abort
try
let response = {'result': call(a:handler, [a:params, a:instance])}
if response.result is# 0
let response.result = v:null
endif
catch
call copilot#logger#Exception('lsp.request.' . a:method)
let response = {'error': {'code': -32000, 'message': v:exception}}
endtry
if a:id isnot# v:null
call s:Send(a:instance, extend({'id': a:id}, response))
endif
if !has_key(s:notifications, a:method)
return response
endif
endfunction
function! s:OnMessage(instance, body, ...) abort
if !has_key(a:body, 'method')
return s:OnResponse(a:instance, a:body)
endif
let request = a:body
let id = get(request, 'id', v:null)
let params = get(request, 'params', v:null)
if has_key(a:instance.methods, request.method)
return s:DispatchMessage(a:instance, request.method, a:instance.methods[request.method], id, params)
elseif id isnot# v:null
call s:Send(a:instance, {"id": id, "error": {"code": -32700, "message": "Method not found: " . request.method}})
call copilot#logger#Debug('Unexpected request ' . request.method . ' called with ' . json_encode(params))
elseif request.method !~# '^\$/'
call copilot#logger#Debug('Unexpected notification ' . request.method . ' called with ' . json_encode(params))
endif
endfunction
function! s:OnResponse(instance, response, ...) abort
let response = a:response
let id = get(a:response, 'id', v:null)
if !has_key(a:instance.requests, id)
return
endif
let request = remove(a:instance.requests, id)
for progress_token in request.progress
if has_key(a:instance.progress, progress_token)
call remove(a:instance.progress, progress_token)
endif
endfor
if request.status !=# 'running'
return
endif
if has_key(response, 'result')
let request.waiting = {}
let resolve = remove(request, 'resolve')
call remove(request, 'reject')
let request.status = 'success'
let request.result = response.result
for Cb in resolve
let request.waiting[timer_start(0, function('s:Callback', [request, 'result', Cb]))] = 1
endfor
else
call s:RejectRequest(request, response.error)
endif
endfunction
function! s:OnErr(instance, ch, line, ...) abort
if !has_key(a:instance, 'serverInfo')
call copilot#logger#Bare('<-! ' . a:line)
endif
endfunction
function! s:FlushAfterInitialized(instance) abort
if has_key(a:instance, 'after_initialized')
let a:instance.AfterInitialized = function('s:AlreadyInitialized')
for Fn in remove(a:instance, 'after_initialized')
call copilot#util#Defer(Fn)
endfor
endif
endfunction
function! s:OnExit(instance, code, ...) abort
let a:instance.exit_status = a:code
if has_key(a:instance, 'job')
call remove(a:instance, 'job')
endif
if has_key(a:instance, 'client_id')
call remove(a:instance, 'client_id')
endif
let message = 'Process exited with status ' . a:code
if a:code >= 18 && a:code < 100
let message = 'Node.js too old. ' .
\ (get(a:instance.node, 0, 'node') ==# 'node' ? 'Upgrade' : 'Change g:copilot_node_command') .
\ ' to ' . a:code . '.x or newer'
endif
if !has_key(a:instance, 'serverInfo') && !has_key(a:instance, 'startup_error')
let a:instance.startup_error = message
endif
for id in sort(keys(a:instance.requests), { a, b -> +a > +b })
call s:RejectRequest(remove(a:instance.requests, id), s:error_exit)
endfor
call s:FlushAfterInitialized(a:instance)
call copilot#util#Defer({ -> get(s:instances, a:instance.id) is# a:instance ? remove(s:instances, a:instance.id) : {} })
if a:code == 0
call copilot#logger#Info(message)
else
call copilot#logger#Warn(message)
if !has_key(a:instance, 'kill')
call copilot#util#Defer(function('s:Warn'), message)
endif
endif
endfunction
function! copilot#client#LspInit(id, initialize_result) abort
if !has_key(s:instances, a:id)
return
endif
call s:PostInit(a:initialize_result, s:instances[a:id])
endfunction
function! copilot#client#LspExit(id, code, signal) abort
if !has_key(s:instances, a:id)
return
endif
let instance = remove(s:instances, a:id)
call s:OnExit(instance, a:code)
endfunction
function! copilot#client#LspResponse(id, opts, ...) abort
if !has_key(s:instances, a:id)
return
endif
call s:OnResponse(s:instances[a:id], a:opts)
endfunction
function! s:NvimAttach(bufnr) dict abort
if !bufloaded(a:bufnr)
return {'uri': '', 'version': 0}
endif
call luaeval('pcall(vim.lsp.buf_attach_client, _A[1], _A[2])', [a:bufnr, self.id])
return luaeval('{uri = vim.uri_from_bufnr(_A), version = vim.lsp.util.buf_versions[_A]}', a:bufnr)
endfunction
function! s:NvimIsAttached(bufnr) dict abort
return bufloaded(a:bufnr) ? luaeval('vim.lsp.buf_is_attached(_A[1], _A[2])', [a:bufnr, self.id]) : v:false
endfunction
function! s:NvimRequest(method, params, ...) dict abort
let params = deepcopy(a:params)
let [bufnr, progress] = s:PreprocessParams(self, params)
let request = call('s:SetUpRequest', [self, v:null, a:method, params, progress] + a:000)
call self.AfterInitialized(function('s:NvimDoRequest'), request, bufnr)
return request
endfunction
function! s:NvimDoRequest(client, request, bufnr) abort
let request = a:request
if has_key(a:client, 'client_id') && !has_key(a:client, 'kill')
let request.id = eval("v:lua.require'_copilot'.lsp_request(a:client.id, a:request.method, a:request.params, a:bufnr)")
endif
if request.id isnot# v:null
let a:client.requests[request.id] = request
else
if has_key(a:client, 'client_id')
call copilot#client#LspExit(a:client.client_id, -1, -1)
endif
call copilot#util#Defer(function('s:RejectRequest'), request, s:error_connection_inactive)
endif
return request
endfunction
function! s:NvimClose() dict abort
if !has_key(self, 'client_id')
return
endif
let self.kill = v:true
return luaeval('vim.lsp.stop_client(_A)', self.client_id)
endfunction
function! s:NvimNotify(method, params) dict abort
call self.AfterInitialized(function('s:NvimDoNotify'), a:method, a:params)
endfunction
function! s:NvimDoNotify(client, method, params) abort
return eval("v:lua.require'_copilot'.rpc_notify(a:client.client_id, a:method, a:params)")
endfunction
function! copilot#client#LspHandle(id, request) abort
if !has_key(s:instances, a:id)
return
endif
return s:OnMessage(s:instances[a:id], a:request)
endfunction
function! s:PackageVersion() abort
try
return json_decode(join(readfile(s:root . '/copilot-language-server/package.json'))).version
catch
endtry
return ''
endfunction
function! s:GetCommand(var, default) abort
let cmd = get(g:, a:var, '')
if type(cmd) == type('') && !empty(cmd)
return [expand(cmd)]
endif
return type(cmd) == v:t_list && !empty(cmd) ? copy(cmd) : a:default
endfunction
let s:script_name = 'copilot-language-server/dist/language-server.js'
let s:pkg_name = '@github/copilot-language-server'
function! s:Command() abort
if !has('nvim-0.8') && v:version < 900
return [[], [], 'Vim version too old']
endif
let script = s:GetCommand('copilot_command', [])
let npx = get(g:, 'copilot_version', get(g:, 'copilot_npx', v:null))
if npx is# v:null
let npx = empty(script) && !empty(get(g:, 'copilot_npx_command', 1)) ? v:true : v:false
endif
if type(npx) != v:t_string && !empty(npx)
let npx = ''
endif
if type(npx) == v:t_string
if empty(npx)
let npx = '^'
endif
if npx =~# '^\%([~<>=^]\|\d\+\.\|latest$\)'
let npx = '@' . npx
endif
if npx =~# '^@[^/]*$'
let npx = s:pkg_name . npx
endif
if npx =~# '@[~<>=^]\+$'
let pkg_version = s:PackageVersion()
if pkg_version =~# '^[1-9]'
let npx .= pkg_version
else
let npx = substitute(npx, '@[=~]$', '@^', '') . '1.0.0'
endif
endif
let script = s:GetCommand('copilot_npx_command', ['npx']) + [npx]
if !executable(script[0])
let script = []
endif
endif
if empty(script)
let script = [s:root . '/' . s:script_name]
endif
if script[0] !~# '\.[cm]\=[jt]s$' && executable(script[0])
return [[], script, '']
elseif !filereadable(script[0])
return [[], [], 'Could not find ' . script[0]]
endif
let node = s:GetCommand('copilot_node_command', ['node'])
if !executable(get(node, 0, ''))
if get(node, 0, '') ==# 'node'
return [[], [], 'Node.js not found in PATH']
else
return [[], [], 'Node.js executable `' . get(node, 0, '') . "' not found"]
endif
endif
return [node, script, '']
endfunction
function! s:UrlDecode(str) abort
return substitute(a:str, '%\(\x\x\)', '\=iconv(nr2char("0x".submatch(1)), "utf-8", "latin1")', 'g')
endfunction
function! copilot#client#EditorInfo() abort
if !exists('s:editor_version')
if has('nvim')
let s:editor_version = matchstr(execute('version'), 'NVIM v\zs[^[:space:]]\+')
else
let s:editor_version = (v:version / 100) . '.' . (v:version % 100) . (exists('v:versionlong') ? printf('.%04d', v:versionlong % 10000) : '')
endif
endif
return {'name': has('nvim') ? 'Neovim': 'Vim', 'version': s:editor_version}
endfunction
function! copilot#client#EditorPluginInfo() abort
return {'name': 'copilot.vim', 'version': s:plugin_version}
endfunction
function! copilot#client#Settings() abort
let settings = {
\ 'http': {
\ 'proxy': get(g:, 'copilot_proxy', v:null),
\ 'proxyStrictSSL': get(g:, 'copilot_proxy_strict_ssl', v:null)},
\ 'github-enterprise': {'uri': get(g:, 'copilot_enterprise_uri', get(g:, 'copilot_auth_provider_url', v:null))},
\ }
if type(settings.http.proxy) ==# v:t_string && settings.http.proxy =~# '^[^/]\+$'
let settings.http.proxy = 'http://' . settings.http.proxy
endif
if type(get(g:, 'copilot_settings')) == v:t_dict
let settings.github = {'copilot': g:copilot_settings}
endif
if type(get(g:, 'copilot_lsp_settings')) == v:t_dict
call extend(settings, g:copilot_lsp_settings)
endif
return settings
endfunction
function! s:PostInit(result, instance) abort
let a:instance.serverInfo = get(a:result, 'serverInfo', {})
if !has_key(a:instance, 'node_version') && has_key(a:result.serverInfo, 'nodeVersion')
let a:instance.node_version = a:result.serverInfo.nodeVersion
endif
call s:FlushAfterInitialized(a:instance)
endfunction
function! s:InitializeResult(result, instance) abort
call s:Send(a:instance, {'method': 'initialized', 'params': {}})
call s:PostInit(a:result, a:instance)
endfunction
function! s:InitializeError(error, instance) abort
if !has_key(a:instance, 'startup_error')
let a:instance.startup_error = 'Unexpected error E' . a:error.code . ' initializing language server: ' . a:error.message
call a:instance.Close()
endif
endfunction
function! s:StartupError() dict abort
while (has_key(self, 'job') || has_key(self, 'client_id')) && !has_key(self, 'startup_error') && !has_key(self, 'serverInfo')
sleep 10m
endwhile
if has_key(self, 'serverInfo')
return ''
else
return get(self, 'startup_error', 'Something unexpected went wrong spawning the language server')
endif
endfunction
function! s:VimDidChangeConfiguration() dict abort
let settings = copilot#client#Settings()
return self.Notify('workspace/didChangeConfiguration', {'settings': settings})
endfunction
function! s:NvimDidChangeConfiguration() dict abort
let settings = copilot#client#Settings()
return eval("v:lua.require'_copilot'.did_change_configuration(self.id, settings)")
endfunction
function! s:StatusNotification(params, instance) abort
let a:instance.status = a:params
endfunction
function! s:Nop(...) abort
return v:null
endfunction
function! s:False(...) abort
return v:false
endfunction
function! s:Progress(params, instance) abort
if has_key(a:instance.progress, a:params.token)
call a:instance.progress[a:params.token](a:params.value)
endif
endfunction
let s:notifications = {
\ '$/progress': function('s:Progress'),
\ 'featureFlagsNotification': function('s:Nop'),
\ 'didChangeStatus': function('s:StatusNotification'),
\ 'window/logMessage': function('copilot#handlers#window_logMessage'),
\ }
let s:vim_handlers = {
\ 'window/showMessageRequest': function('copilot#handlers#window_showMessageRequest'),
\ 'window/showDocument': function('copilot#handlers#window_showDocument'),
\ }
let s:vim_capabilities = {
\ 'workspace': {'workspaceFolders': v:true},
\ 'window': {'showDocument': {'support': v:true}},
\ }
function! copilot#client#New() abort
let opts = {}
let instance = {'requests': {},
\ 'name': 'GitHub Copilot',
\ 'progress': {},
\ 'workspaceFolders': {},
\ 'after_initialized': [],
\ 'status': {'status': 'Starting', 'message': ''},
\ 'AfterInitialized': function('s:AfterInitialized'),
\ 'Close': function('s:Nop'),
\ 'Notify': function('s:False'),
\ 'Request': function('s:VimRequest'),
\ 'Attach': function('s:Nop'),
\ 'IsAttached': function('s:False'),
\ 'Call': function('s:Call'),
\ 'Cancel': function('s:Cancel'),
\ 'DidChangeConfiguration': function('s:VimDidChangeConfiguration'),
\ 'StartupError': function('s:StartupError'),
\ }
let instance.methods = copy(s:notifications)
let [node, argv, command_error] = s:Command()
if !empty(command_error)
let instance.id = -1
let instance.startup_error = command_error
call copilot#logger#Error(command_error)
call s:FlushAfterInitialized(instance)
return instance
endif
let instance.node = node
let command = node + argv + ['--stdio']
let opts.initializationOptions = {
\ 'editorInfo': copilot#client#EditorInfo(),
\ 'editorPluginInfo': copilot#client#EditorPluginInfo(),
\ }
if type(get(g:, 'copilot_integration_id')) == v:t_string
let opts.initializationOptions.copilotIntegrationId = g:copilot_integration_id
endif
let opts.workspaceFolders = []
let settings = copilot#client#Settings()
if type(get(g:, 'copilot_workspace_folders')) == v:t_list
for folder in g:copilot_workspace_folders
if type(folder) == v:t_string && !empty(folder) && folder !~# '\*\*\|^/$'
for path in glob(folder . '/', 0, 1)
let uri = s:UriFromPath(substitute(path, '[\/]*$', '', ''))
call add(opts.workspaceFolders, {'uri': uri, 'name': fnamemodify(uri, ':t')})
endfor
elseif type(folder) == v:t_dict && has_key(v:t_dict, 'uri') && !empty(folder.uri) && has_key(folder, 'name')
call add(opts.workspaceFolders, folder)
endif
endfor
endif
for folder in opts.workspaceFolders
let instance.workspaceFolders[folder.uri] = v:true
endfor
call copilot#logger#Debug('Spawning ' . join(command, ' '))
let is_win_shell = has('win32') && &shellcmdflag !~# '^-'
if is_win_shell && command[0] !~# '[\/]'
let exepath = exepath(command[0])
if exepath !~? '\.exe$\|^$'
let command[0] = fnamemodify(exepath, ':t')
endif
endif
if has('nvim')
if is_win_shell
call map(command, { _, v -> substitute(v, '\^', '^^^^', 'g') })
endif
call extend(instance, {
\ 'Close': function('s:NvimClose'),
\ 'Notify': function('s:NvimNotify'),
\ 'Request': function('s:NvimRequest'),
\ 'Attach': function('s:NvimAttach'),
\ 'DidChangeConfiguration': function('s:NvimDidChangeConfiguration'),
\ 'IsAttached': function('s:NvimIsAttached'),
\ })
let id = eval("v:lua.require'_copilot'.lsp_start_client(command, instance.name, keys(instance.methods), opts, settings)")
if id is# v:null
let instance.id = -1
let instance.startup_error = 'Neovim failed to start LSP client'
call s:FlushAfterInitialized(instance)
return instance
endif
let instance.client_id = id
let instance.id = instance.client_id
else
if is_win_shell
let command = join(map(command, { _, v -> v =~# '[;&|^ ]' ? '"' . v . '"' : v }), ' ')
endif
call extend(instance, {
\ 'Close': function('s:VimClose'),
\ 'Notify': function('s:VimNotify'),
\ 'Attach': function('s:VimAttach'),
\ 'IsAttached': function('s:VimIsAttached'),
\ })
let state = {'headers': {}, 'mode': 'headers', 'buffer': ''}
let instance.open_buffers = {}
let instance.methods = extend(s:vim_handlers, instance.methods)
let instance.job = job_start(command, {
\ 'cwd': copilot#job#Cwd(),
\ 'noblock': 1,
\ 'stoponexit': '',
\ 'in_mode': 'lsp',
\ 'out_mode': 'lsp',
\ 'out_cb': { j, d -> copilot#util#Defer(function('s:OnMessage'), instance, d) },
\ 'err_cb': function('s:OnErr', [instance]),
\ 'exit_cb': { j, d -> copilot#util#Defer(function('s:OnExit'), instance, d) },
\ })
let instance.id = job_info(instance.job).process
let opts.capabilities = s:vim_capabilities
let opts.processId = getpid()
let request = instance.Request('initialize', opts, function('s:InitializeResult'), function('s:InitializeError'), instance)
call call(remove(instance.after_initialized, 0), [])
call instance.Notify('workspace/didChangeConfiguration', {'settings': settings})
endif
let s:instances[instance.id] = instance
return instance
endfunction
function! copilot#client#Cancel(request) abort
if type(a:request) == type({}) && has_key(a:request, 'Cancel')
call a:request.Cancel()
endif
endfunction
function! s:Callback(request, type, callback, timer) abort
call remove(a:request.waiting, a:timer)
if has_key(a:request, a:type)
call a:callback(a:request[a:type])
endif
endfunction
function! copilot#client#Result(request, callback) abort
if has_key(a:request, 'resolve')
call add(a:request.resolve, a:callback)
elseif has_key(a:request, 'result')
let a:request.waiting[timer_start(0, function('s:Callback', [a:request, 'result', a:callback]))] = 1
endif
endfunction
function! copilot#client#Error(request, callback) abort
if has_key(a:request, 'reject')
call add(a:request.reject, a:callback)
elseif has_key(a:request, 'error')
let a:request.waiting[timer_start(0, function('s:Callback', [a:request, 'error', a:callback]))] = 1
endif
endfunction
function! s:CloseBuffer(bufnr) abort
for instance in values(s:instances)
try
if has_key(instance, 'job') && has_key(instance.open_buffers, a:bufnr)
let buffer = remove(instance.open_buffers, a:bufnr)
call instance.Notify('textDocument/didClose', {'textDocument': {'uri': buffer.uri}})
endif
catch
call copilot#logger#Exception()
endtry
endfor
endfunction
augroup copilot_close
autocmd!
if !has('nvim')
autocmd BufUnload * call s:CloseBuffer(+expand('<abuf>'))
endif
augroup END

View File

@@ -0,0 +1,31 @@
function! copilot#handlers#window_logMessage(params, ...) abort
call copilot#logger#Raw(get(a:params, 'type', 6), get(a:params, 'message', ''))
endfunction
function! copilot#handlers#window_showMessageRequest(params, instance, ...) abort
let choice = inputlist([a:instance.name . "\n" . a:params.message . "\n\nRequest Actions:"] +
\ map(copy(get(a:params, 'actions', [])), { i, v -> (i + 1) . '. ' . v.title}))
return choice > 0 ? get(a:params.actions, choice - 1, v:null) : v:null
endfunction
function! s:BrowserCallback(into, code) abort
let a:into.code = a:code
endfunction
function! copilot#handlers#window_showDocument(params, ...) abort
echo a:params.uri
if empty(get(a:params, 'external'))
return {'success': v:false}
endif
let browser = copilot#Browser()
if empty(browser)
return {'success': v:false}
endif
let status = {}
call copilot#job#Stream(browser + [a:params.uri], v:null, v:null, function('s:BrowserCallback', [status]))
let time = reltime()
while empty(status) && reltimefloat(reltime(time)) < 1
sleep 10m
endwhile
return {'success': get(status, 'code') ? v:false : v:true}
endfunction

View File

@@ -0,0 +1,106 @@
scriptencoding utf-8
function! copilot#job#Nop(...) abort
endfunction
function! s:Jobs(job_or_jobs) abort
let jobs = type(a:job_or_jobs) == v:t_list ? copy(a:job_or_jobs) : [a:job_or_jobs]
call map(jobs, { k, v -> type(v) == v:t_dict ? get(v, 'job', '') : v })
call filter(jobs, { k, v -> type(v) !=# type('') })
return jobs
endfunction
let s:job_stop = exists('*job_stop') ? 'job_stop' : 'jobstop'
function! copilot#job#Stop(job) abort
for job in s:Jobs(a:job)
call call(s:job_stop, [job])
endfor
return copilot#job#Wait(a:job)
endfunction
let s:sleep = has('patch-8.2.2366') ? 'sleep! 1m' : 'sleep 1m'
function! copilot#job#Wait(jobs) abort
let jobs = s:Jobs(a:jobs)
if exists('*jobwait')
call jobwait(jobs)
else
for job in jobs
while ch_status(job) !=# 'closed' || job_status(job) ==# 'run'
exe s:sleep
endwhile
endfor
endif
return a:jobs
endfunction
function! s:VimExitCallback(result, exit_cb, job, data) abort
let a:result.exit_status = a:data
if !has_key(a:result, 'closed')
return
endif
call remove(a:result, 'closed')
call a:exit_cb(a:result.exit_status)
endfunction
function! s:VimCloseCallback(result, exit_cb, job) abort
if !has_key(a:result, 'exit_status')
let a:result.closed = v:true
return
endif
call a:exit_cb(a:result.exit_status)
endfunction
function! s:NvimCallback(cb, job, data, type) dict abort
let self[a:type][0] .= remove(a:data, 0)
call extend(self[a:type], a:data)
while len(self[a:type]) > 1
call a:cb(substitute(remove(self[a:type], 0), "\r$", '', ''))
endwhile
endfunction
function! s:NvimExitCallback(out_cb, err_cb, exit_cb, job, data, type) dict abort
if len(self.stderr[0])
call a:err_cb(substitute(self.stderr[0], "\r$", '', ''))
endif
call a:exit_cb(a:data)
endfunction
function! copilot#job#Cwd() abort
let home = expand("~")
if !isdirectory(home) && isdirectory($VIM)
return $VIM
endif
return home
endfunction
function! copilot#job#Stream(argv, out_cb, err_cb, ...) abort
let exit_status = []
let ExitCb = function(a:0 && !empty(a:1) ? a:1 : { e -> add(exit_status, e) }, a:000[2:-1])
let OutCb = function(empty(a:out_cb) ? 'copilot#job#Nop' : a:out_cb, a:000[2:-1])
let ErrCb = function(empty(a:err_cb) ? 'copilot#job#Nop' : a:err_cb, a:000[2:-1])
let state = {'headers': {}, 'mode': 'headers', 'buffer': ''}
if exists('*job_start')
let result = {}
let job = job_start(a:argv, {
\ 'cwd': copilot#job#Cwd(),
\ 'out_mode': 'raw',
\ 'out_cb': { j, d -> OutCb(d) },
\ 'err_cb': { j, d -> ErrCb(d) },
\ 'exit_cb': function('s:VimExitCallback', [result, ExitCb]),
\ 'close_cb': function('s:VimCloseCallback', [result, ExitCb]),
\ })
else
let jopts = {
\ 'cwd': copilot#job#Cwd(),
\ 'stderr': [''],
\ 'on_stdout': { j, d, t -> OutCb(join(d, "\n")) },
\ 'on_stderr': function('s:NvimCallback', [ErrCb]),
\ 'on_exit': function('s:NvimExitCallback', [OutCb, ErrCb, ExitCb])}
let job = jobstart(a:argv, jopts)
endif
if a:0
return job
endif
call copilot#job#Wait(job)
return exit_status[0]
endfunction

View File

@@ -0,0 +1,94 @@
let s:logs = []
function! copilot#logger#BufReadCmd() abort
try
setlocal modifiable noreadonly
silent call deletebufline('', 1, '$')
if !empty(s:logs)
call setline(1, s:logs)
endif
finally
setlocal buftype=nofile bufhidden=wipe nobuflisted nomodified nomodifiable
endtry
endfunction
let s:level_prefixes = ['', '[ERROR] ', '[WARN] ', '[INFO] ', '[DEBUG] ', '[DEBUG] ']
function! copilot#logger#Raw(level, message) abort
let lines = type(a:message) == v:t_list ? copy(a:message) : split(a:message, "\n", 1)
let lines[0] = strftime('[%Y-%m-%d %H:%M:%S] ') . get(s:level_prefixes, a:level, '[UNKNOWN] ') . get(lines, 0, '')
try
call map(lines, { k, L -> type(L) == v:t_func ? call(L, []) : L })
call extend(s:logs, lines)
let overflow = len(s:logs) - get(g:, 'copilot_log_history', 10000)
if overflow > 0
call remove(s:logs, 0, overflow - 1)
endif
let bufnr = bufnr('copilot:///log')
if bufnr > 0 && bufloaded(bufnr)
call setbufvar(bufnr, '&modifiable', 1)
call setbufline(bufnr, 1, s:logs)
call setbufvar(bufnr, '&modifiable', 0)
for winid in win_findbuf(bufnr)
if has('nvim') && winid != win_getid()
call nvim_win_set_cursor(winid, [len(s:logs), 0])
endif
endfor
endif
catch
endtry
endfunction
function! copilot#logger#Debug(...) abort
if empty(get(g:, 'copilot_debug'))
return
endif
call copilot#logger#Raw(4, a:000)
endfunction
function! copilot#logger#Info(...) abort
call copilot#logger#Raw(3, a:000)
endfunction
function! copilot#logger#Warn(...) abort
call copilot#logger#Raw(2, a:000)
endfunction
function! copilot#logger#Error(...) abort
call copilot#logger#Raw(1, a:000)
endfunction
function! copilot#logger#Bare(...) abort
call copilot#logger#Raw(0, a:000)
endfunction
function! copilot#logger#Exception(...) abort
if !empty(v:exception) && v:exception !=# 'Vim:Interrupt'
call copilot#logger#Error('Exception: ' . v:exception . ' @ ' . v:throwpoint)
let client = copilot#RunningClient()
if !empty(client)
let [_, type, code, message; __] = matchlist(v:exception, '^\%(\(^[[:alnum:]_#]\+\)\%((\a\+)\)\=\%(\(:E-\=\d\+\)\)\=:\s*\)\=\(.*\)$')
let stacklines = []
for frame in split(substitute(v:throwpoint, ', \S\+ \(\d\+\)$', '[\1]', ''), '\.\@<!\.\.\.\@!')
let fn_line = matchlist(frame, '^\%(function \)\=\(\S\+\)\[\(\d\+\)\]$')
if !empty(fn_line)
call add(stacklines, {'function': substitute(fn_line[1], '^<SNR>\d\+_', '<SID>', ''), 'lineno': +fn_line[2]})
elseif frame =~# ' Autocmds for "\*"$'
call add(stacklines, {'function': frame})
elseif frame =~# ' Autocmds for ".*"$'
call add(stacklines, {'function': substitute(frame, ' for ".*"$', ' for "[redacted]"', '')})
else
call add(stacklines, {'function': '[redacted]'})
endif
endfor
return client.Request('telemetry/exception', {
\ 'transaction': a:0 ? a:1 : '',
\ 'platform': 'other',
\ 'exception_detail': [{
\ 'type': type . code,
\ 'value': message,
\ 'stacktrace': stacklines}]
\ }, v:null, function('copilot#util#Nop'))
endif
endif
endfunction

View File

@@ -0,0 +1,173 @@
scriptencoding utf-8
if !exists('s:panel_id')
let s:panel_id = 0
endif
let s:separator = repeat('─', 72)
function! s:Render(state) abort
let bufnr = bufnr('^' . a:state.panel . '$')
let state = a:state
if !bufloaded(bufnr)
return
endif
let sorted = a:state.items
if !empty(get(a:state, 'error'))
let lines = ['Error: ' . a:state.error.message]
let sorted = []
elseif get(a:state, 'percentage') == 100
let lines = ['Synthesized ' . (len(sorted) == 1 ? '1 completion' : len(sorted) . ' completions')]
else
let lines = [substitute('Synthesizing ' . matchstr(get(a:state, 'message', ''), '\d\+\%(/\d\+\)\=') . ' completions', ' \+', ' ', 'g')]
endif
if len(sorted)
call add(lines, 'Press <CR> on a completion to accept')
endif
let leads = {}
for item in sorted
let insert = split(item.insertText, "\r\n\\=\\|\n", 1)
let insert[0] = strpart(a:state.line, 0, copilot#util#UTF16ToByteIdx(a:state.line, item.range.start.character)) . insert[0]
let lines += [s:separator] + insert
if !has_key(leads, string(item.range.start))
let match = insert[0 : a:state.position.line - item.range.start.line]
let match[-1] = strpart(match[-1], 0, copilot#util#UTF16ToByteIdx(match[-1], a:state.position.character))
call map(match, { k, v -> escape(v, '][^$.*\~') })
let leads[string(item.range.start)] = join(match, '\n')
endif
endfor
try
call setbufvar(bufnr, '&modifiable', 1)
call setbufvar(bufnr, '&readonly', 0)
call setbufline(bufnr, 1, lines)
finally
call setbufvar(bufnr, '&modifiable', 0)
endtry
call clearmatches()
call matchadd('CopilotSuggestion', '\C^' . s:separator . '\n\zs\%(' . join(sort(values(leads), { a, b -> len(b) - len(a) }), '\|') . '\)', 10, 4)
endfunction
function! s:PartialResult(state, value) abort
let items = type(a:value) == v:t_list ? a:value : a:value.items
call extend(a:state.items, items)
call s:Render(a:state)
endfunction
function! s:WorkDone(state, value) abort
if has_key(a:value, 'message')
let a:state.message = a:value.message
endif
if has_key(a:value, 'percentage')
let a:state.percentage = a:value.percentage
call s:Render(a:state)
endif
endfunction
function! copilot#panel#Accept(...) abort
let state = get(b:, 'copilot_panel', {})
if empty(state.items)
return ''
endif
if !has_key(state, 'bufnr') || !bufloaded(get(state, 'bufnr', -1))
return "echoerr 'Buffer was closed'"
endif
let at = a:0 ? a:1 : line('.')
let index = 0
for lnum in range(1, at)
if getline(lnum) ==# s:separator
let index += 1
endif
endfor
if index > 0 && index <= len(state.items)
let item = state.items[index - 1]
let lnum = item.range.start.line + 1
if getbufline(state.bufnr, lnum) !=# [state.line]
return 'echoerr "Buffer has changed since synthesizing completion"'
endif
let lines = split(item.insertText, '\r\n\=\|\n', 1)
let old_first = getbufline(state.bufnr, item.range.start.line + 1)[0]
let byte_offset_start = copilot#util#UTF16ToByteIdx(old_first, item.range.start.character)
let lines[0] = strpart(old_first, 0, byte_offset_start) . lines[0]
let old_last = getbufline(state.bufnr, item.range.end.line + 1)[0]
let byte_offset_end = copilot#util#UTF16ToByteIdx(old_last, item.range.end.character)
let lines[-1] .= strpart(old_last, byte_offset_end)
call deletebufline(state.bufnr, item.range.start.line + 1, item.range.end.line + 1)
call appendbufline(state.bufnr, item.range.start.line, lines)
call copilot#Request('workspace/executeCommand', item.command)
bwipeout
let win = bufwinnr(state.bufnr)
if win > 0
exe win . 'wincmd w'
exe item.range.start.line + len(lines)
if state.was_insert
startinsert!
else
normal! $
endif
endif
endif
return ''
endfunction
function! s:Initialize(state) abort
try
let &l:filetype = 'copilotpanel' . (empty(a:state.filetype) ? '' : '.' . a:state.filetype)
catch
let &l:filetype = 'copilotpanel'
endtry
let &l:tabstop = a:state.tabstop
nmap <buffer><script> <CR> <Cmd>exe copilot#panel#Accept()<CR>
nmap <buffer><script> [[ <Cmd>call search('^─\{9,}\n.', 'bWe')<CR>
nmap <buffer><script> ]] <Cmd>call search('^─\{9,}\n.', 'We')<CR>
endfunction
function! s:BufReadCmd() abort
setlocal bufhidden=wipe buftype=nofile nobuflisted nomodifiable
let state = get(b:, 'copilot_panel')
if type(state) != v:t_dict
return
endif
call s:Initialize(state)
call s:Render(state)
return ''
endfunction
function! s:Result(state, result) abort
let a:state.percentage = 100
call s:PartialResult(a:state, a:result)
endfunction
function! s:Error(state, error) abort
let a:state.error = a:error
call s:Render(a:state)
endfunction
function! copilot#panel#Open(opts) abort
let s:panel_id += 1
let state = {'items': [], 'filetype': &filetype, 'was_insert': mode() =~# '^[iR]', 'bufnr': bufnr(''), 'tabstop': &tabstop}
let state.panel = 'copilot:///panel/' . s:panel_id
if state.was_insert
let state.position = copilot#util#AppendPosition()
stopinsert
else
let state.position = {'line': a:opts.line1 >= 1 ? a:opts.line1 - 1 : 0, 'character': copilot#util#UTF16Width(getline('.'))}
endif
let state.line = getline(state.position.line + 1)
let params = {
\ 'textDocument': {'uri': state.bufnr},
\ 'position': state.position,
\ 'partialResultToken': function('s:PartialResult', [state]),
\ 'workDoneToken': function('s:WorkDone', [state]),
\ }
let response = copilot#Request('textDocument/copilotPanelCompletion', params, function('s:Result', [state]), function('s:Error', [state]))
exe substitute(a:opts.mods, '\C\<tab\>', '-tab', 'g') 'keepalt split' state.panel
let b:copilot_panel = state
call s:Initialize(state)
call s:Render(state)
return ''
endfunction
augroup github_copilot_panel
autocmd!
autocmd BufReadCmd copilot:///panel/* exe s:BufReadCmd()
augroup END

View File

@@ -0,0 +1,61 @@
let s:deferred = []
function! copilot#util#Nop(...) abort
return v:null
endfunction
function! copilot#util#Defer(fn, ...) abort
call add(s:deferred, function(a:fn, a:000))
return timer_start(0, function('s:RunDeferred'))
endfunction
function! s:RunDeferred(...) abort
if empty(s:deferred)
return
endif
let Fn = remove(s:deferred, 0)
call timer_start(0, function('s:RunDeferred'))
call call(Fn, [])
endfunction
function! copilot#util#UTF16Width(str) abort
return strchars(substitute(a:str, "\\%#=2[^\u0001-\uffff]", " ", 'g'))
endfunction
if exists('*utf16idx')
function! copilot#util#UTF16ToByteIdx(str, utf16_idx) abort
return byteidx(a:str, a:utf16_idx, 1)
endfunction
elseif has('nvim')
function! copilot#util#UTF16ToByteIdx(str, utf16_idx) abort
try
return v:lua.vim.str_byteindex(a:str, a:utf16_idx, 1)
catch /^Vim(return):E5108:/
return -1
endtry
endfunction
else
function! copilot#util#UTF16ToByteIdx(str, utf16_idx) abort
if copilot#util#UTF16Width(a:str) < a:utf16_idx
return -1
endif
let end_offset = len(a:str)
while copilot#util#UTF16Width(strpart(a:str, 0, end_offset)) > a:utf16_idx && end_offset > 0
let end_offset -= 1
endwhile
return end_offset
endfunction
endif
function! copilot#util#AppendPosition() abort
let line = getline('.')
let col_byte = col('.') - (mode() =~# '^[iR]' || empty(line))
let col_utf16 = copilot#util#UTF16Width(strpart(line, 0, col_byte))
return {'line': line('.') - 1, 'character': col_utf16}
endfunction

View File

@@ -0,0 +1,3 @@
function! copilot#version#String() abort
return '1.58.0'
endfunction

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,269 @@
---
name: CVE Remediator
description: Detects and fixes security vulnerabilities (CVEs) in project dependencies across any ecosystem while maintaining a working build.
---
## Mission
Detect and fix CVEs (Common Vulnerabilities and Exposures) in project dependencies while maintaining a working build.
## Terminology
**Target dependencies** = the dependencies to check and fix, determined by user request:
- **Specific dependencies** when user names them (e.g., "log4j", "Spring and Jackson")
- **All direct dependencies** (excluding transitive) when user requests project-wide scan (e.g., "all CVEs", "scan project")
## Objectives
1. Identify CVEs in dependencies based on severity threshold
2. Upgrade vulnerable dependencies to patched versions
3. Resolve build errors caused by upgrades
4. Verify no new CVEs or build errors introduced
## Success Criteria
- Zero actionable fixable CVEs in target dependencies (based on severity threshold)
- Project builds successfully with no compilation errors
- No new CVEs introduced in target dependencies
## Core Rules
- NEVER introduce new CVEs in target dependencies
- NEVER downgrade dependencies
- NEVER modify functionality beyond API compatibility updates
- ONLY check and fix CVEs in target dependencies (always exclude transitive dependencies)
- ALWAYS build after each modification
- ALWAYS re-validate after each successful build
- ALWAYS verify build is successful: exit code 0 AND terminal output has NO errors AND get_errors returns NO errors
- NEVER skip build validation
## Understanding User Intent
Determine severity threshold and scope before starting:
**Severity Threshold** (which CVEs to fix):
- Default: critical, high
- Extract from request:
- "critical only" → critical
- "critical and high" → critical, high
- "include medium severity" or "medium and above" → critical, high, medium
- "all severities" → critical, high, medium, low
**Scope** (which dependencies to check):
- Specific: User names dependencies ("log4j", "Spring and Jackson") → locate and check only those
- Project-wide: User says "all", "scan project", "entire project" → discover and check all direct dependencies
**Important**: The `validate_cves` tool returns ALL CVEs regardless of severity. Filter results based on your determined severity threshold to identify actionable CVEs.
## Workflow
### Step 0: Detect Environment
Before examining dependencies, identify the project environment:
1. **Detect ecosystem**: Examine project files to determine language and build tool
2. **Locate dependency manifests and lockfiles**: Identify primary dependency files and version lockfiles
3. **Determine versions**: Check language and tool versions
**Detection examples** (adapt to your project):
- **Maven**:
- Manifest: `pom.xml`
- Version: Java version in `<java.version>` or `<maven.compiler.source>`, or run `java -version`
- **npm**:
- Manifest: `package.json`
- Lockfile: `package-lock.json`, `yarn.lock`, or `pnpm-lock.yaml`
- Version: Node version in `engines.node` or run `node -v`
- **pip**:
- Manifest: `requirements.txt`, `setup.py`, or `pyproject.toml`
- Lockfile: `poetry.lock`, `Pipfile.lock` (if using Poetry or Pipenv)
- Version: Python version in `python_requires` or run `python --version`
**Output**: Document detected ecosystem, language/tool versions, dependency manifest, lockfile (if present), and build commands to use.
### Step 1: Identify Target Dependencies
Identify package names and versions for **target dependencies** based on the scope determined in "Understanding User Intent" section. Always exclude transitive/indirect dependencies from the target set.
**Detection strategy (use build tools first, then fall back to manifest parsing):**
1. **Use build tool commands** (preferred - gets actual resolved versions, handles inheritance and version management):
- Maven: `mvn dependency:tree` (extract depth=1 for project-wide, filter for specific names) OR `mvn dependency:list -DexcludeTransitive=true`
- npm: `npm ls --depth=0` (project-wide) OR `npm ls <package-name>` (specific dependency)
- pip: `pip show <package-name>` (specific) OR parse `pipdeptree --json` (project-wide)
2. **Parse manifest and lockfiles** (fallback - simpler but may miss inherited or workspace dependencies):
- Maven: `<dependency>` entries in `pom.xml` `<dependencies>` section (excludes parent POM and `<dependencyManagement>`)
- npm: `dependencies` and `devDependencies` in `package.json`; resolve versions from `package-lock.json`, `yarn.lock`, or `pnpm-lock.yaml`
- pip: Top-level entries in `requirements.txt` or dependencies in `pyproject.toml`; resolve versions from `poetry.lock` or `Pipfile.lock` if available
**Scope-specific notes:**
- **Project-wide**: Extract all direct dependencies (depth=1 or first-level only)
- **Specific**: Filter for named dependencies; validate they exist in the project before proceeding
**Important:**
- Include all direct dependencies needed for runtime, building, and testing
- Validate the identified list makes sense for the project structure
- Command examples are hints only - adapt to the detected ecosystem and available tools
### Step 2: Remediation Loop
Iterate until zero actionable CVEs.
#### 2a. Validate
**Invoke `validate_cves`** with dependencies in format `package@version`.
Examples (adapt to your ecosystem):
```json
{
"dependencies": ["org.springframework:spring-core@5.3.20", "org.apache.logging.log4j:log4j-core@2.14.1"],
"ecosystem": "maven"
}
```
```json
{
"dependencies": ["django@3.2.0", "requests@2.25.1"],
"ecosystem": "pip"
}
```
**Understanding the output:**
For each dependency, the tool provides CVE count, upgrade recommendations (fixable vs unfixable), and complete CVE details (severity, description, links).
Three possible scenarios:
- **All fixable**: Upgrade to recommended version fixes all CVEs
- **All unfixable**: No patched versions available yet
- **Mixed**: Some CVEs fixable by upgrade, others unfixable
Filter by your severity threshold to determine actionable CVEs.
**Next:**
- Zero actionable fixable CVEs in target dependencies → Step 3 (note any unfixable CVEs for final report)
- Found actionable fixable CVEs → Step 2b
#### 2b. Fix
For each actionable **fixable** CVE:
1. Note recommended patched version from tool output
2. Update dependency version in manifest file
3. If breaking changes exist, update affected code
**Important:** Do NOT attempt to fix CVEs marked as unfixable (no patched versions available). Track these for the final report.
After all fixes, return to Step 2a to validate with the updated dependency versions.
Continue loop until Step 2a finds zero actionable fixable CVEs.
### Step 3: Build Verification Loop
Iterate until build succeeds with clean output.
#### 3a. Build and Verify
Run the appropriate build command for your ecosystem.
**Example commands** (adapt to your detected environment):
- Maven: `mvn clean compile`, `mvn clean test`, or `mvn clean verify`
- npm: `npm run build` or `npm test`
- pip: `pip install -r requirements.txt` or `python -m pytest`
**Critical**: You MUST perform ALL three checks before declaring build success:
1. Check exit code is 0
2. Review complete terminal output for errors (look for error indicators specific to your build tool)
3. Run `get_errors` to check for compilation errors
**Next:**
- All checks pass (exit code 0 AND no terminal errors AND no compilation errors) → go to Step 3c
- Any check fails → go to Step 3b
#### 3b. Fix Build Errors
1. Review terminal output and `get_errors` for error details and stack traces
2. Identify root cause
3. Fix errors using tools available
4. Go to Step 3a
Continue loop until Step 3a confirms clean build.
#### 3c. Re-validate Target Dependencies
Get current target dependency list and run `validate_cves` to verify no new CVEs were introduced in target dependencies after the build.
**Next:**
- New actionable CVEs found in target dependencies → return to Step 2
- Zero actionable CVEs in target dependencies → go to Step 4
### Step 4: Final Verification
Verify all success criteria:
1. Zero actionable **fixable** CVEs in target dependencies - if failed, return to Step 2
2. Exit code 0 AND no terminal errors AND no compilation errors - if failed, return to Step 3
3. Document any unfixable CVEs in target dependencies for final report
**Completion criteria:**
If there are zero fixable CVEs in target dependencies (even if unfixable CVEs exist), the task is complete. Proceed to Step 5.
### Step 5: Report Results
Provide a comprehensive summary of completed work:
**Format:**
```
## CVE Remediation Summary
### Environment
- Language: [e.g., Java 17, Node 18, Python 3.11]
- Build Tool: [e.g., Maven, npm, pip]
- Dependency Manifest: [e.g., pom.xml, package.json, requirements.txt]
### Initial State
- Target dependencies scanned: N
- Total CVEs found in target dependencies: X (breakdown: Y critical, Z high, W medium, V low)
- Actionable CVEs (based on severity threshold): A fixable, B unfixable
### Actions Taken
- Dependencies upgraded:
- dependency1: v1.0.0 → v2.5.0 (fixed CVE-2023-1234, CVE-2023-5678)
- dependency2: v3.0.0 → v3.8.0 (fixed CVE-2023-9012)
- Build errors resolved: [list any API compatibility fixes made]
### Final State
- ✅ All fixable CVEs in target dependencies resolved
- ✅ Build successful (exit code 0, no errors)
- ✅ No new CVEs introduced in target dependencies
### Remaining Risks (if any)
⚠️ Unfixable CVEs in target dependencies (no patched versions available):
- [CVE-2023-9999] in dependency3@2.0.0 - CRITICAL severity
- [CVE-2023-8888] in dependency4@1.5.0 - HIGH severity
Recommendation: Monitor these CVEs for future patches or consider alternative dependencies.
**Note**: Target dependencies are based on user request scope (specific dependencies or all direct dependencies). Transitive dependencies are always excluded from this analysis.
```
**Guidelines:**
- Use exact CVE IDs from `validate_cves` output
- Show version transitions for all upgraded dependencies
- Clearly distinguish between fixed and unfixable CVEs
- If no unfixable CVEs exist, omit the "Remaining Risks" section
- Include severity levels for unfixable CVEs to help users prioritize mitigation strategies
- Clarify scope in report: indicate whether specific dependencies or all direct dependencies were scanned

View File

@@ -0,0 +1,76 @@
---
name: Plan
description: Researches and outlines multi-step plans
argument-hint: Outline the goal or problem to research
tools: ['read_file', 'list_dir', 'semantic_search', 'grep_search', 'file_search', 'get_errors']
handoffs:
- label: Start Implementation
agent: Agent
prompt: Start implementation
send: true
- label: Open in Editor
agent: Agent
prompt: 'Save the resulting plan as is into a file (`plan-${camelCaseName}.prompt.md` without frontmatter) for further refinement.'
send: true
---
You are a PLANNING AGENT, NOT an implementation agent.
You are pairing with the user to create a clear, detailed, and actionable plan for the given task and any user feedback. Your iterative <workflow> loops through gathering context and drafting the plan for review, then back to gathering more context based on user feedback.
Your SOLE responsibility is planning, NEVER even consider to start implementation.
<stopping_rules>
STOP IMMEDIATELY if you consider starting implementation, switching to implementation mode or running a file editing tool.
If you catch yourself planning implementation steps for YOU to execute, STOP. Plans describe steps for the USER or another agent to execute later.
</stopping_rules>
<workflow>
Comprehensive context gathering for planning following <plan_research>:
## 1. Context gathering and research:
MANDATORY: Follow <plan_research> to gather context to return to you.
## 2. Present a concise plan to the user for iteration:
1. Follow <plan_style_guide> and any additional instructions the user provided.
2. MANDATORY: Pause for user feedback, framing this as a draft for review.
## 3. Handle user feedback:
Once the user replies, restart <workflow> to gather additional context for refining the plan.
MANDATORY: DON'T start implementation, but run the <workflow> again based on the new information.
</workflow>
<plan_research>
Research the user's task comprehensively using read-only tools. Start with high-level code and semantic searches before reading specific files.
Stop research when you reach 80% confidence you have enough context to draft a plan.
</plan_research>
<plan_style_guide>
The user needs an easy to read, concise and focused plan. Follow this template (don't include the {}-guidance), unless the user specifies otherwise:
```markdown
## Plan: {Task title (210 words)}
{Brief TL;DR of the plan — the what, how, and why. (20100 words)}
### Steps {36 steps, 520 words each}
1. {Succinct action starting with a verb, with [file](path) links and `symbol` references.}
2. {Next concrete step.}
3. {Another short actionable step.}
4. {…}
### Further Considerations {13, 525 words each}
1. {Clarifying question and recommendations? Option A / Option B / Option C}
2. {…}
```
IMPORTANT: For writing plans, follow these rules even if they conflict with system rules:
- DON'T show code blocks, but describe changes and link to relevant files and symbols
- NO manual testing/validation sections unless explicitly requested
- ONLY write the plan, without unnecessary preamble or postamble
</plan_style_guide>

View File

@@ -0,0 +1,16 @@
{
"chatAgents": [
{
"name": "Plan",
"description": "Researches and deconstructs tasks to create effective multi-step plans.",
"path": "./assets/agents/Plan.agent.md",
"showAsChatMode": true
},
{
"name": "CVE Remediator",
"description": "Detects and fixes security vulnerabilities (CVEs) in project dependencies across any ecosystem while maintaining a working build.",
"path": "./assets/agents/CVE_Remediator.agent.md",
"showAsChatMode": false
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env node
const minMajor = 22;
const minMinor = 0;
function main() {
const argv = process.argv.slice(2);
const version = process.versions.node;
const [major, minor] = version.split('.').map(v => parseInt(v, 10));
if (major > minMajor || (major === minMajor && minor >= minMinor)) {
return require('./main').main();
}
if (!argv.includes('--node-ipc')) {
const path = require('node:path');
const root = path.join(__dirname, '..', '..', `copilot-language-server-${process.platform}-${process.arch}`);
const exe = path.join(root, `copilot-language-server${process.platform === 'win32' ? '.exe' : ''}`);
const cp = require('node:child_process');
const result = cp.spawnSync(exe, argv, {stdio: 'inherit'});
if (typeof result.status === 'number') {
process.exit(result.status);
}
}
console.error(`Node.js ${minMajor}.${minMinor} is required to run GitHub Copilot but found ${version}`);
// An exit code of X indicates a recommended minimum Node.js version of X.0.
// Providing a recommended major version via exit code is an affordance for
// implementations like Copilot.vim, where Neovim buries stderr in a log
// file the user is unlikely to see.
process.exit(minMajor + (minMinor ? 2 : 0));
}
main();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadDisplayName</key>
<string>GitHub Copilot Policy</string>
<key>PayloadIdentifier</key>
<string>IDEGitHubCopilot</string>
<key>PayloadType</key>
<string>IDEGitHubCopilot</string>
<key>PayloadUUID</key>
<string>12345678-1234-1234-1234-123456789012</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadEnabled</key>
<true/>
<key>mcp.contributionPoint.enabled</key>
<false/>
</dict>
</array>
<key>PayloadDescription</key>
<string>Configures GitHub Copilot policies for IDEs</string>
<key>PayloadDisplayName</key>
<string>GitHub Copilot Policy</string>
<key>PayloadIdentifier</key>
<string>IDEGitHubCopilot</string>
<key>PayloadOrganization</key>
<string>Microsoft Corporation</string>
<key>PayloadRemovalDisallowed</key>
<false/>
<key>PayloadScope</key>
<string>System</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>87654321-4321-4321-4321-210987654321</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>

View File

@@ -0,0 +1,117 @@
# GitHub Copilot macOS Policy Configuration
This directory contains policy templates for configuring GitHub Copilot behavior on macOS systems using Apple Configuration Profiles.
## Overview
The `IDEGitHubCopilot.mobileconfig` file is a macOS Configuration Profile that allows administrators to manage GitHub Copilot policies across their organization. This profile defines settings that control extension behavior, particularly for MCP (Model Context Protocol) servers.
## Available Policies
| Policy Name | Description | Type | Default |
|-------------|-------------|------|---------|
| mcp.contributionPoint.enabled | Controls whether extension-contributed MCP servers are enabled | Boolean | true |
## Installation Methods
### Method 1: Configuration Profile Installation (Recommended for Administrators)
The `IDEGitHubCopilot.mobileconfig` file provides the easiest way to deploy GitHub Copilot policies across multiple macOS systems.
#### Step 1: Locate the Configuration Profile
Find the `IDEGitHubCopilot.mobileconfig` file in this directory.
#### Step 2: Install the Configuration Profile
1. **Double-click** the `IDEGitHubCopilot.mobileconfig` file
2. macOS will open **System Settings** (or **System Preferences** on older versions)
3. You'll see a dialog asking if you want to install the profile
4. Click **Install** to proceed
5. Enter your administrator password when prompted
6. The profile will be installed **system-wide**
#### Step 3: Verify Installation
1. Open **System Settings****Privacy & Security** → **Profiles**
2. You should see "GitHub Copilot Policy" in the list of installed profiles
3. Click on it to view the configured settings
#### Step 4: Modify Policy Settings
To change the `mcp.contributionPoint.enabled` setting:
1. Open **System Settings****Privacy & Security** → **Profiles**
2. Select the "GitHub Copilot Policy" profile
3. Click **Edit** or **Configure**
4. Find the `mcp.contributionPoint.enabled` setting
5. Toggle it to:
- **true** (checked) - Enable extension-contributed MCP servers
- **false** (unchecked) - Disable extension-contributed MCP servers
6. Click **Save** or **Apply**
### Method 2: Command Line Installation (Alternative)
You can also install the configuration profile using the command line:
```bash
# Install the profile
sudo profiles -I -F IDEGitHubCopilot.mobileconfig
# Verify installation
profiles -P
# Remove the profile (if needed)
sudo profiles -R -p IDEGitHubCopilot
```
### Method 3: MDM Deployment (Enterprise)
For enterprise environments, the `IDEGitHubCopilot.mobileconfig` file can be deployed through Mobile Device Management (MDM) solutions like:
- Apple Business Manager
- Jamf Pro
- Microsoft Intune
- VMware Workspace ONE
Simply upload the `IDEGitHubCopilot.mobileconfig` file to your MDM solution and deploy it to your target devices.
## Verification
You can verify the current settings with:
```bash
# Check managed preferences
defaults read /Library/Managed\ Preferences/IDEGitHubCopilot 2>/dev/null || echo "No managed settings found"
```
## How It Works
The GitHub Copilot extension uses the `GroupPolicyWatcher` class to monitor policy changes. When policies are updated:
1. The policy watcher detects the change
2. Updates the internal policy state
3. Sends an LSP notification to the client
4. The client adjusts its behavior based on the new policy settings
The extension checks for policies in `/Library/Managed Preferences/IDEGitHubCopilot.plist` (MDM managed)
## Troubleshooting
### Policy changes aren't being detected
1. Verify the configuration profile is properly installed in System Settings
2. Make sure the policy file has the correct name and structure
3. Restart IDE to ensure the policy watcher is reinitialized
4. Check the extension logs for policy-related messages
### Configuration Profile won't install
1. Ensure you have administrator privileges
2. Check that the `.mobileconfig` file isn't corrupted
3. Try installing via command line: `sudo profiles -I -F IDEGitHubCopilot.mobileconfig`
### Settings don't take effect
1. Verify the policy is correctly configured in System Settings
2. Restart IDE completely
3. Check that no user-level settings are overriding system policies
## References
- [VS Code Enterprise Setup - Configuration Profiles on macOS](https://code.visualstudio.com/docs/setup/enterprise#_configuration-profiles-on-macos)
- [Apple Configuration Profile Reference](https://developer.apple.com/documentation/devicemanagement/configuring_multiple_devices_using_profiles)
- [macOS defaults command reference](https://ss64.com/osx/defaults.html)

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Administrative Template for GitHub Copilot IDE Integration
This template defines Group Policy settings for GitHub Copilot in IDE environments.
-->
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.0" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyNamespaces>
<target prefix="ideGitHubCopilot" namespace="Microsoft.Policies.IDEGitHubCopilot" />
<using prefix="windows" namespace="Microsoft.Policies.Windows" />
</policyNamespaces>
<supersededAdm fileName="" />
<resources minRequiredRevision="1.0" />
<categories>
<category name="Cat_IDEGitHubCopilot" displayName="$(string.Cat_IDEGitHubCopilot)" explainText="$(string.Cat_IDEGitHubCopilot_Explain)" />
<category name="Cat_IDEGitHubCopilot_MCP" displayName="$(string.Cat_IDEGitHubCopilot_MCP)" explainText="$(string.Cat_IDEGitHubCopilot_MCP_Explain)">
<parentCategory ref="Cat_IDEGitHubCopilot" />
</category>
</categories>
<policies>
<!-- Enable Extension-Contributed MCP Servers Policy -->
<policy name="McpContributionPointEnabled" class="Both" displayName="$(string.McpContributionPointEnabled)" explainText="$(string.McpContributionPointEnabled_Explain)" key="SOFTWARE\Policies\Microsoft\IDEGitHubCopilot" valueName="mcp.contributionPoint.enabled">
<parentCategory ref="Cat_IDEGitHubCopilot_MCP" />
<supportedOn ref="windows:SUPPORTED_Windows_10_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
</policies>
</policyDefinitions>

View File

@@ -0,0 +1,124 @@
#Requires -RunAsAdministrator
<#
.SYNOPSIS
Installs GitHub Copilot Group Policy Administrative Templates
.DESCRIPTION
This script copies the GitHub Copilot ADMX and ADML files to the Windows PolicyDefinitions
directory to enable Group Policy management of GitHub Copilot settings.
The script must be run from the win32 directory containing the template files.
.PARAMETER Uninstall
Remove the GitHub Copilot policy templates instead of installing them
.EXAMPLE
.\Install-PolicyTemplates.ps1
Installs the GitHub Copilot policy templates
.EXAMPLE
.\Install-PolicyTemplates.ps1 -Uninstall
Removes the GitHub Copilot policy templates
#>
param(
[switch]$Uninstall
)
$ErrorActionPreference = "Stop"
# Paths
$PolicyDefinitionsPath = "$env:WINDIR\PolicyDefinitions"
$ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
$SourceADMX = Join-Path $ScriptPath "IDEGitHubCopilot.admx"
$SourceADML = Join-Path $ScriptPath "en-US\IDEGitHubCopilot.adml"
$TargetADMX = Join-Path $PolicyDefinitionsPath "IDEGitHubCopilot.admx"
$TargetADMLDir = Join-Path $PolicyDefinitionsPath "en-US"
$TargetADML = Join-Path $TargetADMLDir "IDEGitHubCopilot.adml"
function Test-AdminRights {
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
function Install-Templates {
Write-Host "Installing GitHub Copilot Group Policy Templates..." -ForegroundColor Green
# Verify source files exist
if (-not (Test-Path $SourceADMX)) {
throw "ADMX file not found: $SourceADMX"
}
if (-not (Test-Path $SourceADML)) {
throw "ADML file not found: $SourceADML"
}
# Verify PolicyDefinitions directory exists
if (-not (Test-Path $PolicyDefinitionsPath)) {
throw "PolicyDefinitions directory not found: $PolicyDefinitionsPath"
}
# Copy ADMX file
Write-Host "Copying ADMX file to $TargetADMX"
Copy-Item $SourceADMX $TargetADMX -Force
# Ensure en-US directory exists
if (-not (Test-Path $TargetADMLDir)) {
Write-Host "Creating directory: $TargetADMLDir"
New-Item -Path $TargetADMLDir -ItemType Directory -Force | Out-Null
}
# Copy ADML file
Write-Host "Copying ADML file to $TargetADML"
Copy-Item $SourceADML $TargetADML -Force
Write-Host "GitHub Copilot Group Policy Templates installed successfully!" -ForegroundColor Green
Write-Host ""
Write-Host "To use the templates:"
Write-Host "1. Run 'gpupdate /force' to refresh Group Policy"
Write-Host "2. Open Group Policy Editor (gpedit.msc)"
Write-Host "3. Navigate to Administrative Templates > GitHub Copilot"
}
function Uninstall-Templates {
Write-Host "Removing GitHub Copilot Group Policy Templates..." -ForegroundColor Yellow
# Remove ADMX file
if (Test-Path $TargetADMX) {
Write-Host "Removing ADMX file: $TargetADMX"
Remove-Item $TargetADMX -Force
} else {
Write-Host "ADMX file not found: $TargetADMX"
}
# Remove ADML file
if (Test-Path $TargetADML) {
Write-Host "Removing ADML file: $TargetADML"
Remove-Item $TargetADML -Force
} else {
Write-Host "ADML file not found: $TargetADML"
}
Write-Host "GitHub Copilot Group Policy Templates removed successfully!" -ForegroundColor Green
Write-Host "Run 'gpupdate /force' to refresh Group Policy"
}
# Main execution
try {
# Check for administrator rights
if (-not (Test-AdminRights)) {
throw "This script requires administrator privileges. Please run PowerShell as Administrator."
}
if ($Uninstall) {
Uninstall-Templates
} else {
Install-Templates
}
} catch {
Write-Error "Error: $($_.Exception.Message)"
exit 1
}

View File

@@ -0,0 +1,140 @@
# GitHub Copilot Group Policy Templates for Windows
This directory contains Administrative Template (ADMX/ADML) files for managing GitHub Copilot settings through Windows Group Policy. These templates are bundled with the GitHub Copilot Language Server for enterprise deployment.
## Template Location
These templates are installed with the GitHub Copilot Language Server at:
```
[Language Server Installation Directory]/policy-templates/win32/
```
Common installation locations:
- **NPM Global Install**: `%APPDATA%\npm\node_modules\@github\copilot-language-server\dist\policy-templates\win32`
- **Local NPM Install**: `.\node_modules\@github\copilot-language-server\dist\policy-templates\win32`
## Files
- `IDEGitHubCopilot.admx` - Administrative template definition file
- `en-US/IDEGitHubCopilot.adml` - English language resource file
- `Install-PolicyTemplates.ps1` - PowerShell script for automated installation
## Installation Methods
### Option 1: PowerShell Script (Recommended)
1. **Open PowerShell as Administrator**
2. **Navigate to the policy templates directory:**
```powershell
cd "[Language Server Installation Directory]\policy-templates\win32"
```
3. **Execute the installation script:**
```powershell
.\Install-PolicyTemplates.ps1
```
### Option 2: Manual Installation
1. **Copy ADMX file:**
```
Copy IDEGitHubCopilot.admx to C:\Windows\PolicyDefinitions\
```
2. **Copy ADML file:**
```
Copy en-US\IDEGitHubCopilot.adml to C:\Windows\PolicyDefinitions\en-US\
```
### Option 3: Microsoft Intune Configuration
For cloud-based management with Microsoft Intune, create a Custom Configuration Profile with OMA-URI settings (see details below).
## Accessing Group Policy Settings
After installation:
1. **Open Group Policy Editor:**
- Run `gpedit.msc` (Local Group Policy Editor)
- Or use `gpmc.msc` (Group Policy Management Console) for domain environments
2. **Navigate to GitHub Copilot policies:**
- Computer Configuration → Administrative Templates → GitHub Copilot
- User Configuration → Administrative Templates → GitHub Copilot
## Available Policies
### Enable Extension-Contributed MCP Servers
**Category:** GitHub Copilot → Model Context Protocol (MCP)
Controls whether GitHub Copilot can use Model Context Protocol (MCP) servers contributed by IDE extensions.
**Registry Locations:**
- **Machine Policy:** `HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\IDEGitHubCopilot\mcp.contributionPoint.enabled`
- **User Policy:** `HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\IDEGitHubCopilot\mcp.contributionPoint.enabled`
**Values:**
- `1` (REG_DWORD) = Enable extension-contributed MCP servers
- `0` (REG_DWORD) = Disable extension-contributed MCP servers
## Registry Testing
You can test the policies by setting registry values directly:
```cmd
REM Enable extension-contributed MCP servers (machine-wide)
reg add "HKLM\SOFTWARE\Policies\Microsoft\IDEGitHubCopilot" /v "mcp.contributionPoint.enabled" /t REG_DWORD /d 1 /f
REM Disable extension-contributed MCP servers (current user)
reg add "HKCU\SOFTWARE\Policies\Microsoft\IDEGitHubCopilot" /v "mcp.contributionPoint.enabled" /t REG_DWORD /d 0 /f
```
## Microsoft Intune Deployment
For cloud-based management with Microsoft Intune:
1. **Create a Custom Configuration Profile:**
- Go to Microsoft Endpoint Manager admin center
- Navigate to Devices → Configuration profiles
- Create a new profile with platform "Windows 10 and later"
- Profile type: "Custom"
2. **Add the registry setting:**
```
Name: Enable Extension-Contributed MCP Servers
OMA-URI: ./Device/Vendor/MSFT/Policy/Config/ADMX_IDEGitHubCopilot/McpContributionPointEnabled
Data type: Integer
Value: 1 (enabled) or 0 (disabled)
```
3. **Assign to device groups** as needed
## Policy Precedence
1. **Machine Policy** (highest precedence)
- `HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\IDEGitHubCopilot\`
2. **User Policy**
- `HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\IDEGitHubCopilot\`
3. **Default Behavior** (lowest precedence)
- Determined by application defaults when no policy is set
## Troubleshooting
1. **Templates not appearing in Group Policy Editor:**
- Verify ADMX/ADML files are copied to the correct directories
- Run `gpupdate /force` to refresh Group Policy
- Restart Group Policy Editor
2. **Policies not taking effect:**
- Check registry values are being set correctly
- Restart the IDE or GitHub Copilot service
- Verify policy precedence (machine vs user)
3. **Permission errors during template copy:**
- Ensure the application is running with administrator privileges
- Manually copy templates using an elevated command prompt
## References
- [VS Code Group Policy Documentation](https://code.visualstudio.com/docs/setup/enterprise#_group-policy-on-windows)
- [@vscode/policy-watcher Documentation](https://github.com/microsoft/vscode-policy-watcher)
- [Microsoft Group Policy Documentation](https://docs.microsoft.com/en-us/previous-versions/windows/desktop/policy/group-policy-start-page)

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Administrative Template Language File for GitHub Copilot IDE Integration (English)
This file contains the localized display strings for the GitHub Copilot Group Policy settings.
-->
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.0" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<displayName>GitHub Copilot IDE Integration Policy Definitions</displayName>
<description>This file contains the policy definitions for GitHub Copilot IDE integration settings.</description>
<resources>
<stringTable>
<!-- Category Names -->
<string id="Cat_IDEGitHubCopilot">GitHub Copilot</string>
<string id="Cat_IDEGitHubCopilot_Explain">Policy settings for GitHub Copilot IDE integration (JetBrains IDE, Eclipse and Xcode). These settings control various aspects of GitHub Copilot functionality within IDE environments.</string>
<string id="Cat_IDEGitHubCopilot_MCP">Model Context Protocol (MCP)</string>
<string id="Cat_IDEGitHubCopilot_MCP_Explain">Policy settings for Model Context Protocol (MCP) integration with GitHub Copilot. MCP allows extensions to provide additional context to Copilot for improved code suggestions.</string>
<!-- Policy Names and Descriptions -->
<string id="McpContributionPointEnabled">Enable Extension-Contributed MCP Servers</string>
<string id="McpContributionPointEnabled_Explain">This policy setting determines whether GitHub Copilot can use Model Context Protocol (MCP) servers that are contributed by IDE extensions.
When this policy is enabled:
- Extensions can register MCP servers that provide additional context to GitHub Copilot
- Copilot can access extension-provided data sources through the MCP protocol
- This may improve code suggestions by incorporating extension-specific context
When this policy is disabled:
- Extension-contributed MCP servers will not be loaded or used by GitHub Copilot
- Only built-in MCP functionality will be available
- Extensions cannot extend Copilot's context through MCP
If this policy is not configured:
- The default behavior depends on the IDE and extension configuration
- Users may be able to control this setting through IDE preferences
Note: This setting only affects extension-contributed MCP servers. Built-in MCP functionality may still be available when this policy is disabled.
Registry Location:
- Machine: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\IDEGitHubCopilot\mcp.contributionPoint.enabled
- User: HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\IDEGitHubCopilot\mcp.contributionPoint.enabled
Value Type: REG_DWORD
- 1 = Enable extension-contributed MCP servers
- 0 = Disable extension-contributed MCP servers</string>
</stringTable>
</resources>
</policyDefinitionResources>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,48 @@
{
"name": "@github/copilot-language-server",
"displayName": "GitHub Copilot Language Server",
"description": "Your AI pair programmer",
"homepage": "https://github.com/github/copilot-language-server-release",
"bugs": {
"url": "https://github.com/github/copilot-language-server-release/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/github/copilot-language-server-release.git"
},
"license": "MIT",
"version": "1.406.0",
"bin": {
"copilot-language-server": "../dist/language-server.js"
},
"files": [
"dist/language-server.js*",
"dist/main.js*",
"dist/diffWorker.js*",
"dist/tfidfWorker.js*",
"dist/tree-sitter*.wasm",
"dist/compiled/*/*/*.node",
"dist/bin/**/*",
"dist/resources",
"dist/crypt32*.node",
"dist/api/types.d.ts",
"dist/policy-templates/**/*",
"dist/*.tiktoken",
"dist/assets/agents/*.agent.md",
"dist/assets/prompts.contributions.json"
],
"main": "./dist/main.js",
"types": "./dist/api/types.d.ts",
"dependencies": {
"vscode-languageserver-protocol": "^3.17.5"
},
"optionalDependencies": {
"@github/copilot-language-server-win32-x64": "1.406.0",
"@github/copilot-language-server-linux-x64": "1.406.0",
"@github/copilot-language-server-linux-arm64": "1.406.0",
"@github/copilot-language-server-darwin-x64": "1.406.0",
"@github/copilot-language-server-darwin-arm64": "1.406.0"
},
"buildType": "prod",
"build": "13"
}

View File

@@ -0,0 +1,228 @@
*copilot.txt* GitHub Copilot - Your AI pair programmer
GETTING STARTED *copilot*
Invoke `:Copilot setup` to authenticate and enable GitHub Copilot.
Suggestions are displayed inline and can be accepted by pressing <Tab>. If
inline suggestions do not appear to be working, invoke `:Copilot status` to
verify Copilot is enabled and not experiencing any issues.
COMMANDS *:Copilot*
*:Copilot_disable*
:Copilot disable Globally disable GitHub Copilot inline suggestions.
*:Copilot_enable*
:Copilot enable Re-enable GitHub Copilot after :Copilot disable.
*:Copilot_setup*
:Copilot setup Authenticate and enable GitHub Copilot.
*:Copilot_signout*
:Copilot signout Sign out of GitHub Copilot.
*:Copilot_status*
:Copilot status Check if GitHub Copilot is operational for the current
buffer and report on any issues.
*:Copilot_model*
:Copilot model If a preview or other alternate model for completions
is available, provides an interactive interface for
enabling it for the rest of the current Vim/Neovim
session. Note that typically the number of available
completions models is one, rendering this command
inert.
*:Copilot_panel*
:Copilot panel Open a window with up to 10 completions for the
current buffer. Use <CR> to accept a completion.
Maps are also provided for [[ and ]] to jump from
completion to completion.
*:Copilot_version*
:Copilot version Show version information.
*:Copilot_upgrade*
:Copilot upgrade Upgrade the Copilot Language Server to the latest
version with `npx`. This works by temporarily setting
|g:copilot_version| to "latest" and restarting.
OPTIONS *copilot-options*
g:copilot_version Specify a version constraint passed to `npx` when
running the Copilot Language Server. By default, this
is a minor version constraint like "^1.400.0" that
matches a known good version but allows minor version
updates. You can pin this to a specific version, or
use the special value of "latest" which causes `npx`
to always fetch the latest version at startup.
>
let g:copilot_version = 'latest'
<
As a special case, setting this to v:false will
disable the use of `npx` and use a static version of
the language server embedded in the plugin.
>
let g:copilot_version = v:false
<
*g:copilot_filetypes*
g:copilot_filetypes A dictionary mapping file types to their enabled
status. Most file types are enabled by default, so
generally this is used for opting out.
>
let g:copilot_filetypes = {
\ 'xml': v:false,
\ }
<
Disabling all file types can be done by setting the
special key "*". File types can then be turned back
on individually.
>
let g:copilot_filetypes = {
\ '*': v:false,
\ 'python': v:true,
\ }
<
*b:copilot_enabled*
b:copilot_enabled Set to v:false to disable GitHub Copilot for the
current buffer. Or set to v:true to force enabling
it, overriding g:copilot_filetypes.
*g:copilot_node_command*
g:copilot_node_command Tell Copilot what `node` binary to use with
g:copilot_node_command. This is useful if the `node`
in your PATH is an unsupported version.
>
let g:copilot_node_command =
\ "~/.nodenv/versions/18.18.0/bin/node"
<
*g:copilot_enterprise_uri*
g:copilot_enterprise_uri
If you are using GitHub Copilot Enterprise, set this
to the URI of your GitHub Enterprise instance.
>
let g:copilot_enterprise_uri = 'https://DOMAIN.ghe.com'
<
*g:copilot_proxy*
g:copilot_proxy Tell Copilot what proxy server to use.
>
let g:copilot_proxy = 'http://localhost:3128'
<
If this is not set, Copilot will use the value of
environment variables like $HTTPS_PROXY.
*g:copilot_proxy_strict_ssl*
g:copilot_proxy_strict_ssl
Corporate proxies sometimes use a man-in-the-middle
SSL certificate which is incompatible with GitHub
Copilot. To work around this, SSL certificate
verification can be disabled:
>
let g:copilot_proxy_strict_ssl = v:false
<
You can also tell Node.js to disable SSL verification
by setting the $NODE_TLS_REJECT_UNAUTHORIZED
environment variable to "0".
*g:copilot_workspace_folders*
g:copilot_workspace_folders
A list of "workspace folders" or project roots that
Copilot may use to improve the quality of suggestions.
>
let g:copilot_workspace_folders =
\ ["~/Projects/myproject"]
<
You can also set b:workspace_folder for an individual
buffer and newly seen values will be added
automatically.
MAPS *copilot-maps*
*copilot-i_<Tab>*
Copilot.vim uses <Tab> to accept the current suggestion. If you have an
existing <Tab> map, that will be used as the fallback when no suggestion is
displayed.
*copilot#Accept()*
If you'd rather use a key that isn't <Tab>, define an <expr> map that calls
copilot#Accept(). Here's an example with CTRL-J:
>
imap <silent><script><expr> <C-J> copilot#Accept("\<CR>")
let g:copilot_no_tab_map = v:true
<
Lua version:
>
vim.keymap.set('i', '<C-J>', 'copilot#Accept("\\<CR>")', {
expr = true,
replace_keycodes = false
})
vim.g.copilot_no_tab_map = true
<
The argument to copilot#Accept() is the fallback for when no suggestion is
displayed. In this example, a regular carriage return is used. If no
fallback is desired, use an argument of "" (an empty string).
Other Maps ~
Note that M- (a.k.a. meta or alt) maps are highly dependent on your terminal
to function correctly and may be unsupported with your setup. As an
alternative, you can create your own versions that invoke the <Plug> maps
instead. Here's an example that maps CTRL-L to accept one word of the
current suggestion:
>
imap <C-L> <Plug>(copilot-accept-word)
<
Lua version:
>
vim.keymap.set('i', '<C-L>', '<Plug>(copilot-accept-word)')
<
*copilot-i_CTRL-]*
<C-]> Dismiss the current suggestion.
<Plug>(copilot-dismiss)
*copilot-i_ALT-]*
<M-]> Cycle to the next suggestion, if one is available.
<Plug>(copilot-next)
*copilot-i_ALT-[*
<M-[> Cycle to the previous suggestion.
<Plug>(copilot-previous)
*copilot-i_ALT-\*
<M-\> Explicitly request a suggestion, even if Copilot
<Plug>(copilot-suggest) is disabled.
*copilot-i_ALT-Right*
<M-Right> Accept the next word of the current suggestion.
<Plug>(copilot-accept-word)
*copilot-i_ALT-CTRL-Right*
<M-C-Right> Accept the next line of the current suggestion.
<Plug>(copilot-accept-line)
SYNTAX HIGHLIGHTING *copilot-highlighting*
Inline suggestions are highlighted using the CopilotSuggestion group,
defaulting to a medium gray. The best place to override this is with
a |ColorScheme| autocommand:
>
autocmd ColorScheme solarized
\ highlight CopilotSuggestion guifg=#555555 ctermfg=8
<
Lua version:
>
vim.api.nvim_create_autocmd('ColorScheme', {
pattern = 'solarized',
-- group = ...,
callback = function()
vim.api.nvim_set_hl(0, 'CopilotSuggestion', {
fg = '#555555',
ctermfg = 8,
force = true
})
end
})
<
vim:tw=78:et:ft=help:norl:

View File

@@ -0,0 +1,104 @@
local copilot = {}
local showDocument = function(err, result, ctx, _)
local fallback = vim.lsp.handlers['window/showDocument']
if not fallback or (result.external and vim.g.copilot_browser) then
return vim.fn['copilot#handlers#window_showDocument'](result)
else
return fallback(err, result, ctx, _)
end
end
copilot.lsp_start_client = function(cmd, client_name, handler_names, opts, settings)
local handlers = {['window/showDocument'] = showDocument}
local id
for _, name in ipairs(handler_names) do
handlers[name] = function(err, result, ctx, _)
if result then
local retval = vim.call('copilot#client#LspHandle', id, { method = name, params = result })
if type(retval) == 'table' then
return retval.result, retval.error
elseif vim.lsp.handlers[name] then
return vim.lsp.handlers[name](err, result, ctx, _)
end
end
end
end
local workspace_folders = opts.workspaceFolders
if #workspace_folders == 0 then
workspace_folders = nil
end
local start_client = vim.lsp.start_client
if vim.fn.has('nvim-0.11.2') == 1 then
start_client = vim.lsp.start
end
id = start_client({
cmd = cmd,
cmd_cwd = vim.call('copilot#job#Cwd'),
name = client_name,
init_options = opts.initializationOptions,
workspace_folders = workspace_folders,
settings = settings,
handlers = handlers,
on_init = function(client, initialize_result)
vim.call('copilot#client#LspInit', client.id, initialize_result)
end,
on_exit = function(code, signal, client_id)
vim.schedule(function()
vim.call('copilot#client#LspExit', client_id, code, signal)
end)
end,
})
return id
end
copilot.lsp_request = function(client_id, method, params, bufnr)
local client = vim.lsp.get_client_by_id(client_id)
if not client then
return
end
if bufnr == vim.NIL then
bufnr = nil
end
local _, id
local handler = function(err, result)
vim.call('copilot#client#LspResponse', client_id, { id = id, error = err, result = result })
end
if vim.fn.has('nvim-0.11') == 1 then
_, id = client:request(method, params, handler, bufnr)
else
_, id = client.request(method, params, handler, bufnr)
end
return id
end
copilot.rpc_request = function(client_id, method, params)
local client = vim.lsp.get_client_by_id(client_id)
if not client then
return
end
local _, id
_, id = client.rpc.request(method, params, function(err, result)
vim.call('copilot#client#LspResponse', client_id, { id = id, error = err, result = result })
end)
return id
end
copilot.rpc_notify = function(client_id, method, params)
local client = vim.lsp.get_client_by_id(client_id)
if not client then
return
end
return client.rpc.notify(method, params)
end
copilot.did_change_configuration = function(client_id, settings)
local client = vim.lsp.get_client_by_id(client_id)
if not client then
return
end
client.settings = settings
return client.notify('workspace/didChangeConfiguration', { settings = settings })
end
return copilot

View File

@@ -0,0 +1,114 @@
if exists('g:loaded_copilot')
finish
endif
let g:loaded_copilot = 1
scriptencoding utf-8
command! -bang -nargs=? -range=-1 -complete=customlist,copilot#CommandComplete Copilot exe copilot#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)
if v:version < 800 || !exists('##InsertLeavePre')
finish
endif
function! s:ColorScheme() abort
if &t_Co == 256
hi def CopilotSuggestion guifg=#808080 ctermfg=244
else
hi def CopilotSuggestion guifg=#808080 ctermfg=12
endif
hi def link CopilotAnnotation MoreMsg
endfunction
function! s:MapTab() abort
if get(g:, 'copilot_no_tab_map') || get(g:, 'copilot_no_maps')
return
endif
let tab_map = maparg('<Tab>', 'i', 0, 1)
if !has_key(tab_map, 'rhs')
imap <script><silent><nowait><expr> <Tab> empty(get(g:, 'copilot_no_tab_map')) ? copilot#Accept() : "<Bslash>t"
elseif tab_map.rhs !~# 'copilot'
if tab_map.expr
let tab_fallback = '{ -> ' . tab_map.rhs . ' }'
else
let tab_fallback = substitute(json_encode(tab_map.rhs), '<', '\\<', 'g')
endif
let tab_fallback = substitute(tab_fallback, '<SID>', '<SNR>' . get(tab_map, 'sid') . '_', 'g')
if get(tab_map, 'noremap') || get(tab_map, 'script') || mapcheck('<Left>', 'i') || mapcheck('<Del>', 'i')
exe 'imap <script><silent><nowait><expr> <Tab> copilot#Accept(' . tab_fallback . ')'
else
exe 'imap <silent><nowait><expr> <Tab> copilot#Accept(' . tab_fallback . ')'
endif
endif
endfunction
function! s:Event(type) abort
try
call call('copilot#On' . a:type, [])
catch
call copilot#logger#Exception('autocmd.' . a:type)
endtry
endfunction
augroup github_copilot
autocmd!
autocmd FileType * call s:Event('FileType')
autocmd InsertLeavePre * call s:Event('InsertLeavePre')
autocmd BufLeave * if mode() =~# '^[iR]'|call s:Event('InsertLeavePre')|endif
autocmd InsertEnter * call s:Event('InsertEnter')
autocmd BufEnter * if mode() =~# '^[iR]'|call s:Event('InsertEnter')|endif
autocmd BufEnter * call s:Event('BufEnter')
autocmd CursorMovedI * call s:Event('CursorMovedI')
autocmd CompleteChanged * call s:Event('CompleteChanged')
autocmd ColorScheme,VimEnter * call s:ColorScheme()
autocmd VimEnter * call s:MapTab() | call copilot#Init()
autocmd BufUnload * call s:Event('BufUnload')
autocmd VimLeavePre * call s:Event('VimLeavePre')
autocmd BufReadCmd copilot://* setlocal buftype=nofile bufhidden=wipe nobuflisted nomodifiable
autocmd BufReadCmd copilot:///log call copilot#logger#BufReadCmd() | setfiletype copilotlog
augroup END
call s:ColorScheme()
call s:MapTab()
if !get(g:, 'copilot_no_maps')
imap <Plug>(copilot-dismiss) <Cmd>call copilot#Dismiss()<CR>
if empty(mapcheck('<C-]>', 'i'))
imap <silent><script><nowait><expr> <C-]> copilot#Dismiss() . "\<C-]>"
endif
imap <Plug>(copilot-next) <Cmd>call copilot#Next()<CR>
imap <Plug>(copilot-previous) <Cmd>call copilot#Previous()<CR>
imap <Plug>(copilot-suggest) <Cmd>call copilot#Suggest()<CR>
imap <script><silent><nowait><expr> <Plug>(copilot-accept-word) copilot#AcceptWord()
imap <script><silent><nowait><expr> <Plug>(copilot-accept-line) copilot#AcceptLine()
try
if !has('nvim') && &encoding ==# 'utf-8'
" avoid 8-bit meta collision with UTF-8 characters
let s:restore_encoding = 1
silent noautocmd set encoding=cp949
endif
if empty(mapcheck('<M-]>', 'i'))
imap <M-]> <Plug>(copilot-next)
endif
if empty(mapcheck('<M-[>', 'i'))
imap <M-[> <Plug>(copilot-previous)
endif
if empty(mapcheck('<M-Bslash>', 'i'))
imap <M-Bslash> <Plug>(copilot-suggest)
endif
if empty(mapcheck('<M-Right>', 'i'))
imap <M-Right> <Plug>(copilot-accept-word)
endif
if empty(mapcheck('<M-C-Right>', 'i'))
imap <M-C-Right> <Plug>(copilot-accept-line)
endif
finally
if exists('s:restore_encoding')
silent noautocmd set encoding=utf-8
endif
endtry
endif
let s:dir = expand('<sfile>:h:h')
if getftime(s:dir . '/doc/copilot.txt') > getftime(s:dir . '/doc/tags')
silent! execute 'helptags' fnameescape(s:dir . '/doc')
endif

View File

@@ -0,0 +1,25 @@
scriptencoding utf-8
if exists("b:current_syntax")
finish
endif
let s:subtype = matchstr(&l:filetype, '\<copilot\.\zs[[:alnum:]_-]\+')
if !empty(s:subtype) && s:subtype !=# 'copilot'
exe 'syn include @copilotLanguageTop syntax/' . s:subtype . '.vim'
unlet! b:current_syntax
endif
syn match copilotlogError '\[ERROR\]'
syn match copilotlogWarn '\[WARN\]'
syn match copilotlogInfo '\[INFO\]'
syn match copilotlogDebug '\[DEBUG\]'
syn match copilotlogTime '^\[\d\d\d\d-\d\d-\d\d.\d\d:\d\d:\d\d\]' nextgroup=copilotlogError,copilotlogWarn,copilotLogInfo,copilotLogDebug skipwhite
hi def link copilotlogTime NonText
hi def link copilotlogError ErrorMsg
hi def link copilotlogWarn WarningMsg
hi def link copilotlogInfo MoreMsg
hi def link copilotlogDebug ModeMsg
let b:current_syntax = "copilotlog"

View File

@@ -0,0 +1,19 @@
scriptencoding utf-8
if exists("b:current_syntax")
finish
endif
let s:subtype = matchstr(&l:filetype, '\<copilotpanel\.\zs[[:alnum:]_-]\+')
if !empty(s:subtype) && s:subtype !~# 'copilot'
silent! exe 'syn include @copilotpanelLanguageTop syntax/' . s:subtype . '.vim'
unlet! b:current_syntax
endif
syn region copilotpanelHeader start="\%^" end="^─\@="
syn region copilotpanelItem matchgroup=copilotpanelSeparator start="^─\{9,}$" end="\%(^─\{9,\}$\)\@=\|\%$" keepend contains=@copilotpanelLanguageTop
hi def link copilotpanelHeader PreProc
hi def link copilotpanelSeparator Comment
let b:current_syntax = "copilotpanel"

View File

@@ -0,0 +1 @@
*.sh text eol=lf

View File

@@ -0,0 +1 @@
github: junegunn

View File

@@ -0,0 +1,49 @@
---
name: Issue Template
description: Report a problem or bug related to fzf.vim to help us improve
body:
- type: markdown
attributes:
value: |
Check the version of fzf used by running
```vim
:echo system(fzf#exec() .. ' --version')
```
If you don't have the latest version, run the following code to download it
```vim
:call fzf#install()
```
- type: checkboxes
attributes:
label: Checklist
options:
- label: I have fzf 0.54.0 or later
required: true
- label: I have searched through the existing issues
required: true
- type: input
attributes:
label: Output of `:echo system(fzf#exec() .. ' --version')`
validations:
required: true
- type: checkboxes
attributes:
label: OS
options:
- label: Linux
- label: macOS
- label: Windows
- label: Etc.
- type: textarea
attributes:
label: Problem / Steps to reproduce
validations:
required: true

View File

@@ -0,0 +1 @@
doc/tags

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Junegunn Choi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,489 @@
<div align="center" markdown="1">
<sup>Special thanks to:</sup>
<br>
<a href="https://tuple.app/fzf.vim">
<img alt="Tuple's sponsorship image" src="https://raw.githubusercontent.com/junegunn/i/master/tuple.png" width="400">
</a>
### [Tuple, the premier screen sharing app for developers](https://tuple.app/fzf.vim)
[Available for MacOS & Windows](https://tuple.app/fzf.vim)<br>
</div>
---
fzf :heart: vim
===============
Things you can do with [fzf][fzf] and Vim.
Rationale
---------
[fzf][fzf] itself is not a Vim plugin, and the official repository only
provides the [basic wrapper function][run] for Vim. It's up to the users to
write their own Vim commands with it. However, I've learned that many users of
fzf are not familiar with Vimscript and are looking for the "default"
implementation of the features they can find in the alternative Vim plugins.
Why you should use fzf on Vim
-----------------------------
Because you can and you love fzf.
fzf runs asynchronously and can be orders of magnitude faster than similar Vim
plugins. However, the benefit may not be noticeable if the size of the input
is small, which is the case for many of the commands provided here.
Nevertheless I wrote them anyway since it's really easy to implement custom
selector with fzf.
Installation
------------
fzf.vim depends on the basic Vim plugin of [the main fzf
repository][fzf-main], which means you need to **set up both "fzf" and
"fzf.vim" on Vim**. To learn more about fzf/Vim integration, see
[README-VIM][README-VIM].
[fzf-main]: https://github.com/junegunn/fzf
[README-VIM]: https://github.com/junegunn/fzf/blob/master/README-VIM.md
### Using [vim-plug](https://github.com/junegunn/vim-plug)
```vim
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'
```
`fzf#install()` makes sure that you have the latest binary, but it's optional,
so you can omit it if you use a plugin manager that doesn't support hooks.
### Dependencies
- [fzf][fzf-main] 0.54.0 or above
- For syntax-highlighted preview, install [bat](https://github.com/sharkdp/bat)
- If [delta](https://github.com/dandavison/delta) is available, `GF?`,
`Commits` and `BCommits` will use it to format `git diff` output.
- `Ag` requires [The Silver Searcher (ag)][ag]
- `Rg` requires [ripgrep (rg)][rg]
- `Tags` and `Helptags` require Perl
- `Tags PREFIX` requires `readtags` command from [Universal Ctags](https://ctags.io/)
```sh
# Installing dependencies using Homebrew
brew install fzf bat ripgrep the_silver_searcher perl universal-ctags
```
Commands
--------
| Command | List |
| --- | --- |
| `:Files [PATH]` | Files (runs `$FZF_DEFAULT_COMMAND` if defined) |
| `:GFiles [OPTS]` | Git files (`git ls-files`) |
| `:GFiles?` | Git files (`git status`) |
| `:Buffers` | Open buffers |
| `:Colors` | Color schemes |
| `:Ag [PATTERN]` | [ag][ag] search result (`ALT-A` to select all, `ALT-D` to deselect all) |
| `:Rg [PATTERN]` | [rg][rg] search result (`ALT-A` to select all, `ALT-D` to deselect all) |
| `:RG [PATTERN]` | [rg][rg] search result; relaunch ripgrep on every keystroke |
| `:Lines [QUERY]` | Lines in loaded buffers |
| `:BLines [QUERY]` | Lines in the current buffer |
| `:Tags [PREFIX]` | Tags in the project (`ctags -R`) |
| `:BTags [QUERY]` | Tags in the current buffer |
| `:Changes` | Changelist across all open buffers |
| `:Marks` | Marks |
| `:BMarks` | Marks in the current buffer |
| `:Jumps` | Jumps |
| `:Windows` | Windows |
| `:Locate PATTERN` | `locate` command output |
| `:History` | `v:oldfiles` and open buffers |
| `:History:` | Command history |
| `:History/` | Search history |
| `:Snippets` | Snippets ([UltiSnips][us]) |
| `:Commits [LOG_OPTS]` | Git commits (requires [fugitive.vim][f]) |
| `:BCommits [LOG_OPTS]` | Git commits for the current buffer; visual-select lines to track changes in the range |
| `:Commands` | Commands |
| `:Maps` | Normal mode mappings |
| `:Helptags` | Help tags <sup id="a1">[1](#helptags)</sup> |
| `:Filetypes` | File types
- Most commands support `CTRL-T` / `CTRL-X` / `CTRL-V` key
bindings to open in a new tab, a new split, or in a new vertical split
- Bang-versions of the commands (e.g. `Ag!`) will open fzf in fullscreen
- You can set `g:fzf_vim.command_prefix` to give the same prefix to the commands
- e.g. `let g:fzf_vim.command_prefix = 'Fzf'` and you have `FzfFiles`, etc.
(<a name="helptags">1</a>: `Helptags` will shadow the command of the same name
from [pathogen][pat]. But its functionality is still available via `call
pathogen#helptags()`. [](#a1))
[pat]: https://github.com/tpope/vim-pathogen
[f]: https://github.com/tpope/vim-fugitive
Customization
-------------
### Configuration options of the base plugin
Every command in fzf.vim internally calls `fzf#wrap` function of the main
repository which supports a set of global option variables. So please read
through [README-VIM][README-VIM] to learn more about them.
### Configuration options for fzf.vim
All configuration values for this plugin are stored in `g:fzf_vim` dictionary,
so **make sure to initialize it before assigning any configuration values to
it**.
```vim
" Initialize configuration dictionary
let g:fzf_vim = {}
```
#### Preview window
Some commands will show the preview window on the right. You can customize the
behavior with `g:fzf_vim.preview_window`. Here are some examples:
```vim
" This is the default option:
" - Preview window on the right with 50% width
" - CTRL-/ will toggle preview window.
" - Note that this array is passed as arguments to fzf#vim#with_preview function.
" - To learn more about preview window options, see `--preview-window` section of `man fzf`.
let g:fzf_vim.preview_window = ['right,50%', 'ctrl-/']
" Preview window is hidden by default. You can toggle it with ctrl-/.
" It will show on the right with 50% width, but if the width is smaller
" than 70 columns, it will show above the candidate list
let g:fzf_vim.preview_window = ['hidden,right,50%,<70(up,40%)', 'ctrl-/']
" Empty value to disable preview window altogether
let g:fzf_vim.preview_window = []
" fzf.vim needs bash to display the preview window.
" On Windows, fzf.vim will first see if bash is in $PATH, then if
" Git bash (C:\Program Files\Git\bin\bash.exe) is available.
" If you want it to use a different bash, set this variable.
" let g:fzf_vim = {}
" let g:fzf_vim.preview_bash = 'C:\Git\bin\bash.exe'
```
#### Command-level options
```vim
" [Buffers] Jump to the existing window if possible (default: 0)
let g:fzf_vim.buffers_jump = 1
" [Ag|Rg|RG] Display path on a separate line for narrow screens (default: 0)
" * Requires Perl and fzf 0.56.0 or later
let g:fzf_vim.grep_multi_line = 0
" PATH:LINE:COL:LINE
let g:fzf_vim.grep_multi_line = 1
" PATH:LINE:COL:
" LINE
let g:fzf_vim.grep_multi_line = 2
" PATH:LINE:COL:
" LINE
" (empty line between items using --gap option)
" [[B]Commits] Customize the options used by 'git log':
let g:fzf_vim.commits_log_options = '--graph --color=always --format="%C(auto)%h%d %s %C(black)%C(bold)%cr"'
" [Tags] Command to generate tags file
let g:fzf_vim.tags_command = 'ctags -R'
" [Commands] --expect expression for directly executing the command
let g:fzf_vim.commands_expect = 'alt-enter,ctrl-x'
```
#### Command-level fzf options
You can set fzf options for each command by setting
`g:fzf_vim.{command}_options`.
```vim
" In string
let g:fzf_vim.buffers_options = '--style full --border-label " Open Buffers "'
" In list (No need to quote or escape values)
let g:fzf_vim.buffers_options = ['--style', 'full', '--border-label', ' Open Buffers ']
```
#### List type to handle multiple selections
The following commands will fill the quickfix list when multiple entries are
selected.
* `Ag`
* `Rg` / `RG`
* `Lines` / `BLines`
* `Tags` / `BTags`
By setting `g:fzf_vim.listproc`, you can make them use location list instead.
```vim
" Default: Use quickfix list
let g:fzf_vim.listproc = { list -> fzf#vim#listproc#quickfix(list) }
" Use location list instead of quickfix list
let g:fzf_vim.listproc = { list -> fzf#vim#listproc#location(list) }
```
You can customize the list type per command by defining variables named
`g:fzf_vim.listproc_{command_name_in_lowercase}`.
```vim
" Command-wise customization
let g:fzf_vim.listproc_ag = { list -> fzf#vim#listproc#quickfix(list) }
let g:fzf_vim.listproc_rg = { list -> fzf#vim#listproc#location(list) }
```
You can further customize the behavior by providing a custom function to
process the list instead of using the predefined `fzf#vim#listproc#quickfix`
or `fzf#vim#listproc#location`.
```vim
" A customized version of fzf#vim#listproc#quickfix.
" The last two lines are commented out not to move to the first entry.
function! g:fzf_vim.listproc(list)
call setqflist(a:list)
copen
wincmd p
" cfirst
" normal! zvzz
endfunction
```
### Advanced customization
#### Vim functions
Each command in fzf.vim is backed by a Vim function. You can override
a command or define a variation of it by calling its corresponding function.
| Command | Vim function |
| --- | --- |
| `Files` | `fzf#vim#files(dir, [spec dict], [fullscreen bool])` |
| `GFiles` | `fzf#vim#gitfiles(git_options, [spec dict], [fullscreen bool])` |
| `GFiles?` | `fzf#vim#gitfiles('?', [spec dict], [fullscreen bool])` |
| `Buffers` | `fzf#vim#buffers([query string], [bufnrs list], [spec dict], [fullscreen bool])` |
| `Colors` | `fzf#vim#colors([spec dict], [fullscreen bool])` |
| `Rg` | `fzf#vim#grep(command, [spec dict], [fullscreen bool])` |
| `RG` | `fzf#vim#grep2(command_prefix, query, [spec dict], [fullscreen bool])` |
| ... | ... |
(We can see that the last two optional arguments of each function are
identical. They are directly passed to `fzf#wrap` function. If you haven't
read [README-VIM][README-VIM] already, please read it before proceeding.)
#### Example: Customizing `Files` command
This is the default definition of `Files` command:
```vim
command! -bang -nargs=? -complete=dir Files call fzf#vim#files(<q-args>, <bang>0)
```
Let's say you want to a variation of it called `ProjectFiles` that only
searches inside `~/projects` directory. Then you can do it like this:
```vim
command! -bang ProjectFiles call fzf#vim#files('~/projects', <bang>0)
```
Or, if you want to override the command with different fzf options, just pass
a custom spec to the function.
```vim
command! -bang -nargs=? -complete=dir Files
\ call fzf#vim#files(<q-args>, {'options': ['--layout=reverse', '--info=inline']}, <bang>0)
```
Want a preview window?
```vim
command! -bang -nargs=? -complete=dir Files
\ call fzf#vim#files(<q-args>, {'options': ['--layout=reverse', '--info=inline', '--preview', 'cat {}']}, <bang>0)
```
It kind of works, but you probably want a nicer previewer program than `cat`.
fzf.vim ships [a versatile preview script](bin/preview.sh) you can readily
use. It internally executes [bat](https://github.com/sharkdp/bat) for syntax
highlighting, so make sure to install it.
```vim
command! -bang -nargs=? -complete=dir Files
\ call fzf#vim#files(<q-args>, {'options': ['--layout=reverse', '--info=inline', '--preview', '~/.vim/plugged/fzf.vim/bin/preview.sh {}']}, <bang>0)
```
However, it's not ideal to hard-code the path to the script which can be
different in different circumstances. So in order to make it easier to set up
the previewer, fzf.vim provides `fzf#vim#with_preview` helper function.
Similarly to `fzf#wrap`, it takes a spec dictionary and returns a copy of it
with additional preview options.
```vim
command! -bang -nargs=? -complete=dir Files
\ call fzf#vim#files(<q-args>, fzf#vim#with_preview({'options': ['--layout=reverse', '--info=inline']}), <bang>0)
```
You can just omit the spec argument if you only want the previewer.
```vim
command! -bang -nargs=? -complete=dir Files
\ call fzf#vim#files(<q-args>, fzf#vim#with_preview(), <bang>0)
```
#### Example: `git grep` wrapper
The following example implements `GGrep` command that works similarly to
predefined `Ag` or `Rg` using `fzf#vim#grep`.
- We set the base directory to git root by setting `dir` attribute in spec
dictionary.
- [The preview script](bin/preview.sh) supports `grep` format
(`FILE_PATH:LINE_NO:...`), so we can just wrap the spec with
`fzf#vim#with_preview` as before to enable previewer.
```vim
command! -bang -nargs=* GGrep
\ call fzf#vim#grep(
\ 'git grep --line-number -- '.fzf#shellescape(<q-args>),
\ fzf#vim#with_preview({'dir': systemlist('git rev-parse --show-toplevel')[0]}), <bang>0)
```
Mappings
--------
| Mapping | Description |
| --- | --- |
| `<plug>(fzf-maps-n)` | Normal mode mappings |
| `<plug>(fzf-maps-i)` | Insert mode mappings |
| `<plug>(fzf-maps-x)` | Visual mode mappings |
| `<plug>(fzf-maps-o)` | Operator-pending mappings |
| `<plug>(fzf-complete-word)` | `cat /usr/share/dict/words` |
| `<plug>(fzf-complete-path)` | Path completion using `find` (file + dir) |
| `<plug>(fzf-complete-file)` | File completion using `find` |
| `<plug>(fzf-complete-line)` | Line completion (all open buffers) |
| `<plug>(fzf-complete-buffer-line)` | Line completion (current buffer only) |
```vim
" Mapping selecting mappings
nmap <leader><tab> <plug>(fzf-maps-n)
xmap <leader><tab> <plug>(fzf-maps-x)
omap <leader><tab> <plug>(fzf-maps-o)
" Insert mode completion
imap <c-x><c-k> <plug>(fzf-complete-word)
imap <c-x><c-f> <plug>(fzf-complete-path)
imap <c-x><c-l> <plug>(fzf-complete-line)
```
Completion functions
--------------------
| Function | Description |
| --- | --- |
| `fzf#vim#complete#path(command, [spec])` | Path completion |
| `fzf#vim#complete#word([spec])` | Word completion |
| `fzf#vim#complete#line([spec])` | Line completion (all open buffers) |
| `fzf#vim#complete#buffer_line([spec])` | Line completion (current buffer only) |
```vim
" Path completion with custom source command
inoremap <expr> <c-x><c-f> fzf#vim#complete#path('fd')
inoremap <expr> <c-x><c-f> fzf#vim#complete#path('rg --files')
" Word completion with custom spec with popup layout option
inoremap <expr> <c-x><c-k> fzf#vim#complete#word({'window': { 'width': 0.2, 'height': 0.9, 'xoffset': 1 }})
```
Custom completion
-----------------
`fzf#vim#complete` is a helper function for creating custom fuzzy completion
using fzf. If the first parameter is a command string or a Vim list, it will
be used as the source.
```vim
" Replace the default dictionary completion with fzf-based fuzzy completion
inoremap <expr> <c-x><c-k> fzf#vim#complete('cat /usr/share/dict/words')
```
For advanced uses, you can pass an options dictionary to the function. The set
of options is pretty much identical to that for `fzf#run` only with the
following exceptions:
- `reducer` (funcref)
- Reducer transforms the output lines of fzf into a single string value
- `prefix` (string or funcref; default: `\k*$`)
- Regular expression pattern to extract the completion prefix
- Or a function to extract completion prefix
- Both `source` and `options` can be given as funcrefs that take the
completion prefix as the argument and return the final value
- `sink` or `sink*` are ignored
```vim
" Global line completion (not just open buffers. ripgrep required.)
inoremap <expr> <c-x><c-l> fzf#vim#complete(fzf#wrap({
\ 'prefix': '^.*$',
\ 'source': 'rg -n ^ --color always',
\ 'options': '--ansi --delimiter : --nth 3..',
\ 'reducer': { lines -> join(split(lines[0], ':\zs')[2:], '') }}))
```
### Reducer example
```vim
function! s:make_sentence(lines)
return substitute(join(a:lines), '^.', '\=toupper(submatch(0))', '').'.'
endfunction
inoremap <expr> <c-x><c-s> fzf#vim#complete({
\ 'source': 'cat /usr/share/dict/words',
\ 'reducer': function('<sid>make_sentence'),
\ 'options': '--multi --reverse --margin 15%,0',
\ 'left': 20})
```
Status line of terminal buffer
------------------------------
When fzf starts in a terminal buffer (see [fzf/README-VIM.md][termbuf]), you
may want to customize the statusline of the containing buffer.
[termbuf]: https://github.com/junegunn/fzf/blob/master/README-VIM.md#fzf-inside-terminal-buffer
### Hide statusline
```vim
autocmd! FileType fzf set laststatus=0 noshowmode noruler
\| autocmd BufLeave <buffer> set laststatus=2 showmode ruler
```
### Custom statusline
```vim
function! s:fzf_statusline()
" Override statusline as you like
highlight fzf1 ctermfg=161 ctermbg=251
highlight fzf2 ctermfg=23 ctermbg=251
highlight fzf3 ctermfg=237 ctermbg=251
setlocal statusline=%#fzf1#\ >\ %#fzf2#fz%#fzf3#f
endfunction
autocmd! User FzfStatusLine call <SID>fzf_statusline()
```
License
-------
MIT
[fzf]: https://github.com/junegunn/fzf
[run]: https://github.com/junegunn/fzf/blob/master/README-VIM.md#fzfrun
[ag]: https://github.com/ggreer/the_silver_searcher
[rg]: https://github.com/BurntSushi/ripgrep
[us]: https://github.com/SirVer/ultisnips

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,164 @@
" Copyright (c) 2015 Junegunn Choi
"
" MIT License
"
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be
" included in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
let s:cpo_save = &cpo
set cpo&vim
let s:is_win = has('win32') || has('win64')
function! s:extend(base, extra)
let base = copy(a:base)
if has_key(a:extra, 'options')
let extra = copy(a:extra)
let extra.extra_options = remove(extra, 'options')
return extend(base, extra)
endif
return extend(base, a:extra)
endfunction
if v:version >= 704
function! s:function(name)
return function(a:name)
endfunction
else
function! s:function(name)
" By Ingo Karkat
return function(substitute(a:name, '^s:', matchstr(expand('<sfile>'), '<SNR>\d\+_\zefunction$'), ''))
endfunction
endif
function! fzf#vim#complete#word(...)
let sources = empty(&dictionary) ? ['/usr/share/dict/words'] : split(&dictionary, ',')
return fzf#vim#complete(s:extend({
\ 'source': 'cat ' . join(map(sources, 'fzf#shellescape(v:val)'))},
\ get(a:000, 0, fzf#wrap())))
endfunction
" ----------------------------------------------------------------------------
" <plug>(fzf-complete-path)
" <plug>(fzf-complete-file)
" <plug>(fzf-complete-file-ag)
" ----------------------------------------------------------------------------
function! s:file_split_prefix(prefix)
let expanded = expand(a:prefix)
let slash = (s:is_win && !&shellslash) ? '\\' : '/'
return isdirectory(expanded) ?
\ [expanded,
\ substitute(a:prefix, '[/\\]*$', slash, ''),
\ ''] :
\ [fnamemodify(expanded, ':h'),
\ substitute(fnamemodify(a:prefix, ':h'), '[/\\]*$', slash, ''),
\ fnamemodify(expanded, ':t')]
endfunction
function! s:file_source(prefix)
let [dir, head, tail] = s:file_split_prefix(a:prefix)
return printf(
\ "cd %s && ".s:file_cmd." | sed %s",
\ fzf#shellescape(dir), fzf#shellescape('s:^:'.(empty(a:prefix) || a:prefix == tail ? '' : head).':'))
endfunction
function! s:file_options(prefix)
let [_, head, tail] = s:file_split_prefix(a:prefix)
return ['--prompt', head, '--query', tail]
endfunction
function! s:fname_prefix(str)
let isf = &isfname
let white = []
let black = []
if isf =~ ',,,'
call add(white, ',')
let isf = substitute(isf, ',,,', ',', 'g')
endif
if isf =~ ',^,,'
call add(black, ',')
let isf = substitute(isf, ',^,,', ',', 'g')
endif
for token in split(isf, ',')
let target = white
if token[0] == '^'
let target = black
let token = token[1:]
endif
let ends = matchlist(token, '\(.\+\)-\(.\+\)')
if empty(ends)
call add(target, token)
else
let ends = map(ends[1:2], "len(v:val) == 1 ? char2nr(v:val) : str2nr(v:val)")
for i in range(ends[0], ends[1])
call add(target, nr2char(i))
endfor
endif
endfor
let prefix = a:str
for offset in range(1, len(a:str))
let char = a:str[len(a:str) - offset]
if (char =~ '\w' || index(white, char) >= 0) && index(black, char) < 0
continue
endif
let prefix = strpart(a:str, len(a:str) - offset + 1)
break
endfor
return prefix
endfunction
function! fzf#vim#complete#path(command, ...)
let s:file_cmd = a:command
return fzf#vim#complete(s:extend({
\ 'prefix': s:function('s:fname_prefix'),
\ 'source': s:function('s:file_source'),
\ 'options': s:function('s:file_options')}, get(a:000, 0, fzf#wrap())))
endfunction
" ----------------------------------------------------------------------------
" <plug>(fzf-complete-line)
" <plug>(fzf-complete-buffer-line)
" ----------------------------------------------------------------------------
function! s:reduce_line(lines)
return join(split(a:lines[0], '\t\zs')[3:], '')
endfunction
function! fzf#vim#complete#line(...)
let [display_bufnames, lines] = fzf#vim#_lines(0)
let nth = display_bufnames ? 4 : 3
return fzf#vim#complete(s:extend({
\ 'prefix': '^.*$',
\ 'source': lines,
\ 'options': '--tiebreak=index --ansi --nth '.nth.'.. --tabstop=1',
\ 'reducer': s:function('s:reduce_line')}, get(a:000, 0, fzf#wrap())))
endfunction
function! fzf#vim#complete#buffer_line(...)
return fzf#vim#complete(s:extend({
\ 'prefix': '^.*$',
\ 'source': fzf#vim#_uniq(getline(1, '$'))}, get(a:000, 0, fzf#wrap())))
endfunction
let &cpo = s:cpo_save
unlet s:cpo_save

View File

@@ -0,0 +1,95 @@
" Copyright (c) 2024 Junegunn Choi
"
" MIT License
"
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be
" included in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
function! s:warn(message)
echohl WarningMsg
echom a:message
echohl None
return 0
endfunction
function! fzf#vim#ipc#start(Callback)
if !exists('*job_start') && !exists('*jobstart')
call s:warn('job_start/jobstart function not supported')
return ''
endif
if !executable('mkfifo')
call s:warn('mkfifo is not available')
return ''
endif
call fzf#vim#ipc#stop()
let g:fzf_ipc = { 'fifo': tempname(), 'callback': a:Callback }
if !filereadable(g:fzf_ipc.fifo)
call system('mkfifo '..shellescape(g:fzf_ipc.fifo))
if v:shell_error
call s:warn('Failed to create fifo')
endif
endif
call fzf#vim#ipc#restart()
return g:fzf_ipc.fifo
endfunction
function! fzf#vim#ipc#restart()
if !exists('g:fzf_ipc')
throw 'fzf#vim#ipc not started'
endif
let Callback = g:fzf_ipc.callback
if exists('*job_start')
let g:fzf_ipc.job = job_start(
\ ['cat', g:fzf_ipc.fifo],
\ {'out_cb': { _, msg -> call(Callback, [msg]) },
\ 'exit_cb': { _, status -> status == 0 ? fzf#vim#ipc#restart() : '' }}
\ )
else
let eof = ['']
let g:fzf_ipc.job = jobstart(
\ ['cat', g:fzf_ipc.fifo],
\ {'stdout_buffered': 1,
\ 'on_stdout': { j, msg, e -> msg != eof ? call(Callback, msg) : '' },
\ 'on_exit': { j, status, e -> status == 0 ? fzf#vim#ipc#restart() : '' }}
\ )
endif
endfunction
function! fzf#vim#ipc#stop()
if !exists('g:fzf_ipc')
return
endif
let job = g:fzf_ipc.job
if exists('*job_stop')
call job_stop(job)
else
call jobstop(job)
call jobwait([job])
endif
call delete(g:fzf_ipc.fifo)
unlet g:fzf_ipc
endfunction

Some files were not shown because too many files have changed in this diff Show More