diff --git a/.github/workflows/.luarc.json b/.github/workflows/.luarc.json deleted file mode 100644 index 311cd64..0000000 --- a/.github/workflows/.luarc.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json", - "runtime": { - "version": "LuaJIT", - "pathStrict": true - }, - "workspace": { - "library": [ - "$VIMRUNTIME/lua", - "$VIMRUNTIME/lua/vim/lsp", - "$PWD/lua", - "${3rd}/luv/library", - "$DEPS_PATH/lazy.nvim/lua", - "$DEPS_PATH/dressing.nvim/lua", - "$DEPS_PATH/snacks.nvim/lua", - "$DEPS_PATH/plenary.nvim/lua", - "$DEPS_PATH/nui.nvim/lua", - "$DEPS_PATH/mini.pick/lua", - "$DEPS_PATH/telescope.nvim/lua", - "$DEPS_PATH/nvim-cmp/lua", - "$DEPS_PATH/fzf-lua/lua", - "$DEPS_PATH/nvim-web-devicons/lua", - "$DEPS_PATH/copilot.lua/lua" - ], - "ignoreDir": [ - "/lua" - ], - "checkThirdParty": false - } -} diff --git a/.github/workflows/lua.yaml b/.github/workflows/lua.yaml index 83d9fff..0290dae 100644 --- a/.github/workflows/lua.yaml +++ b/.github/workflows/lua.yaml @@ -69,38 +69,8 @@ jobs: neovim: true version: ${{ matrix.nvim_version }} - - name: Install luals - run: | - mkdir -p luals - curl -L "https://github.com/LuaLS/lua-language-server/releases/download/${{ matrix.luals_version }}/lua-language-server-${{ matrix.luals_version }}-linux-x64.tar.gz" | tar zx --directory luals - - - run: echo "luals/bin" >> "$GITHUB_PATH" - - - name: Checkout dependencies - run: | - mkdir -p deps - DEPS=( - "folke/neodev.nvim" - "nvim-lua/plenary.nvim" - "MunifTanjim/nui.nvim" - "stevearc/dressing.nvim" - "folke/snacks.nvim" - "echasnovski/mini.nvim" - "nvim-telescope/telescope.nvim" - "hrsh7th/nvim-cmp" - "ibhagwan/fzf-lua" - "nvim-tree/nvim-web-devicons" - "zbirenbaum/copilot.lua" - "folke/lazy.nvim" - ) - for dep in "${DEPS[@]}"; do - repo_name=$(echo $dep | cut -d'/' -f2) - git clone --depth 1 "https://github.com/${dep}.git" "deps/${repo_name}" - done - - name: Typecheck env: VIMRUNTIME: /home/runner/nvim-${{ matrix.nvim_version }}/share/nvim/runtime - DEPS_PATH: /home/runner/work/avante.nvim/avante.nvim/deps/ run: | make lua-typecheck diff --git a/Makefile b/Makefile index 978dac1..69d8bbe 100644 --- a/Makefile +++ b/Makefile @@ -102,7 +102,7 @@ lint: luacheck luastylecheck ruststylecheck rustlint .PHONY: lua-typecheck lua-typecheck: - bash ./scripts/lua-typecheck.sh + @./scripts/lua-typecheck.sh .PHONY: build-image build-image: diff --git a/luarc.json.template b/luarc.json.template new file mode 100644 index 0000000..489717e --- /dev/null +++ b/luarc.json.template @@ -0,0 +1,21 @@ +{ + "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json", + "runtime": { + "version": "LuaJIT", + "pathStrict": true + }, + "workspace": { + "library": [ + "$VIMRUNTIME/lua", + "$VIMRUNTIME/lua/vim/lsp", + "$PWD/lua", + "${3rd}/luv/library", + "$DEPS_PATH/luvit-meta/library" + {{DEPS}} + ], + "ignoreDir": [ + "/lua" + ], + "checkThirdParty": false + } +} diff --git a/scripts/lua-typecheck.sh b/scripts/lua-typecheck.sh index 9bd6ed0..68ee8cf 100755 --- a/scripts/lua-typecheck.sh +++ b/scripts/lua-typecheck.sh @@ -1,15 +1,142 @@ -#!/bin/env bash +#!/usr/bin/env bash +set -e -if [ -z "${VIMRUNTIME}" ]; then - export VIMRUNTIME=$(nvim --headless --noplugin -u NONE -c "echo \$VIMRUNTIME" +qa 2>&1) -fi +# This script performs a Lua typecheck, with different behaviors for local and CI environments. +# +# It supports two local modes: +# 1. Default (Managed): Downloads all dependencies into a project-local ./target/deps directory. +# 2. --live: Uses the system's installed `nvim` and `lua-language-server`. It does not +# manage plugin dependencies, assuming the user has them configured. -echo "VIMRUNTIME: ${VIMRUNTIME}" +verbose=false -if [ -z "${DEPS_PATH}" ]; then - export DEPS_PATH=${HOME}/.local/share/nvim/lazy/ -fi +log() { + echo "$1" >&2 +} -echo "DEPS_PATH: ${DEPS_PATH}" +log_verbose() { + if [ "$verbose" = "true" ]; then + echo "$1" >&2 + fi +} -lua-language-server --check=${PWD}/lua --configpath=${PWD}/.github/workflows/.luarc.json --checklevel=Information +die() { + echo "Error: $1" >&2 + exit 1 +} + +handle_live_mode() { + export DEPS_PATH="$HOME/.local/share/nvim/lazy" + log_verbose "Setting DEPS_PATH for live mode to: $DEPS_PATH" + + command -v nvim &>/dev/null || die "nvim command not found. Please install Neovim." + + if command -v lua-language-server &>/dev/null; then + log_verbose "Found lua-language-server in PATH." + else + log_verbose "lua-language-server not found in PATH. Checking Mason..." + local mason_luals_path="$HOME/.local/share/nvim/mason/bin/lua-language-server" + if [ -x "$mason_luals_path" ]; then + log_verbose "Found lua-language-server in Mason packages." + export PATH="$HOME/.local/share/nvim/mason/bin:$PATH" + else + die "lua-language-server not found in PATH or in Mason packages. Please install it." + fi + fi + + # $VIMRUNTIME is not supposed to be expanded below + # shellcheck disable=SC2016 + VIMRUNTIME="$(nvim --headless --noplugin -u NONE -c 'echo $VIMRUNTIME' +qa 2>&1)" + export VIMRUNTIME +} + +manage_plugin_dependencies() { + local deps_dir=$1 + local setup_deps_flags=$2 + log "Cloning/updating dependencies to $deps_dir..." + ./scripts/setup-deps.sh "$setup_deps_flags" clone "$deps_dir" + export DEPS_PATH="$deps_dir" + log_verbose "Set DEPS_PATH to $DEPS_PATH" +} + +run_typechecker() { + local config_path=$1 + if [ -z "$VIMRUNTIME" ]; then + die "VIMRUNTIME is not set. Cannot proceed." + fi + if [ -z "$config_path" ]; then + die "Luarc config path is not set. Cannot proceed." + fi + command -v lua-language-server &>/dev/null || die "lua-language-server not found in PATH." + + log "Running Lua typechecker..." + lua-language-server --check="$PWD/lua" \ + --loglevel=trace \ + --configpath="$config_path" \ + --checklevel=Information + log_verbose "Typecheck complete." +} + +main() { + local dest_dir="$PWD/target/tests" + local luarc_path="$dest_dir/luarc.json" + local mode="managed" + local setup_deps_flags="" + + for arg in "$@"; do + case $arg in + --live) + mode="live" + shift + ;; + --verbose|-v) + verbose=true + setup_deps_flags="--verbose" + shift + ;; + esac + done + + if [ "$GITHUB_ACTIONS" = "true" ]; then + mode="ci" + # Always be verbose in CI + setup_deps_flags="--verbose" + fi + + log "mode: $mode" + + if [ "$mode" == "live" ]; then + handle_live_mode + else + log "Setting up environment in: $dest_dir" + mkdir -p "$dest_dir" + + if [ "$mode" == "managed" ]; then + log "Installing nvim runtime..." + VIMRUNTIME="$(./scripts/setup-deps.sh "$setup_deps_flags" install-nvim "$dest_dir")" + export VIMRUNTIME + log_verbose "Installed nvim runtime at: $VIMRUNTIME" + fi + + log "Installing lua-language-server..." + local luals_bin_path + luals_bin_path="$(./scripts/setup-deps.sh "$setup_deps_flags" install-luals "$dest_dir")" + export PATH="$luals_bin_path:$PATH" + log_verbose "Added $luals_bin_path to PATH" + + local deps_dir="$dest_dir/deps" + log "Cloning/updating dependencies to $deps_dir..." + ./scripts/setup-deps.sh "$setup_deps_flags" clone "$deps_dir" + export DEPS_PATH="$deps_dir" + log_verbose "Set DEPS_PATH to $DEPS_PATH" + fi + + ./scripts/setup-deps.sh $setup_deps_flags generate-luarc "$luarc_path" + + log "VIMRUNTIME: $VIMRUNTIME" + log "DEPS_PATH: $DEPS_PATH" + + run_typechecker "$luarc_path" +} + +main "$@" diff --git a/scripts/setup-deps.sh b/scripts/setup-deps.sh new file mode 100755 index 0000000..931c146 --- /dev/null +++ b/scripts/setup-deps.sh @@ -0,0 +1,187 @@ +#!/bin/bash + +DEPS=( + "folke/neodev.nvim" + "nvim-lua/plenary.nvim" + "MunifTanjim/nui.nvim" + "stevearc/dressing.nvim" + "folke/snacks.nvim" + "echasnovski/mini.nvim" + "nvim-telescope/telescope.nvim" + "hrsh7th/nvim-cmp" + "ibhagwan/fzf-lua" + "nvim-tree/nvim-web-devicons" + "zbirenbaum/copilot.lua" + "folke/lazy.nvim" +) + +LUALS_VERSION="3.13.6" + +verbose=false + +log() { + echo "$1" >&2 +} + +log_verbose() { + if [ "$verbose" = "true" ]; then + echo "$1" >&2 + fi +} + +clone_deps() { + local deps_dir=${1:-"$PWD/deps"} + log_verbose "Cloning dependencies into: $deps_dir" + mkdir -p "$deps_dir" + + for dep in "${DEPS[@]}"; do + repo_name="$(echo "$dep" | cut -d'/' -f2)" + local repo_path="$deps_dir/$repo_name" + if [ -d "$repo_path/.git" ]; then + log_verbose "Updating existing repository: $repo_path" + ( + cd "$repo_path" + git fetch -q + if git show-ref --verify --quiet refs/remotes/origin/main; then + git reset -q --hard origin/main + elif git show-ref --verify --quiet refs/remotes/origin/master; then + git reset -q --hard origin/master + else + log "Could not find main or master branch for $repo_name" + fi + ) + else + if [ -d "$repo_path" ]; then + log_verbose "Directory '$repo_path' exists but is not a git repository. Removing and re-cloning." + rm -rf "$repo_path" + fi + log_verbose "Cloning new repository: $dep to $repo_path" + git clone -q --depth 1 "https://github.com/${dep}.git" "$repo_path" + fi + done +} + +install_luals() { + local dest_dir=${1:-"$PWD/target/tests"} + local luals_url_template="https://github.com/LuaLS/lua-language-server/releases/download/__VERSION__/lua-language-server-__VERSION__-linux-x64.tar.gz" + local luals_download_url="${luals_url_template//__VERSION__/$LUALS_VERSION}" + local luals_dir="$dest_dir/lua-language-server-${LUALS_VERSION}" + + if [ ! -d "$luals_dir" ]; then + log "Installing lua-language-server ${LUALS_VERSION}..." + mkdir -p "$luals_dir" + curl -sSL "${luals_download_url}" | tar zx --directory "$luals_dir" + else + log_verbose "lua-language-server is already installed in $luals_dir" + fi + echo "$luals_dir/bin" +} + +install_nvim_runtime() { + local dest_dir=${1:-"$PWD/target/tests"} + + command -v yq &>/dev/null || die "yq is not installed for parsing GitHub API responses." + + local nvim_version + nvim_version="$(yq -r '.jobs.typecheck.strategy.matrix.nvim_version[0]' .github/workflows/lua.yaml)" + log_verbose "Parsed nvim version from workflow: $nvim_version" + + log_verbose "Resolving ${nvim_version} Neovim release from GitHub API..." + local api_url="https://api.github.com/repos/neovim/neovim/releases" + if [ "$nvim_version" == "stable" ]; then + api_url="$api_url/latest" + else + api_url="$api_url/tags/${nvim_version}" + fi + + local release_data + release_data="$(curl -s "$api_url")" + if [ -z "$release_data" ] || echo "$release_data" | yq -e '.message == "Not Found"' > /dev/null; then + die "Failed to fetch release data from GitHub API for version '${nvim_version}'." + fi + + # Find the correct asset by regex and extract its name and download URL. + local asset_info + asset_info="$(echo "$release_data" | \ + yq -r '.assets[] | select(.name | test("nvim-linux(64|-x86_64)\\.tar\\.gz$")) | .name + " " + .browser_download_url')" + + if [ -z "$asset_info" ]; then + die "Could not find a suitable linux tarball asset for version '${nvim_version}'." + fi + + local asset_name + local download_url + read -r asset_name download_url <<< "$asset_info" + + local actual_version + actual_version="$(echo "$download_url" | grep -E -o 'v[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" + if [ -z "$actual_version" ]; then + die "Could not resolve a version tag from URL: $download_url" + fi + log_verbose "Resolved Neovim version is ${actual_version}" + + local runtime_dir="$dest_dir/nvim-${actual_version}-runtime" + if [ ! -d "$runtime_dir" ]; then + log "Installing Neovim runtime (${actual_version})..." + mkdir -p "$runtime_dir" + curl -sSL "${download_url}" | \ + tar xzf - -C "$runtime_dir" --strip-components=4 \ + "${asset_name%.tar.gz}/share/nvim/runtime" + else + log_verbose "Neovim runtime (${actual_version}) is already installed" + fi + echo "$runtime_dir" +} + +generate_luarc() { + local luarc_path=${1:-"$PWD/target/tests/luarc.json"} + local luarc_template="luarc.json.template" + + log_verbose "Generating luarc file at: $luarc_path" + mkdir -p "$(dirname "$luarc_path")" + + local lua_deps="" + for dep in "${DEPS[@]}"; do + repo_name="$(echo "$dep" | cut -d'/' -f2)" + lua_deps="${lua_deps},\n \"\$DEPS_PATH/${repo_name}/lua\"" + done + sed "s#{{DEPS}}#${lua_deps}#" "$luarc_template" > "$luarc_path" +} + +main() { + local command="" + local args=() + + # Manual parsing for flags and command + while [[ $# -gt 0 ]]; do + case $1 in + -v|--verbose) + verbose=true + shift + ;; + *) + if [ -z "$command" ]; then + command=$1 + else + args+=("$1") + fi + shift + ;; + esac + done + + if [ "$command" == "clone" ]; then + clone_deps "${args[@]}" + elif [ "$command" == "generate-luarc" ]; then + generate_luarc "${args[@]}" + elif [ "$command" == "install-luals" ]; then + install_luals "${args[@]}" + elif [ "$command" == "install-nvim" ]; then + install_nvim_runtime "${args[@]}" + else + echo "Usage: $0 [-v|--verbose] {clone [dir]|generate-luarc [path]|install-luals [dir]|install-nvim [dir]}" + exit 1 + fi +} + +main "$@"