convert to vim9
This commit is contained in:
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -19,3 +19,9 @@
|
|||||||
[submodule "vim/.vim/pack/plugins/start/copilot.vim"]
|
[submodule "vim/.vim/pack/plugins/start/copilot.vim"]
|
||||||
path = vim/.vim/pack/plugins/start/copilot.vim
|
path = vim/.vim/pack/plugins/start/copilot.vim
|
||||||
url = https://github.com/github/copilot.vim.git
|
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
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
# set API keys via environment variables, like CLAUDE_API_KEY
|
# set API keys via environment variables, like CLAUDE_API_KEY
|
||||||
# environment variables for aichat can be set at ~/.config/aichat/.env
|
# 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
|
keybindings: vi
|
||||||
repl_prelude: role:cloudops
|
repl_prelude: role:cloudops
|
||||||
clients:
|
clients:
|
||||||
|
|||||||
5
aichat/.config/aichat/roles/none.md
Normal file
5
aichat/.config/aichat/roles/none.md
Normal 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.
|
||||||
3
aichat/.config/aichat/roles/vim.md
Normal file
3
aichat/.config/aichat/roles/vim.md
Normal 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.
|
||||||
@@ -5,4 +5,4 @@ export PAGER=less
|
|||||||
export LESS=RX # R for ANSI color sequences, X to not clear screen on exit
|
export LESS=RX # R for ANSI color sequences, X to not clear screen on exit
|
||||||
export TMPDIR=/var/tmp
|
export TMPDIR=/var/tmp
|
||||||
export PS1="\w $ "
|
export PS1="\w $ "
|
||||||
export PATH=${PATH}:~/bin
|
export PATH=${PATH}:~/.local/bin
|
||||||
|
|||||||
3
vim/.config/vim/.netrwhist
Normal file
3
vim/.config/vim/.netrwhist
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
let g:netrw_dirhistmax =10
|
||||||
|
let g:netrw_dirhistcnt =1
|
||||||
|
let g:netrw_dirhist_1='/home/cli'
|
||||||
2
vim/.config/vim/pack/plugins/start/copilot.vim/.gitattributes
vendored
Normal file
2
vim/.config/vim/pack/plugins/start/copilot.vim/.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.vim eol=lf
|
||||||
|
/copilot-language-server/** -whitespace -diff
|
||||||
1
vim/.config/vim/pack/plugins/start/copilot.vim/.github/pull_request_template.md
vendored
Normal file
1
vim/.config/vim/pack/plugins/start/copilot.vim/.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
At the moment we are not accepting contributions to the repository.
|
||||||
20
vim/.config/vim/pack/plugins/start/copilot.vim/.github/workflows/auto-close-pr.yml
vendored
Normal file
20
vim/.config/vim/pack/plugins/start/copilot.vim/.github/workflows/auto-close-pr.yml
vendored
Normal 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 }}
|
||||||
1
vim/.config/vim/pack/plugins/start/copilot.vim/.gitignore
vendored
Normal file
1
vim/.config/vim/pack/plugins/start/copilot.vim/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/doc/tags
|
||||||
@@ -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.
|
||||||
63
vim/.config/vim/pack/plugins/start/copilot.vim/README.md
Normal file
63
vim/.config/vim/pack/plugins/start/copilot.vim/README.md
Normal 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
|
||||||
|
|
||||||
|
We’d 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).
|
||||||
@@ -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.
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
function! copilot#version#String() abort
|
||||||
|
return '1.58.0'
|
||||||
|
endfunction
|
||||||
@@ -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.
|
||||||
@@ -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
|
||||||
@@ -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 (2–10 words)}
|
||||||
|
|
||||||
|
{Brief TL;DR of the plan — the what, how, and why. (20–100 words)}
|
||||||
|
|
||||||
|
### Steps {3–6 steps, 5–20 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 {1–3, 5–25 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>
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
100256
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/cl100k_base.tiktoken
vendored
Normal file
100256
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/cl100k_base.tiktoken
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/darwin/arm64/kerberos.node
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/darwin/arm64/kerberos.node
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/darwin/arm64/node_sqlite3.node
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/darwin/arm64/node_sqlite3.node
vendored
Executable file
Binary file not shown.
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/darwin/x64/kerberos.node
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/darwin/x64/kerberos.node
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/darwin/x64/node_sqlite3.node
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/darwin/x64/node_sqlite3.node
vendored
Executable file
Binary file not shown.
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/linux/arm64/kerberos.node
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/linux/arm64/kerberos.node
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/linux/arm64/node_sqlite3.node
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/linux/arm64/node_sqlite3.node
vendored
Executable file
Binary file not shown.
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/linux/x64/kerberos.node
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/linux/x64/kerberos.node
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/linux/x64/node_sqlite3.node
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/compiled/linux/x64/node_sqlite3.node
vendored
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/crypt32-arm64.node
vendored
Normal file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/crypt32-arm64.node
vendored
Normal file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/crypt32.node
vendored
Normal file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/crypt32.node
vendored
Normal file
Binary file not shown.
43
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/diffWorker.js
vendored
Normal file
43
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/diffWorker.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
32
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/language-server.js
vendored
Executable file
32
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/language-server.js
vendored
Executable 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();
|
||||||
3283
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/main.js
vendored
Normal file
3283
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/main.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/main.js.map
vendored
Normal file
6
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/main.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
199998
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/o200k_base.tiktoken
vendored
Normal file
199998
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/o200k_base.tiktoken
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||||
@@ -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)
|
||||||
@@ -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>
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
@@ -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>
|
||||||
Binary file not shown.
Binary file not shown.
131
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tfidfWorker.js
vendored
Normal file
131
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tfidfWorker.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-c-sharp.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-c-sharp.wasm
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-cpp.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-cpp.wasm
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-go.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-go.wasm
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-java.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-java.wasm
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-javascript.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-javascript.wasm
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-php.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-php.wasm
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-python.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-python.wasm
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-regex.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-regex.wasm
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-ruby.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-ruby.wasm
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-rust.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-rust.wasm
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-tsx.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-tsx.wasm
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-typescript.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter-typescript.wasm
vendored
Executable file
Binary file not shown.
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter.wasm
vendored
Executable file
BIN
vim/.config/vim/pack/plugins/start/copilot.vim/copilot-language-server/dist/tree-sitter.wasm
vendored
Executable file
Binary file not shown.
@@ -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"
|
||||||
|
}
|
||||||
228
vim/.config/vim/pack/plugins/start/copilot.vim/doc/copilot.txt
Normal file
228
vim/.config/vim/pack/plugins/start/copilot.vim/doc/copilot.txt
Normal 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:
|
||||||
104
vim/.config/vim/pack/plugins/start/copilot.vim/lua/_copilot.lua
Normal file
104
vim/.config/vim/pack/plugins/start/copilot.vim/lua/_copilot.lua
Normal 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
|
||||||
@@ -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
|
||||||
@@ -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"
|
||||||
@@ -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"
|
||||||
1
vim/.config/vim/pack/plugins/start/fzf.vim/.gitattributes
vendored
Normal file
1
vim/.config/vim/pack/plugins/start/fzf.vim/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.sh text eol=lf
|
||||||
1
vim/.config/vim/pack/plugins/start/fzf.vim/.github/FUNDING.yml
vendored
Normal file
1
vim/.config/vim/pack/plugins/start/fzf.vim/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
github: junegunn
|
||||||
49
vim/.config/vim/pack/plugins/start/fzf.vim/.github/ISSUE_TEMPLATE/issue.yml
vendored
Normal file
49
vim/.config/vim/pack/plugins/start/fzf.vim/.github/ISSUE_TEMPLATE/issue.yml
vendored
Normal 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
|
||||||
1
vim/.config/vim/pack/plugins/start/fzf.vim/.gitignore
vendored
Normal file
1
vim/.config/vim/pack/plugins/start/fzf.vim/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
doc/tags
|
||||||
21
vim/.config/vim/pack/plugins/start/fzf.vim/LICENSE
Normal file
21
vim/.config/vim/pack/plugins/start/fzf.vim/LICENSE
Normal 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.
|
||||||
489
vim/.config/vim/pack/plugins/start/fzf.vim/README.md
Normal file
489
vim/.config/vim/pack/plugins/start/fzf.vim/README.md
Normal 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
|
||||||
1836
vim/.config/vim/pack/plugins/start/fzf.vim/autoload/fzf/vim.vim
Executable file
1836
vim/.config/vim/pack/plugins/start/fzf.vim/autoload/fzf/vim.vim
Executable file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
" Copyright (c) 2023 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! fzf#vim#listproc#quickfix(list)
|
||||||
|
call setqflist(a:list)
|
||||||
|
copen
|
||||||
|
wincmd p
|
||||||
|
cfirst
|
||||||
|
normal! zvzz
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! fzf#vim#listproc#location(list)
|
||||||
|
call setloclist(0, a:list)
|
||||||
|
lopen
|
||||||
|
wincmd p
|
||||||
|
lfirst
|
||||||
|
normal! zvzz
|
||||||
|
endfunction
|
||||||
3
vim/.config/vim/pack/plugins/start/fzf.vim/bin/preview.rb
Executable file
3
vim/.config/vim/pack/plugins/start/fzf.vim/bin/preview.rb
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
puts 'preview.rb is deprecated. Use preview.sh instead.'
|
||||||
93
vim/.config/vim/pack/plugins/start/fzf.vim/bin/preview.sh
Executable file
93
vim/.config/vim/pack/plugins/start/fzf.vim/bin/preview.sh
Executable file
@@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
REVERSE="\x1b[7m"
|
||||||
|
RESET="\x1b[m"
|
||||||
|
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
echo "usage: $0 [--tag] FILENAME[:LINENO][:IGNORED]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $1 = --tag ]]; then
|
||||||
|
shift
|
||||||
|
"$(dirname "${BASH_SOURCE[0]}")/tagpreview.sh" "$@"
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ignore if an empty path is given
|
||||||
|
[[ -z $1 ]] && exit
|
||||||
|
|
||||||
|
IFS=':' read -r -a INPUT <<< "$1"
|
||||||
|
FILE=${INPUT[0]}
|
||||||
|
CENTER=${INPUT[1]}
|
||||||
|
|
||||||
|
if [[ "$1" =~ ^[A-Za-z]:\\ ]]; then
|
||||||
|
FILE=$FILE:${INPUT[1]}
|
||||||
|
CENTER=${INPUT[2]}
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$CENTER" && ! "$CENTER" =~ ^[0-9] ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
CENTER=${CENTER/[^0-9]*/}
|
||||||
|
|
||||||
|
# MS Win support
|
||||||
|
if [[ "$FILE" =~ '\' ]]; then
|
||||||
|
if [ -z "$MSWINHOME" ]; then
|
||||||
|
MSWINHOME="$HOMEDRIVE$HOMEPATH"
|
||||||
|
fi
|
||||||
|
if grep -qEi "(Microsoft|WSL)" /proc/version &> /dev/null ; then
|
||||||
|
MSWINHOME="${MSWINHOME//\\/\\\\}"
|
||||||
|
FILE="${FILE/#\~\\/$MSWINHOME\\}"
|
||||||
|
FILE=$(wslpath -u "$FILE")
|
||||||
|
elif [ -n "$MSWINHOME" ]; then
|
||||||
|
FILE="${FILE/#\~\\/$MSWINHOME\\}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
FILE="${FILE/#\~\//$HOME/}"
|
||||||
|
if [ ! -r "$FILE" ]; then
|
||||||
|
if [[ "${INPUT[0]}" != '[No Name]' ]]; then
|
||||||
|
echo "File not found ${FILE}"
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$CENTER" ]; then
|
||||||
|
CENTER=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Sometimes bat is installed as batcat.
|
||||||
|
if [[ -z "$BATCAT" ]]; then
|
||||||
|
if command -v batcat > /dev/null; then
|
||||||
|
BATCAT="batcat"
|
||||||
|
elif command -v bat > /dev/null; then
|
||||||
|
BATCAT="bat"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$FZF_PREVIEW_COMMAND" ] && [ "${BATCAT:+x}" ] && [[ ! -d "$FILE" ]] ; then
|
||||||
|
${BATCAT} --style="${BAT_STYLE:-numbers}" --color=always --pager=never \
|
||||||
|
--highlight-line=$CENTER -- "$FILE"
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
FILE_LENGTH=${#FILE}
|
||||||
|
MIME=$(file --dereference --mime -- "$FILE")
|
||||||
|
if [[ "${MIME:FILE_LENGTH}" =~ binary ]] && [[ ! -d "$FILE" ]]; then
|
||||||
|
echo "$MIME"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEFAULT_COMMAND="highlight -O ansi -l {} || coderay {} || rougify {} || cat {}"
|
||||||
|
if [[ -d "$FILE" ]]; then
|
||||||
|
DEFAULT_COMMAND="tree -C -L2 {} || ls -l --color=always {}"
|
||||||
|
fi
|
||||||
|
CMD=${FZF_PREVIEW_COMMAND:-$DEFAULT_COMMAND}
|
||||||
|
CMD=${CMD//{\}/"$(printf %q "$FILE")"}
|
||||||
|
|
||||||
|
eval "$CMD" 2> /dev/null | awk "{ \
|
||||||
|
if (NR == $CENTER) \
|
||||||
|
{ gsub(/\x1b[[0-9;]*m/, \"&$REVERSE\"); printf(\"$REVERSE%s\n$RESET\", \$0); } \
|
||||||
|
else printf(\"$RESET%s\n\", \$0); \
|
||||||
|
}"
|
||||||
73
vim/.config/vim/pack/plugins/start/fzf.vim/bin/tagpreview.sh
Executable file
73
vim/.config/vim/pack/plugins/start/fzf.vim/bin/tagpreview.sh
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
REVERSE="\x1b[7m"
|
||||||
|
RESET="\x1b[m"
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "usage: $0 FILENAME:TAGFILE:EXCMD"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS=':' read -r FILE TAGFILE EXCMD <<< "$*"
|
||||||
|
|
||||||
|
# Complete file paths which are relative to the given tag file
|
||||||
|
if [ "${FILE:0:1}" != "/" ]; then
|
||||||
|
FILE="$(dirname "${TAGFILE}")/${FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -r "$FILE" ]; then
|
||||||
|
echo "File not found ${FILE}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If users aren't using vim, they are probably using neovim
|
||||||
|
if command -v vim > /dev/null; then
|
||||||
|
VIMNAME="vim"
|
||||||
|
elif command -v nvim > /dev/null; then
|
||||||
|
VIMNAME="nvim"
|
||||||
|
else
|
||||||
|
echo "Cannot preview tag: vim or nvim unavailable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
CENTER="$("${VIMNAME}" -R -i NONE -u NONE -e -m -s "${FILE}" \
|
||||||
|
-c "set nomagic" \
|
||||||
|
-c "silent ${EXCMD}" \
|
||||||
|
-c 'let l=line(".") | new | put =l | print | qa!')" || exit
|
||||||
|
|
||||||
|
START_LINE="$(( CENTER - FZF_PREVIEW_LINES / 2 ))"
|
||||||
|
if (( START_LINE <= 0 )); then
|
||||||
|
START_LINE=1
|
||||||
|
fi
|
||||||
|
END_LINE="$(( START_LINE + FZF_PREVIEW_LINES - 1 ))"
|
||||||
|
|
||||||
|
# Sometimes bat is installed as batcat.
|
||||||
|
if command -v batcat > /dev/null; then
|
||||||
|
BATNAME="batcat"
|
||||||
|
elif command -v bat > /dev/null; then
|
||||||
|
BATNAME="bat"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$FZF_PREVIEW_COMMAND" ] && [ "${BATNAME:+x}" ]; then
|
||||||
|
${BATNAME} --style="${BAT_STYLE:-numbers}" \
|
||||||
|
--color=always \
|
||||||
|
--pager=never \
|
||||||
|
--wrap=never \
|
||||||
|
--terminal-width="${FZF_PREVIEW_COLUMNS}" \
|
||||||
|
--line-range="${START_LINE}:${END_LINE}" \
|
||||||
|
--highlight-line="${CENTER}" \
|
||||||
|
"$FILE"
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEFAULT_COMMAND="highlight -O ansi -l {} || coderay {} || rougify {} || cat {}"
|
||||||
|
CMD=${FZF_PREVIEW_COMMAND:-$DEFAULT_COMMAND}
|
||||||
|
CMD=${CMD//{\}/$(printf %q "$FILE")}
|
||||||
|
|
||||||
|
eval "$CMD" 2> /dev/null | awk "{ \
|
||||||
|
if (NR >= $START_LINE && NR <= $END_LINE) { \
|
||||||
|
if (NR == $CENTER) \
|
||||||
|
{ gsub(/\x1b[[0-9;]*m/, \"&$REVERSE\"); printf(\"$REVERSE%s\n$RESET\", \$0); } \
|
||||||
|
else printf(\"$RESET%s\n\", \$0); \
|
||||||
|
} \
|
||||||
|
}"
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user