diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..4274292f --- /dev/null +++ b/.envrc @@ -0,0 +1,6 @@ +# If nix-shell available, then nix is installed. We're going to use nix-direnv. +# for automatic devshell injection after opt-in `direnv allow` +if command -v nix-shell &> /dev/null +then + use flake +fi diff --git a/.github/workflows/nix.yaml b/.github/workflows/nix.yaml index a931e576..da7c42fb 100644 --- a/.github/workflows/nix.yaml +++ b/.github/workflows/nix.yaml @@ -18,7 +18,7 @@ jobs: name: nix-build (${{ matrix.os }}) steps: - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v20 + - uses: cachix/install-nix-action@v22 with: github_access_token: ${{ secrets.GITHUB_TOKEN }} - run: nix build diff --git a/.gitignore b/.gitignore index 301314a7..2244da04 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ .direnv -.envrc .env .pre-commit-config.yaml +# nix build artifact +result ### Rust ### debug/ diff --git a/README.md b/README.md index 6bb6e334..a4b377ee 100644 --- a/README.md +++ b/README.md @@ -67,15 +67,34 @@ The project is packaged as a [Nix Flake][nix-flakes]. Consume it as you normally *make sure* that sg-nvim is included *both* as a Neovim plugin *and* as an environment/user package (because `sg-lsp` needs to be on your PATH). -See https://nixos.wiki/wiki/Neovim for more details on configuring neovim using Nix. -Or see https://github.com/willruggiano/neovim.drv for a practical example. - -For contributors and maintainers: - -- There should be nothing to do, nix-related, when changes are made to the Rust project -- If you're Nix savvy and want to contribute, it would be nice to use [crate2nix] instead - of the generic `buildRustPackage`. A github workflow would be needed to autoupdate the - generated crate2nix files. +See [Neovim guide on NixOS wiki](https://nixos.wiki/wiki/Neovim) for more details on configuration +See [gh:willruggiano/neovim.drv](https://github.com/willruggiano/neovim.drv) for a practical configuration. + +For Nix contributors and maintainers: + +- Feel free to `nix flake update` every once in a while to make sure `flake.lock` is up-to-date +- [ ] Minimal `sg.nvim`-integrated neovim package for testing and example +- [ ] Integrate `sg.nvim` + Cody onto [nixpkgs:vimPlugins](https://github.com/NixOS/nixpkgs/tree/fe2fb24a00ec510d29ccd4e36af72a0c55d81ec0/pkgs/applications/editors/vim/plugins) + +You will also need to add the built `.cdylib` onto `package.cpath`. Here is one example +using [gh:willruggiano/neovim.nix](https://github.com/willruggiano/neovim.nix): + +```nix +sg = let + system = "x86_64-linux"; + package = inputs.sg-nvim.packages.${system}.default; +in { + inherit package; + init = pkgs.writeTextFile { + name = "sg.lua"; + text = '' + return function() + package.cpath = package.cpath .. ";" .. "${package}/lib/?.so;${package}/lib/?.dylib" + end + ''; + }; +}; +``` ### Setup: diff --git a/contrib/default.nix b/contrib/default.nix new file mode 100644 index 00000000..7cfa23d2 --- /dev/null +++ b/contrib/default.nix @@ -0,0 +1,13 @@ +{ + pkgs, + symlinkJoin, + sg-workspace ? (pkgs.callPackage (import ./workspace-drv.nix)), + sg-plugin ? (pkgs.callPackage (import ./plugin-drv.nix)), + meta ? (pkgs.callPackage (import ./meta.nix)), + ... +}: +symlinkJoin { + name = "sg.nvim"; + paths = [sg-workspace sg-plugin]; + inherit meta; +} diff --git a/contrib/meta.nix b/contrib/meta.nix new file mode 100644 index 00000000..8cea232c --- /dev/null +++ b/contrib/meta.nix @@ -0,0 +1,5 @@ +{lib, ...}: { + description = "A plugin focused on bringing many features of sourcegraph.com onto Neovim"; + homepage = "https://github.com/sourcegraph/sg.nvim"; + license = lib.licenses.unlicense; +} diff --git a/contrib/plugin-drv.nix b/contrib/plugin-drv.nix new file mode 100644 index 00000000..8c3f75f3 --- /dev/null +++ b/contrib/plugin-drv.nix @@ -0,0 +1,17 @@ +{ + pkgs, + stdenv, + proj_root ? ./., + meta ? (pkgs.callPackage (import ./meta.nix)), + ... +}: +stdenv.mkDerivation { + name = "sg.nvim-plugin"; + src = proj_root; + phases = ["installPhase"]; + installPhase = '' + mkdir -p $out + cp -r $src/{lua,plugin} $out + ''; + inherit meta; +} diff --git a/contrib/workspace-drv.nix b/contrib/workspace-drv.nix new file mode 100644 index 00000000..4a13c4b7 --- /dev/null +++ b/contrib/workspace-drv.nix @@ -0,0 +1,74 @@ +{ + pkgs, + lib, + craneLib, # TODO: Make this flakes-free + pkg-config, + openssl, + stdenv, + darwin, + proj_root ? ./., + meta ? (pkgs.callPackage (import ./meta.nix)), + ... +}: let + # PURPOSE: if you modify non-code like github workflows, nix should not trigger a rebuild. + # cleanCargoSource keeps only `.rs`, `.toml`, and files listed below as build source + # NOTE: if you use `include!()` in Rust code. You'll have to opt-in the file + # using a custom filter. See https://github.com/ipetkov/crane/blob/master/lib/filterCargoSources.nix + code_artifacts = + lib.cleanSourceWith + { + src = lib.cleanSource proj_root; + filter = orig_path: type: let + path = toString orig_path; + base = baseNameOf path; + parentDir = baseNameOf (dirOf path); + + matchesSuffix = lib.any (suffix: lib.hasSuffix suffix base) [ + # Keep rust sources + ".rs" + + # Rust configs + "Cargo.toml" + "config.toml" + + ".gql" + ".graphql" + ]; + + # Cargo.toml already captured above + isCargoFile = base == "Cargo.lock"; + + # .cargo/config.toml already captured above + isCargoConfig = parentDir == ".cargo" && base == "config"; + in + type == "directory" || matchesSuffix || isCargoFile || isCargoConfig; + }; + + crane-args = { + pname = "sg.nvim-workspace"; + version = (with builtins; fromTOML (readFile "${proj_root}/Cargo.toml")).package.version or "unknown"; + src = code_artifacts; + + nativeBuildInputs = [pkg-config]; + + # openssl: required by reqwest (-> hyper-tls -> native-tls) + buildInputs = + [openssl] + ++ (lib.optional stdenv.isDarwin [ + darwin.apple_sdk.frameworks.Security + ]); + + cargoExtraArgs = "--workspace"; + inherit meta; + }; + + # build a version with only deps to reuse as build cache + workspace-deps = craneLib.buildDepsOnly crane-args; + + workspace-all = craneLib.buildPackage (crane-args + // { + # PURPOSE: This attempts to reuse build cache to skip having to build dependencies + cargoArtifacts = workspace-deps; + }); +in + workspace-all diff --git a/default.nix b/default.nix deleted file mode 100644 index 1be172f6..00000000 --- a/default.nix +++ /dev/null @@ -1,40 +0,0 @@ -{ - lib, - rustPlatform, - toolchain, - pkg-config, - openssl, - stdenv, - darwin, - ... -}: -rustPlatform.buildRustPackage { - pname = "sg.nvim"; - version = "0.1.0"; - - src = ./.; - cargoLock = { - lockFile = ./Cargo.lock; - }; - - nativeBuildInputs = [pkg-config toolchain]; - buildInputs = [openssl] ++ (lib.optional stdenv.isDarwin [darwin.apple_sdk.frameworks.Security]); - - cargoBuildFlags = ["--workspace"]; - cargoTestFlags = ["--workspace"]; - - checkFlags = [ - "--skip=test::can_get_lines_and_columns" - "--skip=test::create" - ]; - - postInstall = '' - cp -R {lua,plugin} $out - ''; - - meta = with lib; { - description = ""; - homepage = "https://github.com/tjdevries/sg.nvim"; - license = licenses.unlicense; - }; -} diff --git a/flake.lock b/flake.lock index 7a4cb6cb..8ca081e5 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,26 @@ { "nodes": { + "crane": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1687310026, + "narHash": "sha256-20RHFbrnC+hsG4Hyeg/58LvQAK7JWfFItTPFAFamu8E=", + "owner": "ipetkov", + "repo": "crane", + "rev": "116b32c30b5ff28e49f4fcbeeb1bbe3544593204", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, "flake-compat": { "flake": false, "locked": { @@ -16,16 +37,32 @@ "type": "github" } }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-parts": { "inputs": { "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1675295133, - "narHash": "sha256-dU8fuLL98WFXG0VnRgM00bqKX6CEPBLybhiIDIgO45o=", + "lastModified": 1687762428, + "narHash": "sha256-DIf7mi45PKo+s8dOYF+UlXHzE0Wl/+k3tXUyAoAnoGE=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "bf53492df08f3178ce85e0c9df8ed8d03c030c9f", + "rev": "37dd7bb15791c86d55c5121740a1887ab55ee836", "type": "github" }, "original": { @@ -35,12 +72,15 @@ } }, "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", "owner": "numtide", "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", "type": "github" }, "original": { @@ -50,12 +90,33 @@ } }, "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, "locked": { - "lastModified": 1659877975, - "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", "owner": "numtide", "repo": "flake-utils", - "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_3": { + "inputs": { + "systems": "systems_3" + }, + "locked": { + "lastModified": 1681202837, + "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "cfacdce06f30d2b68473a46042957675eebb3401", "type": "github" }, "original": { @@ -87,15 +148,15 @@ }, "nixpkgs": { "locked": { - "lastModified": 1675553537, - "narHash": "sha256-Ll/rx3JnvK53tfeDEFVFlH8UOxtBCyKB3cipyVhRbII=", - "owner": "nixos", + "lastModified": 1685714850, + "narHash": "sha256-OcvbIJq4CGwwFr9m7M/SQcDPZ64hhR4t77oZgEeh7ZY=", + "owner": "NixOS", "repo": "nixpkgs", - "rev": "19ad2a2b84a99b8025ace91ba7b80d12d8ae71db", + "rev": "c6ffce3d5df7b4c588ce80a0c6e2d2348a611707", "type": "github" }, "original": { - "owner": "nixos", + "owner": "NixOS", "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" @@ -104,11 +165,11 @@ "nixpkgs-lib": { "locked": { "dir": "lib", - "lastModified": 1675183161, - "narHash": "sha256-Zq8sNgAxDckpn7tJo7V1afRSk2eoVbu3OjI1QklGLNg=", + "lastModified": 1685564631, + "narHash": "sha256-8ywr3AkblY4++3lIVxmrWZFzac7+f32ZEhH/A8pNscI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e1e1b192c1a5aab2960bf0a0bd53a2e8124fa18e", + "rev": "4f53efe34b3a8877ac923b9350c874e3dcd5dc0a", "type": "github" }, "original": { @@ -121,43 +182,59 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1673800717, - "narHash": "sha256-SFHraUqLSu5cC6IxTprex/nTsI81ZQAtDvlBvGDWfnA=", + "lastModified": 1685801374, + "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2f9fd351ec37f5d479556cd48be4ca340da59b8f", + "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-22.11", + "ref": "nixos-23.05", "repo": "nixpkgs", "type": "github" } }, "nixpkgs_2": { "locked": { - "lastModified": 1671271357, - "narHash": "sha256-xRJdLbWK4v2SewmSStYrcLa0YGJpleufl44A19XSW8k=", + "lastModified": 1687886075, + "narHash": "sha256-PeayJDDDy+uw1Ats4moZnRdL1OFuZm1Tj+KiHlD67+o=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "a565059a348422af5af9026b5174dc5c0dcefdae", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1685866647, + "narHash": "sha256-4jKguNHY/edLYImB+uL8jKPL/vpfOvMmSlLAGfxSrnY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "40f79f003b6377bd2f4ed4027dde1f8f922995dd", + "rev": "a53a3bec10deef6e1cc1caba5bc60f53b959b1e8", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-unstable", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs_3": { + "nixpkgs_4": { "locked": { - "lastModified": 1665296151, - "narHash": "sha256-uOB0oxqxN9K7XGF1hcnY+PQnlQJ+3bP2vCn/+Ru/bbc=", + "lastModified": 1681358109, + "narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "14ccaaedd95a488dd7ae142757884d8e125b3363", + "rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9", "type": "github" }, "original": { @@ -169,18 +246,18 @@ }, "pre-commit-nix": { "inputs": { - "flake-compat": "flake-compat", - "flake-utils": "flake-utils", + "flake-compat": "flake-compat_2", + "flake-utils": "flake-utils_2", "gitignore": "gitignore", - "nixpkgs": "nixpkgs_2", + "nixpkgs": "nixpkgs_3", "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1675337566, - "narHash": "sha256-jmLBTQcs1jFOn8h1Q5b5XwPfYgFOtcZ3+mU9KvfC6Js=", + "lastModified": 1687779420, + "narHash": "sha256-noueZE/Z5qx6NF/grg46qlpZ/1nuPpc92RvqgCmRaLI=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "5668d079583a5b594cb4e0cc0e6d84f1b93da7ae", + "rev": "1fa438eee82f35bdd4bc30a9aacd7648d757b388", "type": "github" }, "original": { @@ -191,23 +268,30 @@ }, "root": { "inputs": { + "crane": "crane", "flake-parts": "flake-parts", - "nixpkgs": "nixpkgs", + "nixpkgs": "nixpkgs_2", "pre-commit-nix": "pre-commit-nix", - "rust-overlay": "rust-overlay" + "rust-overlay": "rust-overlay_2" } }, "rust-overlay": { "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": "nixpkgs_3" + "flake-utils": [ + "crane", + "flake-utils" + ], + "nixpkgs": [ + "crane", + "nixpkgs" + ] }, "locked": { - "lastModified": 1675564291, - "narHash": "sha256-mJ9ISIElFGCPYRDBYVv2AWPwYSsbTCEJg2E9n4ALxwc=", + "lastModified": 1685759304, + "narHash": "sha256-I3YBH6MS3G5kGzNuc1G0f9uYfTcNY9NYoRc3QsykLk4=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "3bf0a253c07b4ddea8a5f0fb805e2a412cc7c7d4", + "rev": "c535b4f3327910c96dcf21851bbdd074d0760290", "type": "github" }, "original": { @@ -215,6 +299,70 @@ "repo": "rust-overlay", "type": "github" } + }, + "rust-overlay_2": { + "inputs": { + "flake-utils": "flake-utils_3", + "nixpkgs": "nixpkgs_4" + }, + "locked": { + "lastModified": 1687919622, + "narHash": "sha256-cJwMwVcx+3wW3QYPj5g/fwzrULRUYnGXH9TBv7JwBGk=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "fc57a011f1c20d2b24f75a79ab669430a221b220", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 5c10fd19..d581d691 100644 --- a/flake.nix +++ b/flake.nix @@ -4,6 +4,7 @@ flake-parts.url = "github:hercules-ci/flake-parts"; pre-commit-nix.url = "github:cachix/pre-commit-hooks.nix"; rust-overlay.url = "github:oxalica/rust-overlay"; + crane.url = "github:ipetkov/crane"; }; outputs = { @@ -20,6 +21,9 @@ overlays.default = final: prev: { sg-nvim = self.packages."${prev.system}".default; }; + # HACK: both nixpkgs.lib and pkgs.lib contain licenses + # Technically impossible to do `callPackage` without proper `${system}` + meta = import ./contrib/meta.nix {inherit (inputs.nixpkgs) lib;}; }; systems = ["x86_64-darwin" "x86_64-linux" "aarch64-darwin"]; @@ -27,6 +31,7 @@ config, system, inputs', + self', ... }: let pkgs = import inputs.nixpkgs { @@ -35,7 +40,7 @@ inputs.rust-overlay.overlays.default ]; }; - toolchain = pkgs.rust-bin.fromRustupToolchainFile ./.rust-toolchain; + toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; in { devShells.default = pkgs.mkShell { name = "sg.nvim"; @@ -51,7 +56,24 @@ formatter = pkgs.alejandra; - packages.default = pkgs.callPackage ./. {inherit toolchain;}; + packages.workspace = pkgs.callPackage ./contrib/workspace-drv.nix { + craneLib = inputs.crane.lib.${system}.overrideToolchain toolchain; + proj_root = inputs.self; + inherit (self) meta; + }; + + packages.plugin = pkgs.callPackage ./contrib/plugin-drv.nix { + proj_root = inputs.self; + inherit (self) meta; + }; + + packages.all = pkgs.callPackage ./contrib/default.nix { + sg-workspace = self'.packages.workspace; + sg-plugin = self'.packages.plugin; + inherit (self) meta; + }; + + packages.default = self'.packages.all; pre-commit = { settings = { diff --git a/lua/sg/lib.lua b/lua/sg/lib.lua index f29fbae1..8f5fdf2e 100644 --- a/lua/sg/lib.lua +++ b/lua/sg/lib.lua @@ -11,8 +11,14 @@ end add_pattern "/target/debug/?.so" add_pattern "/target/debug/?.dylib" +add_pattern "/target/release/?.so" +add_pattern "/target/release/?.dylib" + +add_pattern "/lib/?.so" +add_pattern "/lib/?.dylib" -- Return the required libsg_nvim + local ok, mod = pcall(require, "libsg_nvim") if not ok then print "Failed to load libsg_nvim: You probably did not run `cargo build --workspace`" diff --git a/lua/sg/request.lua b/lua/sg/request.lua index 6f81d578..c1a2e0a2 100644 --- a/lua/sg/request.lua +++ b/lua/sg/request.lua @@ -1,8 +1,33 @@ -local sg_cody_process = vim.api.nvim_get_runtime_file("target/debug/sg-cody", false)[1] -if not sg_cody_process then - error "Could not find sg-cody binary. Make sure you ran `cargo build --bin sg-cody`" +local function discover_sg_cody() + ---@type string | nil + local cmd = "sg-cody" + + if vim.fn.executable(cmd) ~= 1 then + cmd = nil + local rtfile = vim.api.nvim_get_runtime_file + local cmd_paths = { + "target/release/sg-cody", + "target/debug/sg-cody", + "bin/sg-cody" + } + for _, path in ipairs(cmd_paths) do + local res = rtfile(path, false)[1] + if res then + cmd = res + break + end + end + end + + if cmd == nil then + error "Failed to load sg-cody: You probably did not run `cargo build --bin sg-cody`" + end + + return cmd end +local sg_cody_process = discover_sg_cody() + local uv = vim.loop local log = require "sg.log" @@ -40,6 +65,7 @@ M.start = function(force) handle, pid = uv.spawn(sg_cody_process, { stdio = { stdin, stdout, stderr }, env = { + "PATH=" .. vim.env.PATH, "SRC_ACCESS_TOKEN=" .. (vim.env.SRC_ACCESS_TOKEN or ""), "SRC_ENDPOINT=" .. (vim.env.SRC_ENDPOINT or ""), },