Refactor LSP configuration and remove Kite plugin. Updated key mappings for comments and added Python-specific tab settings. Enhanced Treesitter installation list and integrated Ruff LSP for Python. Cleaned up Kite-related files and configurations.

This commit is contained in:
fl4viooliveira 2026-03-31 07:59:45 +01:00
parent de2d52b4dc
commit 643789d616
13 changed files with 110 additions and 983 deletions

View File

@ -151,12 +151,12 @@ require('lazy').setup({
'numToStr/Comment.nvim', 'numToStr/Comment.nvim',
opts = { opts = {
toggler = { toggler = {
line = '<leader>/', -- Changed from <gc> line = 'gc',
block = '<leader>b', -- Changed from <gb> block = 'gb',
}, },
opleader = { opleader = {
line = '<leader>/', -- Optional line = 'gc',
block = '<leader>B', -- Optional block = 'gb',
}, },
} }
}, },
@ -216,6 +216,15 @@ vim.o.softtabstop = 2
vim.o.shiftwidth = 2 vim.o.shiftwidth = 2
vim.o.expandtab = true vim.o.expandtab = true
vim.api.nvim_create_autocmd('FileType', {
pattern = { 'python' },
callback = function()
vim.bo.tabstop = 4
vim.bo.softtabstop = 4
vim.bo.shiftwidth = 4
end,
})
-- Basic keymaps -- Basic keymaps
vim.keymap.set({ 'n', 'v' }, '<Space>', '<Nop>', { silent = true }) vim.keymap.set({ 'n', 'v' }, '<Space>', '<Nop>', { silent = true })
vim.keymap.set('n', 'k', "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true }) vim.keymap.set('n', 'k', "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true })
@ -257,7 +266,27 @@ end, { desc = '[/] Fuzzily search in current buffer' })
-- Treesitter configuration -- Treesitter configuration
vim.defer_fn(function() vim.defer_fn(function()
require('nvim-treesitter.configs').setup { require('nvim-treesitter.configs').setup {
ensure_installed = { 'c', 'cpp', 'go', 'lua', 'python', 'rust', 'tsx', 'javascript', 'typescript', 'vimdoc', 'vim', 'bash' }, ensure_installed = {
'c',
'cpp',
'go',
'lua',
'python',
'rust',
'tsx',
'javascript',
'typescript',
'vimdoc',
'vim',
'bash',
'html',
'css',
'json',
'toml',
'yaml',
'dockerfile',
'htmldjango',
},
auto_install = false, auto_install = false,
highlight = { enable = true }, highlight = { enable = true },
indent = { enable = true }, indent = { enable = true },
@ -357,12 +386,54 @@ end
require('mason').setup() require('mason').setup()
require('mason-lspconfig').setup() require('mason-lspconfig').setup()
local servers = { lua_ls = { Lua = { workspace = { checkThirdParty = false }, telemetry = { enable = false } } } } local lspconfig = require 'lspconfig'
local servers = {
pyright = {
python = {
analysis = {
autoSearchPaths = true,
diagnosticMode = 'openFilesOnly',
useLibraryCodeForTypes = true,
},
},
},
lua_ls = {
Lua = {
workspace = { checkThirdParty = false },
telemetry = { enable = false },
},
},
}
local capabilities = require('cmp_nvim_lsp').default_capabilities(vim.lsp.protocol.make_client_capabilities()) local capabilities = require('cmp_nvim_lsp').default_capabilities(vim.lsp.protocol.make_client_capabilities())
local mason_lspconfig = require 'mason-lspconfig' local mason_lspconfig = require 'mason-lspconfig'
mason_lspconfig.setup { ensure_installed = vim.tbl_keys(servers) } mason_lspconfig.setup { ensure_installed = vim.tbl_keys(servers) }
mason_lspconfig.setup_handlers { function(server_name) require('lspconfig')[server_name].setup { capabilities = capabilities, on_attach = on_attach, settings = servers[server_name], filetypes = (servers[server_name] or {}).filetypes, } end } mason_lspconfig.setup_handlers { function(server_name) require('lspconfig')[server_name].setup { capabilities = capabilities, on_attach = on_attach, settings = servers[server_name], filetypes = (servers[server_name] or {}).filetypes, } end }
-- Ruff installation via Mason can fail on some Python setups.
-- If a system ruff binary exists, attach Ruff LSP directly.
local ruff_server = nil
if lspconfig.ruff then
ruff_server = 'ruff'
elseif lspconfig.ruff_lsp then
ruff_server = 'ruff_lsp'
end
if vim.fn.executable 'ruff' == 1 and ruff_server then
lspconfig[ruff_server].setup {
capabilities = capabilities,
on_attach = on_attach,
}
end
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
local client = vim.lsp.get_client_by_id(args.data.client_id)
if client and (client.name == 'ruff' or client.name == 'ruff_lsp') then
client.server_capabilities.hoverProvider = false
end
end,
})
-- CMP setup -- CMP setup
local cmp = require 'cmp' local cmp = require 'cmp'
local luasnip = require 'luasnip' local luasnip = require 'luasnip'
@ -408,13 +479,10 @@ cmp.setup {
{ name = 'nvim_lsp' }, { name = 'nvim_lsp' },
{ name = 'luasnip' }, { name = 'luasnip' },
}, },
}
require("cmp").setup({
formatting = { formatting = {
format = require("tailwindcss-colorizer-cmp").formatter format = require('tailwindcss-colorizer-cmp').formatter,
} },
}) }
require("colorizer").setup { require("colorizer").setup {
user_default_options = { user_default_options = {

View File

@ -4,13 +4,6 @@
-- See the kickstart.nvim README for more information -- See the kickstart.nvim README for more information
return { return {
{
'neovim/nvim-lspconfig',
config = function()
require('custom.plugins.lspconfig') -- This simply loads the lspconfig.lua file
end,
},
-- nvim-autopairs configuration -- nvim-autopairs configuration
{ {
"windwp/nvim-autopairs", "windwp/nvim-autopairs",

View File

@ -4,18 +4,18 @@
-- Adds additional commands as well to manage the behavior -- Adds additional commands as well to manage the behavior
return { return {
'neovim/nvim-lspconfig', 'stevearc/conform.nvim',
'jose-elias-alvarez/null-ls.nvim', event = { 'BufReadPre', 'BufNewFile' },
cmd = { 'ConformInfo' },
config = function() config = function()
-- Force .html files to be recognized as htmldjango for Jinja compatibility -- Force .html files to be recognized as htmldjango for Jinja compatibility
vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, {
pattern = "*.html", pattern = '*.html',
callback = function() callback = function()
vim.bo.filetype = "htmldjango" vim.bo.filetype = 'htmldjango'
end, end,
}) })
-- Switch for controlling whether you want autoformatting.
-- Use :KickstartFormatToggle to toggle autoformatting on or off -- Use :KickstartFormatToggle to toggle autoformatting on or off
local format_is_enabled = true local format_is_enabled = true
vim.api.nvim_create_user_command('KickstartFormatToggle', function() vim.api.nvim_create_user_command('KickstartFormatToggle', function()
@ -23,71 +23,28 @@ return {
print('Setting autoformatting to: ' .. tostring(format_is_enabled)) print('Setting autoformatting to: ' .. tostring(format_is_enabled))
end, {}) end, {})
-- Create an augroup that is used for managing our formatting autocmds. require('conform').setup {
-- We need one augroup per client to make sure that multiple clients formatters_by_ft = {
-- can attach to the same buffer without interfering with each other. python = { 'ruff_organize_imports', 'ruff_format' },
local _augroups = {} htmldjango = { 'djlint' },
local get_augroup = function(client) html = { 'prettier' },
if not _augroups[client.id] then css = { 'prettier' },
local group_name = 'kickstart-lsp-format-' .. client.name javascript = { 'prettier' },
local id = vim.api.nvim_create_augroup(group_name, { clear = true }) json = { 'prettier' },
_augroups[client.id] = id yaml = { 'prettier' },
end },
format_on_save = function(bufnr)
return _augroups[client.id]
end
-- Whenever an LSP attaches to a buffer, we will run this function.
--
-- See `:help LspAttach` for more information about this autocmd event.
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('kickstart-lsp-attach-format', { clear = true }),
-- This is where we attach the autoformatting for reasonable clients
callback = function(args)
local client_id = args.data.client_id
local client = vim.lsp.get_client_by_id(client_id)
local bufnr = args.buf
-- Only attach to clients that support document formatting
if not client.server_capabilities.documentFormattingProvider then
return
end
-- Tsserver usually works poorly. Sorry you work with bad languages
-- You can remove this line if you know what you're doing :)
if client.name == 'tsserver' then
return
end
-- Create an autocmd that will run *before* we save the buffer.
-- Run the formatting command for the LSP that has just attached.
vim.api.nvim_create_autocmd('BufWritePre', {
group = get_augroup(client),
buffer = bufnr,
callback = function()
if not format_is_enabled then if not format_is_enabled then
return return nil
end end
vim.lsp.buf.format { return {
async = false, timeout_ms = 1000,
filter = function(c) lsp_format = 'fallback',
return c.id == client.id bufnr = bufnr,
}
end, end,
} }
end, end,
})
end,
})
-- Set up null-ls for additional formatting needs
null_ls.setup({
sources = {
null_ls.builtins.formatting.prettier.with({
filetypes = { "html", "jinja", "htmldjango" },
}),
},
})
end,
} }

View File

@ -20,6 +20,7 @@ return {
-- Add your own debuggers here -- Add your own debuggers here
'leoluz/nvim-dap-go', 'leoluz/nvim-dap-go',
'mfussenegger/nvim-dap-python',
}, },
config = function() config = function()
local dap = require 'dap' local dap = require 'dap'
@ -39,6 +40,7 @@ return {
ensure_installed = { ensure_installed = {
-- Update this to ensure that you have the debuggers for the langs you want -- Update this to ensure that you have the debuggers for the langs you want
'delve', 'delve',
'debugpy',
}, },
} }
@ -83,5 +85,6 @@ return {
-- Install golang specific config -- Install golang specific config
require('dap-go').setup() require('dap-go').setup()
require('dap-python').setup(vim.fn.exepath 'python3')
end, end,
} }

View File

@ -1,36 +0,0 @@
dist: trusty
env:
global:
- DEPS=$HOME/deps
- PATH=$DEPS/bin:$PATH
before_install:
- sudo apt-get install python-pip
- pip install --user awscli
- export PATH="$PATH:$HOME/.local/bin"
- curl --silent -L "https://s3-us-west-1.amazonaws.com/kite-data/tensorflow/libtensorflow-cpu-linux-x86_64-1.9.0.tar.gz" | tar -C $HOME -xz
- curl --silent --compressed --output "$HOME/kited-test" "https://s3-us-west-1.amazonaws.com/kited-test/linux/kited-test"
- chmod u+x "$HOME/kited-test"
install: |
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
C_OPTS="--prefix=$DEPS --with-features=huge --disable-gui "
git clone --depth 1 https://github.com/vim/vim
cd vim
export PATH=/usr/bin:$PATH
./configure $C_OPTS
make
make install
cd -
export PATH=$DEPS/bin:$PATH
export VIM="$(which vim)"
script:
- vim --version
- cd test && bash test
- export LD_LIBRARY_PATH="$HOME/lib:$LD_LIBRARY_PATH"
- echo "Running tests with kited-local --------------" && $HOME/kited-test > ~/kite.log 2>&1 & sleep 20 && bash editor_tests && killall kited-test

View File

@ -1,4 +0,0 @@
Copyright (c) 2017 Manhattan Engineering, Inc - All Rights Reserved
Reproduction of this material is strictly forbidden unless prior written
permission is obtained from Manhattan Engineering, Inc.

View File

@ -1,24 +0,0 @@
function! kite#docs#docs()
if &filetype != 'python'
call kite#utils#warn('Docs are only available for Python')
return
endif
if empty(expand('<cword>')) | return | endif
let b:kite_id = ''
call kite#hover#hover()
while b:kite_id == ''
sleep 5m
endwhile
if b:kite_id == -1
call kite#utils#info('No documentation available.')
return
endif
call kite#client#docs(b:kite_id)
endfunction

View File

@ -1,46 +0,0 @@
let s:events_pending = 0
function! kite#events#any_events_pending()
return s:events_pending > 0
endfunction
function! kite#events#event(action)
let filename = kite#utils#filepath(0)
if wordcount().bytes < kite#max_file_size()
let action = a:action
let text = kite#utils#buffer_contents()
else
let action = 'skip'
let text = ''
endif
let [sel_start, sel_end] = kite#utils#selected_region_characters()
if [sel_start, sel_end] == [-1, -1]
return
endif
let selections = [{ 'start': sel_start, 'end': sel_end, 'encoding': 'utf-32' }]
let json = json_encode({
\ 'source': 'vim',
\ 'filename': filename,
\ 'text': text,
\ 'action': action,
\ 'selections': selections,
\ 'editor_version': kite#utils#vim_version(),
\ 'plugin_version': kite#utils#plugin_version()
\ })
let s:events_pending += 1
call kite#client#post_event(json, function('kite#events#handler', [bufnr('')]))
endfunction
function! kite#events#handler(bufnr, response)
let s:events_pending -= 1
call setbufvar(a:bufnr, 'kite_skip', (a:response.status == 0 || a:response.status == 403))
endfunction

View File

@ -1,65 +0,0 @@
let s:languages_supported_by_kited = []
" Returns true if we want Kite completions for the current buffer, false otherwise.
function! kite#languages#supported_by_plugin()
" Return false if the file extension is not recognised by kited.
let recognised_extensions = [
\ 'c',
\ 'cc',
\ 'cpp',
\ 'cs',
\ 'css',
\ 'go',
\ 'h',
\ 'hpp',
\ 'html',
\ 'java',
\ 'js',
\ 'jsx',
\ 'kt',
\ 'less',
\ 'm',
\ 'php',
\ 'py',
\ 'pyw',
\ 'rb',
\ 'scala',
\ 'sh',
\ 'ts',
\ 'tsx',
\ 'vue',
\ ]
if index(recognised_extensions, expand('%:e')) == -1
return 0
endif
if g:kite_supported_languages == ['*']
return 1
endif
" Return false if the buffer's language is not one for which we want Kite completions.
if index(g:kite_supported_languages, &filetype) == -1
return 0
endif
return 1
endfunction
" Returns true if the current buffer's language is supported by kited, false otherwise.
function! kite#languages#supported_by_kited()
" Only check kited's languages once.
if empty(s:languages_supported_by_kited)
" A list of language names, e.g. ['bash', 'c', 'javascript', 'ruby', ...]
let s:languages_supported_by_kited = kite#client#languages(function('kite#languages#handler'))
endif
return index(s:languages_supported_by_kited, &filetype) != -1
endfunction
function! kite#languages#handler(response)
if a:response.status != 200 | return [] | endif
return json_decode(a:response.body)
endfunction

View File

@ -1,209 +0,0 @@
let s:completion_counter = 0
function! kite#signature#increment_completion_counter()
let s:completion_counter = s:completion_counter + 1
endfunction
function! kite#signature#completion_counter()
return s:completion_counter
endfunction
function! kite#signature#handler(counter, startcol, response) abort
call kite#utils#log('signature: '.a:response.status)
" Ignore old completion results.
if a:counter != s:completion_counter
return
endif
if a:response.status != 200
return
endif
let json = json_decode(a:response.body)
let call = g:kite#document#Document.New(json.calls[0])
let function_name = call.dig('func_name', '')
if empty(function_name)
let function_name = call.dig('callee.repr', '')
endif
let function_name = split(function_name, '\.')[-1]
let spacer = {'word': '', 'empty': 1, 'dup': 1}
let indent = ' '
let completions = []
let wrap_width = 50
"
" Signature
"
let parameters = []
let return_type = ''
let [current_arg, in_kwargs] = [call.dig('arg_index', 0), call.dig('language_details.python.in_kwargs', 0)]
let kind = call.dig('callee.kind', '')
" 1. Name of function with parameters.
if kind ==# 'function'
" 1.b.1. Parameters
for parameter in call.dig('callee.details.function.parameters', [])
" 1.b.1.a. Name
let name = parameter.name
" 1.b.1.b. Default value
if kite#utils#present(parameter.language_details.python, 'default_value')
let name .= '='.parameter.language_details.python.default_value[0].repr
endif
" 2. Highlight current argument
if !in_kwargs && len(parameters) == current_arg
let name = '*'.name.'*'
endif
call add(parameters, name)
endfor
" 1.b.2. vararg indicator
let vararg = call.dig('callee.details.function.language_details.python.vararg', {})
if !empty(vararg)
call add(parameters, '*'.vararg.name)
endif
" 1.b.3. keyword arguments indicator
let kwarg = call.dig('callee.details.function.language_details.python.kwarg', {})
if !empty(kwarg)
call add(parameters, '**'.kwarg.name)
endif
" 1.b.4. Return type
let return_value = call.dig('callee.details.function.return_value', [])
if !empty(return_value)
let return_type = ' -> '.return_value[0].type
endif
elseif kind ==# 'type'
" 1.c.1. Parameters
for parameter in call.dig('callee.details.type.language_details.python.constructor.parameters', [])
" 1.c.1.a. Name
let name = parameter.name
" 1.c.1.b. Default value
if kite#utils#present(parameter.language_details.python, 'default_value')
let name .= '='.parameter.language_details.python.default_value[0].repr
endif
" 2. Highlight current argument
if !in_kwargs && len(parameters) == current_arg
let name = '*'.name.'*'
endif
call add(parameters, name)
endfor
" 1.c.2. vararg indicator
let vararg = call.dig('callee.details.type.language_details.python.constructor.language_details.python.vararg', {})
if !empty(vararg)
call add(parameters, '*'.vararg.name)
endif
" 1.c.3. keyword arguments indicator
let kwarg = call.dig('callee.details.type.language_details.python.constructor.language_details.python.kwarg', {})
if !empty(kwarg)
call add(parameters, '*'.kwarg.name)
endif
" 1.c.4. Return type
let return_type = ' -> '.function_name
endif
" The completion popup does not wrap long lines so we wrap manually.
for line in kite#utils#wrap(kite#symbol().' '.function_name.'('.join(parameters, ', ').')'.return_type, wrap_width, 4)
let completion = {
\ 'word': '',
\ 'abbr': line,
\ 'empty': 1,
\ 'dup': 1
\ }
call add(completions, completion)
endfor
" 3. Keyword arguments
let kwarg_parameters = call.dig('callee.details.function.kwarg_parameters', [])
if !empty(kwarg_parameters)
call add(completions, spacer)
call add(completions, s:heading('**kw'))
for kwarg in kwarg_parameters
let name = kwarg.name
let types = kite#utils#map_join(kwarg.inferred_value, 'repr', '|')
if empty(types)
let types = ''
endif
call add(completions, {
\ 'word': name.'=',
\ 'abbr': indent.name,
\ 'menu': types,
\ 'empty': 1,
\ 'dup': 1
\ })
endfor
endif
" 4. Popular patterns
if kite#signature#should_show_popular_patterns()
let signatures = call.dig('signatures', [])
if len(signatures) > 0
call add(completions, spacer)
call add(completions, s:heading('How Others Used This'))
endif
for signature in signatures
let sigdoc = g:kite#document#Document.New(signature)
" b. Arguments
let arguments = []
for arg in sigdoc.dig('args', [])
call add(arguments, arg.name)
endfor
" c. Keyword arguments
for kwarg in sigdoc.dig('language_details.python.kwargs', [])
let name = kwarg.name
let examples = kite#utils#coerce(kwarg.types[0], 'examples', [])
if len(examples) > 0
let name .= '='.examples[0]
endif
call add(arguments, name)
endfor
for line in kite#utils#wrap(function_name.'('.join(arguments, ', ').')', wrap_width, 2)
let completion = {
\ 'word': '',
\ 'abbr': indent.line,
\ 'empty': 1,
\ 'equal': 1,
\ 'dup': 1
\ }
call add(completions, completion)
endfor
endfor
endif
if mode(1) ==# 'i'
call complete(a:startcol+1, completions)
endif
endfunction
function! kite#signature#should_show_popular_patterns()
return kite#utils#get_setting('show_popular_patterns', 0)
endfunction
function! kite#signature#show_popular_patterns()
call kite#utils#set_setting('show_popular_patterns', 1)
endfunction
function! kite#signature#hide_popular_patterns()
call kite#utils#set_setting('show_popular_patterns', 0)
endfunction
function s:heading(text)
return {'abbr': a:text.':', 'word': '', 'empty': 1, 'dup': 1}
endfunction

View File

@ -1,413 +0,0 @@
function! s:setup_stack()
if exists('b:kite_stack') | return | endif
" stack:
" [
" { index: 0, placeholders: { ... } }, <-- depth 0
" { index: 0, placeholders: { ... } }, <-- depth 1
" ... <-- depth n
" ]
"
" index - the currently active placeholder at that depth
let b:kite_stack = {'stack': []}
function! b:kite_stack.pop()
return remove(self.stack, -1)
endfunction
function! b:kite_stack.peek()
return get(self.stack, -1)
endfunction
function! b:kite_stack.push(item)
call add(self.stack, a:item)
endfunction
function! b:kite_stack.is_empty()
return empty(self.stack)
endfunction
function! b:kite_stack.empty()
let self.stack = []
endfunction
endfunction
function! kite#snippet#complete_done()
if empty(v:completed_item) | return | endif
call s:setup_stack()
if has_key(v:completed_item, 'user_data') && !empty(v:completed_item.user_data)
let placeholders = json_decode(v:completed_item.user_data).placeholders
elseif exists('b:kite_completions') && has_key(b:kite_completions, v:completed_item.word)
let placeholders = json_decode(b:kite_completions[v:completed_item.word]).placeholders
let b:kite_completions = {}
else
return
endif
" Send the edit event. Normally this is sent automatically on TextChanged(I).
" But for some reason this doesn't fire when a completion has a snippet placeholder.
call kite#events#event('edit')
if empty(placeholders)
if b:kite_stack.is_empty()
return
else
call kite#snippet#next_placeholder()
return
endif
endif
let b:kite_linenr = line('.')
let b:kite_line_length = col('$')
call s:setup_maps()
call s:setup_autocmds()
" Calculate column number (col_begin) of start of each placeholder, and placeholder length.
let inserted_text = v:completed_item.word
let insertion_start = col('.') - strdisplaywidth(inserted_text)
let b:kite_insertion_end = col('.')
for ph in placeholders
let ph.col_begin = insertion_start + ph.begin
let ph.length = ph.end - ph.begin
unlet ph.begin ph.end
endfor
" Update placeholder locations.
"
" todo move this into the push() function?
" note this is very similar to s:update_placeholder_locations()
if !b:kite_stack.is_empty()
" current placeholder which has just been completed
let level = b:kite_stack.peek()
let ph = level.placeholders[level.index]
let ph_new_length = col('.') - ph.col_begin
let ph_length_delta = ph_new_length - ph.length
let ph.length = ph_new_length
let marker = ph.col_begin
" following placeholders at same level
for ph in level.placeholders[level.index+1:]
let ph.col_begin += ph_length_delta
endfor
" placeholders at outer levels
for level in b:kite_stack.stack[:-2]
for ph in level.placeholders
if ph.col_begin > marker
let ph.col_begin += ph_length_delta
endif
endfor
endfor
endif
call b:kite_stack.push({'placeholders': placeholders, 'index': 0})
" Move to first placeholder.
call s:placeholder(0)
endfunction
" Go to next placeholder at current level, if there is one, or first placeholder at next level otherwise.
function! kite#snippet#next_placeholder()
call s:update_placeholder_locations()
call s:placeholder(b:kite_stack.peek().index + 1)
endfunction
function! kite#snippet#previous_placeholder(...)
call s:placeholder(b:kite_stack.peek().index - 1 - (a:0 ? a:1 : 0))
endfunction
" Move to the placeholder at index and select its text.
function! s:placeholder(index)
let index = a:index
let level = b:kite_stack.peek()
let placeholders = level.placeholders
" Clear highlights before we pop the stack.
call s:clear_all_placeholder_highlights()
if index < 0
" If no other levels in stack
if len(b:kite_stack.stack) == 1
" Stay with first placeholder and proceed
let index = 0
else
call b:kite_stack.pop()
call s:placeholder(b:kite_stack.peek().index - 1)
return
endif
endif
" if navigating forward from last placeholder of current level
if index == len(placeholders)
" If no other levels in stack
if len(b:kite_stack.stack) == 1
call s:goto_initial_completion_end()
else
call b:kite_stack.pop()
call s:placeholder(b:kite_stack.peek().index + 1)
endif
return
endif
call s:highlight_current_level_placeholders()
let level.index = index
let ph = placeholders[index]
" store line length before placeholder gets changed by user
" let b:kite_line_length = col('$')
if ph.length == 0
normal! h
return
endif
" insert mode -> normal mode
stopinsert
let linenr = line('.')
call setpos("'<", [0, linenr, ph.col_begin])
call setpos("'>", [0, linenr, ph.col_begin + ph.length - (mode() == 'n' ? 1 : 0)])
" normal mode -> visual mode -> select mode
execute "normal! gv\<C-G>"
if mode() ==# 'S'
execute "normal! \<C-O>gh"
endif
endfunction
function! s:goto_initial_completion_end()
" call setpos('.', [0, b:kite_linenr, b:kite_insertion_end + col('$') - b:kite_line_length - 1])
call setpos('.', [0, b:kite_linenr, col('$')])
startinsert!
call s:teardown()
endfunction
" Adjust current and subsequent placeholders for the amount of text entered
" at the placeholder we are leaving.
function! s:update_placeholder_locations()
if !exists('b:kite_line_length') | return | endif
let line_length_delta = col('$') - b:kite_line_length
" current placeholder
let level = b:kite_stack.peek()
let ph = level.placeholders[level.index]
let marker = ph.col_begin
let ph.length += line_length_delta
" subsequent placeholders at current level
for ph in level.placeholders[level.index+1:]
let ph.col_begin += line_length_delta
endfor
" placeholders at outer levels
for level in b:kite_stack.stack[:-2]
for ph in level.placeholders
if ph.col_begin > marker
let ph.col_begin += line_length_delta
endif
endfor
endfor
let b:kite_line_length = col('$')
endfunction
function! s:highlight_current_level_placeholders()
let group = s:highlight_group_for_placeholders()
if empty(group) | return | endif
let linenr = line('.')
for ph in b:kite_stack.peek().placeholders
let ph.matchid = matchaddpos(group, [[linenr, ph.col_begin, ph.length]])
endfor
endfunction
" Clears highlights of placeholders in the stack.
"
" Note: if we need a way to clear highlights of placeholders which are no
" longer in the stack (because they have been popped) we could use a custom
" highlight group (e.g. KiteUnderline linked to Underline), call getmatches(),
" and remove all matches using the custom highlight group.
function! s:clear_all_placeholder_highlights()
for level in b:kite_stack.stack
for ph in level.placeholders
if has_key(ph, 'matchid')
call matchdelete(ph.matchid)
unlet ph.matchid
endif
endfor
endfor
endfunction
" Many plugins use vmap for visual-mode mappings but vmap maps both
" visual-mode and select-mode (they should use xmap instead). Assume any
" visual-mode mappings for printable characters are not wanted and remove them
" (but remember them so we can restore them afterwards). Similarly for map.
" Assume any select-only-mode maps are deliberate.
"
" :help mapmode-s
" :help Select-mode-mapping
function! s:remove_smaps_for_printable_characters()
let b:kite_maps = []
let printable_keycodes = [
\ '<Space>',
\ '<Bslash>',
\ '<Tab>',
\ '<C-Tab>',
\ '<NL>',
\ '<CR>',
\ '<BS>',
\ '<Leader>',
\ '<LocalLeader>'
\ ]
" Get a list of maps active in select mode.
for scope in ['<buffer>', '']
redir => maps | silent execute 'smap' scope | redir END
let mappings = split(maps, "\n")
" 'No mapping found' or localised equivalent (starts with capital letter).
if len(mappings) == 1 && mappings[0][0] =~ '\u' | continue | endif
" Assume select-mode maps are deliberate and ignore them.
call filter(mappings, 'v:val[0:2] !~# "s"')
for mapping in mappings
let lhs = matchlist(mapping, '\v^...(\S+)\s.*')[1]
" ^^^ ^^^
" mode lhs
" Ignore keycodes for non-printable characters, e.g. <Left>
if lhs[0] == '<' && index(printable_keycodes, lhs) == -1 | continue | endif
" Remember the mapping so we can restore it later.
call add(b:kite_maps, maparg(lhs, 's', 0, 1))
" Remove the mapping.
silent! execute 'sunmap' scope lhs
endfor
endfor
endfunction
function! s:restore_smaps()
for mapping in b:kite_maps
silent! execute mapping.mode . (mapping.noremap ? 'nore' : '') . 'map '
\ . (mapping.buffer ? '<buffer> ' : '')
\ . (mapping.expr ? '<expr> ' : '')
\ . (mapping.nowait ? '<nowait> ' : '')
\ . (mapping.silent ? '<silent> ' : '')
\ . mapping.lhs . ' '
\ . substitute(mapping.rhs, '<SID>', '<SNR>'.mapping.sid.'_', 'g')
endfor
unlet! b:kite_maps
endfunction
function! s:setup_maps()
execute 'inoremap <buffer> <silent> <expr>' g:kite_next_placeholder 'pumvisible() ? "<C-Y>" : "<C-\><C-O>:call kite#snippet#next_placeholder()<CR>"'
execute 'inoremap <buffer> <silent> <expr>' g:kite_previous_placeholder 'pumvisible() ? "<C-Y><C-G>:<C-U>call kite#snippet#previous_placeholder(2)<CR>" : "<C-\><C-O>:call kite#snippet#previous_placeholder()<CR>"'
execute 'snoremap <buffer> <silent>' g:kite_next_placeholder '<Esc>:call kite#snippet#next_placeholder()<CR>'
execute 'snoremap <buffer> <silent>' g:kite_previous_placeholder '<Esc>:call kite#snippet#previous_placeholder()<CR>'
call s:remove_smaps_for_printable_characters()
endfunction
function! kite#snippet#teardown_maps()
execute 'silent! iunmap <buffer>' g:kite_next_placeholder
execute 'silent! iunmap <buffer>' g:kite_previous_placeholder
execute 'silent! sunmap <buffer>' g:kite_next_placeholder
execute 'silent! sunmap <buffer>' g:kite_previous_placeholder
endfunction
function! s:setup_autocmds()
augroup KiteSnippets
autocmd! * <buffer>
autocmd CursorMovedI <buffer>
\ call s:update_placeholder_locations() |
\ call s:clear_all_placeholder_highlights() |
\ call s:highlight_current_level_placeholders()
autocmd CursorMoved,CursorMovedI <buffer> call s:cursormoved()
autocmd InsertLeave <buffer> call s:insertleave()
augroup END
endfunction
function! s:teardown_autocmds()
autocmd! KiteSnippets * <buffer>
endfunction
" Called to deactivate all placeholders.
function! s:teardown()
call s:clear_all_placeholder_highlights()
call kite#snippet#teardown_maps()
call s:teardown_autocmds()
call s:restore_smaps()
call b:kite_stack.empty()
unlet! b:kite_linenr b:kite_line_length b:kite_insertion_end
endfunction
function! s:highlight_group_for_placeholders()
for group in ['Special', 'SpecialKey', 'Underline', 'DiffChange']
if hlexists(group)
return group
endif
endfor
return ''
endfunction
function! s:cursormoved()
if !exists('b:kite_linenr') | return | endif
if b:kite_linenr == line('.') | return | endif
" TODO check whether the cursor is outside the bounds of the completion?
call s:teardown()
endfunction
function! s:insertleave()
" Modes established by experimentation.
if mode(1) !=# 's' && mode(1) !=# ((has('patch-8.1.0225') || has('nvim-0.4.0')) ? 'niI' : 'n')
call s:teardown()
endif
endfunction
function! s:debug_stack()
if b:kite_stack.is_empty()
echom 'stack empty'
return
endif
let i = 0
for level in b:kite_stack.stack
echom 'level' i
echom ' index' level.index
for pholder in level.placeholders
echom ' '.string(pholder)
endfor
let i += 1
endfor
endfunction

View File

@ -1,62 +0,0 @@
" Updates the status of the current buffer.
"
" Optional argument is a timer id (when called by a timer).
function! kite#status#status(...)
if !s:status_in_status_line() | return | endif
let buf = bufnr('')
let msg = 'NOT SET'
" Check kited status (installed / running) every 10 file status checks.
let counter = getbufvar(buf, 'kite_status_counter', 0)
if counter == 0
if !kite#utils#kite_running()
let msg = 'Kite: not running'
if !kite#utils#kite_installed()
let msg = 'Kite: not installed'
endif
endif
endif
call setbufvar(buf, 'kite_status_counter', (counter + 1) % 10)
if wordcount().bytes > kite#max_file_size()
let msg = 'Kite: file too large'
endif
if msg !=# 'NOT SET'
if msg !=# getbufvar(buf, 'kite_status')
call setbufvar(buf, 'kite_status', msg)
redrawstatus
endif
return
endif
let filename = kite#utils#filepath(0)
call kite#client#status(filename, function('kite#status#handler', [buf]))
endfunction
function! kite#status#handler(buffer, response)
call kite#utils#log('kite status status: '.a:response.status.', body: '.a:response.body)
if a:response.status != 200 | return | endif
let json = json_decode(a:response.body)
let msg = ''
let suffix = get(json, 'short', 'FIELD MISSING')
if suffix !=# 'FIELD MISSING'
let msg = join(['Kite: ', suffix], '')
endif
if msg !=# getbufvar(a:buffer, 'kite_status')
call setbufvar(a:buffer, 'kite_status', msg)
redrawstatus
endif
endfunction
function! s:status_in_status_line()
return stridx(&statusline, 'kite#statusline()') != -1
endfunction

View File

@ -1,35 +0,0 @@
*kite.txt* Kite for VIM
Kite for VIM
============
VIM is now integrated with Kite! To get a taste of what Kite can do, open a
saved Python file and start coding away.
1. Autocompletions
As you code, Kite will provide autocompletion suggestions ranked by popularity
using all the open source code on GitHub.
2. Documentation
Press |K| when your cursor is over a identifier to open a split window with
documentation about the identifier. In addition to documentation, Kite also
provides information about where you've used the identifier in your codebase,
as well as curated code examples showing you how to use the identifier.
3. Goto Definition
Press |C-]| to jump to a method's defintion.
4. Copilot integration
While you code in VIM, the Copilot will automatically show you information
about the code that you're currently working with. To open the Copilot, click
on the Kite menubar icon and select "Open Copilot".
To learn more about Kite and how to use the VIM plugin, visit our [help
page](http://help.kite.com).
vim:tw=78:et:ft=help:norl