#!/usr/bin/env bash # USAGE: To run locally: # bash .github/ci/lint.sh origin/master HEAD set -e REF_BRANCH="$1" PR_BRANCH="$2" _fail() { echo printf "lint.sh: %s\n" "$@" exit 1 } _check_generated_docs() { if ! git diff "${REF_BRANCH}"..."${PR_BRANCH}" --exit-code -- doc/configs.md doc/configs.txt; then _fail '`configs.md` or `configs.txt` will be regenerated by the docgen CI process. Edit the Lua source file instead.' \ 'For details on generating documentation, see: https://github.com/neovim/nvim-lspconfig/blob/master/CONTRIBUTING.md#generating-docs' fi } # Enforce buffer-local commands. _check_cmd_buflocal() { if git grep -P 'nvim_create_user_command' -- 'lsp/*.lua' ; then _fail 'Define commands with nvim_buf_create_user_command (buffer-local), not nvim_create_user_command' fi } # Check that "@brief" docstring is the first line of each "lsp/*.lua" config. _check_brief_placement() { if find ./lsp -type f -name "*.lua" -exec awk 'NR==1 && !/brief/{print FILENAME}' {} \; | grep --color=never '.' ; then _fail '`@brief` docstring must be at the top of the config source file' fi } # Returned object should have `---@type vim.lsp.Config` annotation. # CI checks luals/emmylua: https://github.com/neovim/nvim-lspconfig/pull/4185 _check_type() { if git grep --files-without-match '\-\-\-\@type vim\.lsp\.Config' -- 'lsp/*.lua' ; then _fail 'Missing `---@type vim.lsp.Config` annotation.' fi } # Enforce "Lsp" prefix on all user commands. _check_lsp_cmd_prefix() { local exclude='tinymist' if git grep -P 'nvim_buf_create_user_command' -- 'lsp/*.lua' | grep -v "$exclude" | grep --color -v Lsp ; then _fail 'Command names must start with "Lsp" prefix' fi } # Enforce client:exec_cmd(). _check_exec_cmd() { local exclude='eslint\|pyright\|basedpyright' if git grep -P 'workspace.executeCommand' -- 'lsp/*.lua' | grep -v "$exclude" ; then _fail 'Use client:exec_cmd() instead of calling request("workspace/executeCommand") directly. Example: lsp/pyright.lua' fi } # Disallow util functions in Nvim 0.11+ (lsp/) configs. _check_deprecated_in_nvim_0_11() { if git grep -P 'is_descendant' -- 'lsp/*.lua' ; then _fail 'Use vim.fs.relpath() instead of util.path.is_descendant()' fi if git grep -P 'search_ancestors' -- 'lsp/*.lua' ; then _fail 'Use vim.iter(vim.fs.parents(fname)):find(…) instead of util.path.search_ancestors(fname,…)' fi if git grep -P 'validate_bufnr' -- 'lsp/*.lua' ; then _fail 'Do not use util.validate_bufnr(). Nvim stdlib already treats bufnr=0 as "current buffer".' fi if git grep -P 'single_file_support' -- 'lsp/*.lua' ; then _fail 'vim.lsp.config assumes "single-file support" by default. If the LS does not support that, set workspace_required=true.' fi } _check_deprecated_utils() { # checks for added lines that contain search pattern and prints them SEARCH_PATTERN='(path\.dirname|fn\.cwd)' if git diff --pickaxe-all -U0 -G "${SEARCH_PATTERN}" "${REF_BRANCH}" "${PR_BRANCH}" -- '*.lua' | grep -Ev '(configs|utils)\.lua$' | grep -E "^\+.*${SEARCH_PATTERN}" ; then _fail 'Do not use vim.fn.cwd or util.path.dirname in root_dir.' \ "See: https://github.com/neovim/nvim-lspconfig/blob/master/CONTRIBUTING.md#new-config" fi SEARCH_PATTERN='(util\.path\.dirname|util\.path\.sanitize|util\.path\.exists|util\.path\.is_file|util\.path\.is_dir|util\.path\.join|util\.path\.iterate_parents|util\.find_mercurial_ancestor|util\.find_node_modules_ancestor|util\.find_package_json_ancestor|util\.find_git_ancestor|util\.get_lsp_clients|util\.get_active_client_by_name)' if git diff --pickaxe-all -U0 -G "${SEARCH_PATTERN}" "${REF_BRANCH}" "${PR_BRANCH}" -- '*.lua' | grep -Ev '\.lua$' | grep -E "^\+.*${SEARCH_PATTERN}" ; then _fail 'Do not use deprecated util functions: '"${SEARCH_PATTERN}" fi } _check_legacy_configs() { if ! git diff "${REF_BRANCH}"..."${PR_BRANCH}" --exit-code -- lua/lspconfig/configs/ ; then _fail 'Configs in `lua/lspconfig/configs/*` are deprecated. Add or update configs in `lsp/*` instead.' fi } _check_generated_docs _check_cmd_buflocal _check_brief_placement _check_type _check_lsp_cmd_prefix _check_exec_cmd _check_deprecated_in_nvim_0_11 _check_deprecated_utils _check_legacy_configs