pluginupdate.py: GITHUB_API_TOKEN -> GITHUB_TOKEN; nvim-treesitter/update.py: source from nurr; vimPlugins.nvim-treesitter: update grammars (#405955)

This commit is contained in:
Austin Horstman 2025-05-18 11:59:41 -05:00 committed by GitHub
commit d9c071fc88
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 465 additions and 448 deletions

View file

@ -177,7 +177,7 @@ Finally, there are some plugins that are also packaged in nodePackages because t
Run the update script with a GitHub API token that has at least `public_repo` access. Running the script without the token is likely to result in rate-limiting (429 errors). For steps on creating an API token, please refer to [GitHub's token documentation](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token). Run the update script with a GitHub API token that has at least `public_repo` access. Running the script without the token is likely to result in rate-limiting (429 errors). For steps on creating an API token, please refer to [GitHub's token documentation](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token).
```sh ```sh
nix-shell -p vimPluginsUpdater --run 'vim-plugins-updater --github-token=mytoken' # or set GITHUB_API_TOKEN environment variable nix-shell -p vimPluginsUpdater --run 'vim-plugins-updater --github-token=mytoken' # or set GITHUB_TOKEN environment variable
``` ```
Alternatively, set the number of processes to a lower count to avoid rate-limiting. Alternatively, set the number of processes to a lower count to avoid rate-limiting.

View file

@ -558,7 +558,16 @@ class Editor:
} }
for plugin_desc, plugin, redirect in fetched: for plugin_desc, plugin, redirect in fetched:
result[plugin.normalized_name] = (plugin_desc, plugin, redirect) # Check if plugin is a Plugin object and has normalized_name attribute
if isinstance(plugin, Plugin) and hasattr(plugin, 'normalized_name'):
result[plugin.normalized_name] = (plugin_desc, plugin, redirect)
elif isinstance(plugin, Exception):
# For exceptions, we can't determine the normalized_name
# Just log the error and continue
log.error(f"Error fetching plugin {plugin_desc.name}: {plugin!r}")
else:
# For unexpected types, log the issue
log.error(f"Unexpected plugin type for {plugin_desc.name}: {type(plugin)}")
return list(result.values()) return list(result.values())
@ -615,9 +624,9 @@ class Editor:
"--github-token", "--github-token",
"-t", "-t",
type=str, type=str,
default=os.getenv("GITHUB_API_TOKEN"), default=os.getenv("GITHUB_TOKEN"),
help="""Allows to set --proc to higher values. help="""Allows to set --proc to higher values.
Uses GITHUB_API_TOKEN environment variables as the default value.""", Uses GITHUB_TOKEN environment variables as the default value.""",
) )
common.add_argument( common.add_argument(
"--no-commit", "--no-commit",

View file

@ -5,19 +5,16 @@
with pkgs; with pkgs;
let let
inherit (vimPlugins) nvim-treesitter; pythonWithPackages = python3.withPackages (
ps: with ps; [
neovim = pkgs.neovim.override { requests
configure.packages.all.start = [ nvim-treesitter ]; ]
}; );
in in
mkShell { mkShell {
packages = [ packages = [
neovim
nurl nurl
python3 pythonWithPackages
]; ];
NVIM_TREESITTER = nvim-treesitter;
} }

View file

@ -5,104 +5,128 @@ import json
import logging import logging
import os import os
import subprocess import subprocess
import sys
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
import requests
log = logging.getLogger("vim-updater") log = logging.getLogger("vim-updater")
NURR_JSON_URL = "https://raw.githubusercontent.com/nvim-neorocks/nurr/main/tree-sitter-parsers.json"
def generate_grammar(lang, rev, cfg): def generate_grammar(lang, parser_info):
"""Generate grammar for a language""" """Generate grammar for a language based on the parser info"""
info = cfg["install_info"] try:
url = info["url"] if "install_info" not in parser_info:
log.warning(f"Parser {lang} does not have install_info, skipping")
return ""
generated = f""" {lang} = buildGrammar {{ install_info = parser_info["install_info"]
url = install_info["url"]
rev = install_info["revision"]
generated = f""" {lang} = buildGrammar {{
language = "{lang}"; language = "{lang}";
version = "0.0.0+rev={rev[:7]}"; version = "0.0.0+rev={rev[:7]}";
src = """ src = """
generated += subprocess.check_output(["nurl", url, rev, "--indent=4"], text=True) generated += subprocess.check_output(["nurl", url, rev, "--indent=4"], text=True)
generated += ";" generated += ";"
location = info.get("location") location = install_info.get("location", "")
if location: if location:
generated += f""" generated += f"""
location = "{location}";""" location = "{location}";"""
if info.get("requires_generate_from_grammar"): if install_info.get("generate", False):
generated += """ generated += """
generate = true;""" generate = true;"""
generated += f""" generated += f"""
meta.homepage = "{url}"; meta.homepage = "{url}";
}}; }};
""" """
return generated return generated
except Exception as e:
log.error(f"Error generating grammar for {lang}: {e}")
return ""
def update_grammars(nvim_treesitter_dir: str): def fetch_nurr_parsers():
""" """Fetch the parser information from nurr repository"""
The lockfile contains just revisions so we start neovim to dump the log.info("Fetching parser data from %s", NURR_JSON_URL)
grammar information in a better format
""" headers = {}
# the lockfile github_token = os.environ.get("GITHUB_TOKEN")
cmd = [ if github_token:
"nvim", log.info("Using GITHUB_TOKEN for authentication")
"--headless", headers["Authorization"] = f"token {github_token}"
"-u", else:
"NONE", log.warning("No GITHUB_TOKEN found. GitHub API requests may be rate-limited.")
"--cmd",
f"set rtp^={nvim_treesitter_dir}", response = requests.get(NURR_JSON_URL, headers=headers, timeout=30)
"+lua io.write(vim.json.encode(require('nvim-treesitter.parsers').get_parser_configs()))", response.raise_for_status()
"+quit!", data = response.json()
]
log.debug("Running command: %s", ' '.join(cmd)) try:
configs = json.loads(subprocess.check_output(cmd)) parsers = data["parsers"]
except KeyError:
raise ValueError(
"Unexpected response from NURR:\n" + json.dumps(data, indent=2)
)
log.info(f"Successfully fetched {len(parsers)} parsers")
return parsers
def process_parser_info(parser_info):
"""Process a single parser info entry and generate grammar for it"""
try:
lang = parser_info["lang"]
return generate_grammar(lang, parser_info)
except Exception as e:
log.error(f"Error processing parser: {e}")
return ""
def update_grammars():
"""Update grammar definitions using nurr's parser information"""
parsers_info = fetch_nurr_parsers()
generated_file = """# generated by pkgs/applications/editors/vim/plugins/utils/nvim-treesitter/update.py generated_file = """# generated by pkgs/applications/editors/vim/plugins/utils/nvim-treesitter/update.py
# Using parser data from https://github.com/nvim-neorocks/nurr/blob/main/tree-sitter-parsers.json
{ {
buildGrammar, buildGrammar,
""" """
# Get the output and format it properly
nurl_output = subprocess.check_output(["nurl", "-Ls", ","], text=True).strip() nurl_output = subprocess.check_output(["nurl", "-Ls", ","], text=True).strip()
# Add proper indentation (2 spaces) to the comma-separated list
indented_output = nurl_output.replace(",", ",\n ") indented_output = nurl_output.replace(",", ",\n ")
generated_file += indented_output generated_file += indented_output
generated_file += """, generated_file += """,
}: }:
{ {
""" """
lockfile_path = os.path.join(nvim_treesitter_dir, "lockfile.json") # Process parsers in parallel for better performance
log.debug("Opening %s", lockfile_path) with ThreadPoolExecutor(max_workers=5) as executor:
with open(lockfile_path) as lockfile_fd: for generated in executor.map(process_parser_info, parsers_info):
lockfile = json.load(lockfile_fd)
def _generate_grammar(item):
lang, lock = item
cfg = configs.get(lang)
if not cfg:
return ""
return generate_grammar(lang, lock["revision"], cfg)
for generated in ThreadPoolExecutor(max_workers=5).map(
_generate_grammar, lockfile.items()
):
generated_file += generated generated_file += generated
generated_file += "}\n" generated_file += "}\n"
return generated_file return generated_file
if __name__ == "__main__": if __name__ == "__main__":
generated = update_grammars(sys.argv[1]) logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
generated = update_grammars()
output_path = os.path.join( output_path = os.path.join(
os.path.dirname(__file__), os.path.dirname(__file__),
"../../nvim-treesitter/generated.nix" "../../nvim-treesitter/generated.nix"
) )
open(output_path, "w").write(generated) log.info("Writing output to %s", output_path)
with open(output_path, "w") as f:
f.write(generated)
log.info("Successfully updated grammar definitions")

View file

@ -19,10 +19,8 @@
# #
import inspect import inspect
import json
import logging import logging
import os import os
import subprocess
import textwrap import textwrap
from pathlib import Path from pathlib import Path
from typing import List, Tuple from typing import List, Tuple
@ -136,20 +134,7 @@ class VimEditor(pluginupdate.Editor):
# TODO this should probably be skipped when running outside a nixpkgs checkout # TODO this should probably be skipped when running outside a nixpkgs checkout
if self.nvim_treesitter_updated: if self.nvim_treesitter_updated:
print("updating nvim-treesitter grammars") print("updating nvim-treesitter grammars")
cmd = [ generated = treesitter.update_grammars()
"nix",
"build",
"vimPlugins.nvim-treesitter.src",
"-f",
self.nixpkgs,
"--print-out-paths",
]
log.debug("Running command: %s", " ".join(cmd))
nvim_treesitter_dir = subprocess.check_output(
cmd, text=True, timeout=90
).strip()
generated = treesitter.update_grammars(nvim_treesitter_dir)
treesitter_generated_nix_path = os.path.join( treesitter_generated_nix_path = os.path.join(
NIXPKGS_NVIMTREESITTER_FOLDER, "generated.nix" NIXPKGS_NVIMTREESITTER_FOLDER, "generated.nix"
) )

View file

@ -25,6 +25,7 @@ buildPythonApplication {
pythonPath = [ pythonPath = [
python3Packages.gitpython python3Packages.gitpython
python3Packages.requests
]; ];
dontUnpack = true; dontUnpack = true;