tree-sitter-grammars: expose tree-sitter.json (#442281)
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# This package defines a `TreeSitterConfig` class autogenerated from the
|
||||
# tree-sitter `config.schema.json` using `datamodel-codegen`.
|
||||
{
|
||||
pkgs, # Need to access `pkgs.tree-sitter`, which is different than `pkgs.python3Packages.tree-sitter`.
|
||||
buildPythonPackage,
|
||||
datamodel-code-generator,
|
||||
lib,
|
||||
pydantic,
|
||||
runCommand,
|
||||
hatchling,
|
||||
symlinkJoin,
|
||||
writeTextDir,
|
||||
}:
|
||||
buildPythonPackage (finalAttrs: {
|
||||
pname = "tree-sitter-config";
|
||||
version = "1.0.0";
|
||||
pyproject = true;
|
||||
build-system = [ hatchling ];
|
||||
|
||||
src = symlinkJoin {
|
||||
name = "tree-sitter-config-source";
|
||||
paths = [
|
||||
(writeTextDir "pyproject.toml" /* toml */ ''
|
||||
[build-system]
|
||||
requires = ["hatchling >= 1.26"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "tree_sitter_config"
|
||||
version = "${finalAttrs.version}"
|
||||
'')
|
||||
(runCommand "tree_sitter_config/__init__.py"
|
||||
{
|
||||
nativeBuildInputs = [
|
||||
datamodel-code-generator
|
||||
];
|
||||
}
|
||||
''
|
||||
mkdir -p $out/tree_sitter_config
|
||||
datamodel-codegen \
|
||||
--input ${pkgs.tree-sitter}/config.schema.json \
|
||||
--input-file-type jsonschema \
|
||||
--output-model-type pydantic_v2.BaseModel \
|
||||
--class-name TreeSitterConfig \
|
||||
> $out/tree_sitter_config/__init__.py
|
||||
''
|
||||
)
|
||||
];
|
||||
};
|
||||
|
||||
pythonImportsCheck = [ "tree_sitter_config" ];
|
||||
|
||||
dependencies = [ pydantic ] ++ pydantic.optional-dependencies.email;
|
||||
|
||||
meta = {
|
||||
description = "Python types for tree-sitter.json";
|
||||
license = lib.licenses.mit;
|
||||
maintainers = with lib.maintainers; [ jfly ];
|
||||
};
|
||||
})
|
||||
@@ -4,6 +4,7 @@
|
||||
setuptools,
|
||||
pytestCheckHook,
|
||||
tree-sitter,
|
||||
tree-sitter-config,
|
||||
symlinkJoin,
|
||||
writeTextDir,
|
||||
# `name`: grammar derivation pname in the format of `tree-sitter-<lang>`
|
||||
@@ -44,26 +45,40 @@ buildPythonPackage {
|
||||
src = symlinkJoin {
|
||||
name = "${drvPrefix}-source";
|
||||
paths = [
|
||||
(writeTextDir "${snakeCaseName}/__init__.py" ''
|
||||
(writeTextDir "${snakeCaseName}/__init__.py" /* python */ ''
|
||||
# AUTO-GENERATED DO NOT EDIT
|
||||
|
||||
# preload the parser object before importing c binding
|
||||
# this way we can avoid dynamic linker kicking in when
|
||||
# downstream code imports this python module
|
||||
from pathlib import Path
|
||||
from tree_sitter_config import TreeSitterConfig
|
||||
|
||||
# Preload the parser object before importing the C binding.
|
||||
# This way we can avoid dynamic linker kicking in when
|
||||
# downstream code imports this python module.
|
||||
import ctypes
|
||||
import sys
|
||||
import os
|
||||
parser = "${grammarDrv}/parser"
|
||||
try:
|
||||
ctypes.CDLL(parser, mode=ctypes.RTLD_GLOBAL) # cached
|
||||
except OSError as e:
|
||||
raise ImportError(f"cannot load tree-sitter parser object from {parser}: {e}")
|
||||
|
||||
# expose binding
|
||||
def config() -> TreeSitterConfig | None:
|
||||
grammar_path = Path("${grammarDrv}")
|
||||
json_path = grammar_path / "tree-sitter.json"
|
||||
if not json_path.exists():
|
||||
return None
|
||||
|
||||
# Massage each grammar's path into an absolute path so later code
|
||||
# can find queries, etc.
|
||||
conf = TreeSitterConfig.model_validate_json(json_path.read_text())
|
||||
for grammar in conf.grammars:
|
||||
grammar.path = str(grammar_path / grammar.path)
|
||||
|
||||
return conf
|
||||
|
||||
from ._binding import language
|
||||
__all__ = ["language"]
|
||||
__all__ = ["language", "config"]
|
||||
'')
|
||||
(writeTextDir "${snakeCaseName}/binding.c" ''
|
||||
(writeTextDir "${snakeCaseName}/binding.c" /* c */ ''
|
||||
// AUTO-GENERATED DO NOT EDIT
|
||||
|
||||
#include <Python.h>
|
||||
@@ -94,7 +109,7 @@ buildPythonPackage {
|
||||
return PyModule_Create(&module);
|
||||
}
|
||||
'')
|
||||
(writeTextDir "setup.py" ''
|
||||
(writeTextDir "setup.py" /* python */ ''
|
||||
# AUTO-GENERATED DO NOT EDIT
|
||||
|
||||
from platform import system
|
||||
@@ -116,7 +131,7 @@ buildPythonPackage {
|
||||
],
|
||||
)
|
||||
'')
|
||||
(writeTextDir "pyproject.toml" ''
|
||||
(writeTextDir "pyproject.toml" /* toml */ ''
|
||||
# AUTO-GENERATED DO NOT EDIT
|
||||
|
||||
[build-system]
|
||||
@@ -146,26 +161,35 @@ buildPythonPackage {
|
||||
build = "cp38-*"
|
||||
build-frontend = "build"
|
||||
'')
|
||||
(writeTextDir "tests/test_language.py" ''
|
||||
(writeTextDir "tests/test_language.py" /* python */ ''
|
||||
# AUTO-GENERATED DO NOT EDIT
|
||||
|
||||
from ${snakeCaseName} import language
|
||||
from ${snakeCaseName} import config, language
|
||||
from tree_sitter import Language, Parser
|
||||
|
||||
# This test only checks that the binding can load the grammar from the compiled shared object.
|
||||
# It does not verify the grammar itself; that is tested in
|
||||
# `pkgs/development/tools/parsing/tree-sitter/grammar.nix`.
|
||||
|
||||
def test_language():
|
||||
# This test only checks that the binding can load the grammar from the compiled shared object.
|
||||
# It does not verify the grammar itself; that is tested in
|
||||
# `pkgs/development/tools/parsing/tree-sitter/grammar.nix`.
|
||||
|
||||
lang = Language(language())
|
||||
assert lang is not None
|
||||
parser = Parser(lang)
|
||||
tree = parser.parse(bytes("", "utf-8"))
|
||||
assert tree is not None
|
||||
|
||||
def test_config():
|
||||
# This test only checks if we can parse the tree-sitter.json, if one exists.
|
||||
# (Not all grammars have one yet).
|
||||
config()
|
||||
'')
|
||||
];
|
||||
};
|
||||
|
||||
dependencies = [
|
||||
tree-sitter-config
|
||||
];
|
||||
|
||||
preCheck = ''
|
||||
# https://github.com/NixOS/nixpkgs/issues/255262
|
||||
rm -r ${snakeCaseName}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
src,
|
||||
meta ? { },
|
||||
generate ? false,
|
||||
excludeBrokenTreeSitterJson ? false,
|
||||
...
|
||||
}@args:
|
||||
|
||||
@@ -40,6 +41,13 @@ stdenv.mkDerivation (
|
||||
|
||||
stripDebugList = [ "parser" ];
|
||||
|
||||
# Not all tree-sitter.json files follow the schema. If they're invalid,
|
||||
# remove them. Note: these tree-sitter.json files are not validated here,
|
||||
# but are validated in python3Packages.tree-sitter-grammars.
|
||||
postPatch = lib.optionalString excludeBrokenTreeSitterJson ''
|
||||
rm tree-sitter.json
|
||||
'';
|
||||
|
||||
# Tree-sitter grammar packages contain a `tree-sitter.json` file at their
|
||||
# root. This provides package metadata that can be used to infer build
|
||||
# details.
|
||||
@@ -101,6 +109,9 @@ stdenv.mkDerivation (
|
||||
runHook preInstall
|
||||
mkdir $out
|
||||
mv parser $out/
|
||||
if [[ -f tree-sitter.json ]]; then
|
||||
cp tree-sitter.json $out/
|
||||
fi
|
||||
if [[ -d queries ]]; then
|
||||
cp -r queries $out
|
||||
fi
|
||||
@@ -124,6 +135,7 @@ stdenv.mkDerivation (
|
||||
})
|
||||
// removeAttrs args [
|
||||
"generate"
|
||||
"excludeBrokenTreeSitterJson"
|
||||
"meta"
|
||||
]
|
||||
)
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
fetchFromGitHub,
|
||||
fetchFromGitLab,
|
||||
fetchFromSourcehut,
|
||||
fetchpatch,
|
||||
nix-update-script,
|
||||
runCommand,
|
||||
which,
|
||||
rustPlatform,
|
||||
emscripten,
|
||||
@@ -56,6 +56,7 @@ let
|
||||
fetchFromGitHub
|
||||
fetchFromGitLab
|
||||
fetchFromSourcehut
|
||||
fetchpatch
|
||||
;
|
||||
};
|
||||
|
||||
@@ -134,6 +135,11 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
(substitute {
|
||||
src = ./remove-web-interface.patch;
|
||||
})
|
||||
(fetchpatch {
|
||||
name = "feat: allow `-` in grammar names";
|
||||
url = "https://github.com/tree-sitter/tree-sitter/commit/7d3c32125379c1dc02f47277bcd4eceaac299bdb.diff";
|
||||
hash = "sha256-ZNjdNateHVHDy0/txlAW8TUdz+DVxLKXpw8ojZbIQS8=";
|
||||
})
|
||||
];
|
||||
|
||||
postPatch =
|
||||
@@ -163,6 +169,8 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
PREFIX=$out make install
|
||||
${lib.optionalString (!enableShared) "rm -f $out/lib/*.so{,.*}"}
|
||||
${lib.optionalString (!enableStatic) "rm -f $out/lib/*.a"}
|
||||
|
||||
mv docs/src/assets/schemas/config.schema.json $out/
|
||||
''
|
||||
+ lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
|
||||
installShellCompletion --cmd tree-sitter \
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
fetchFromGitHub,
|
||||
fetchFromGitLab,
|
||||
fetchFromSourcehut,
|
||||
fetchpatch,
|
||||
nix-update-script,
|
||||
}:
|
||||
|
||||
@@ -10,7 +11,7 @@ let
|
||||
/**
|
||||
Set of grammar sources. See ./grammar-sources.nix to define a new grammar.
|
||||
*/
|
||||
grammar-sources = import ./grammar-sources.nix { inherit lib; };
|
||||
grammar-sources = import ./grammar-sources.nix { inherit lib fetchpatch; };
|
||||
|
||||
/**
|
||||
Parse a flakeref style string to { type, owner, repo, ref }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ lib }:
|
||||
{ fetchpatch, lib }:
|
||||
|
||||
{
|
||||
bash = {
|
||||
@@ -17,6 +17,9 @@
|
||||
meta = {
|
||||
license = lib.licenses.mit;
|
||||
};
|
||||
# The tree-sitter.json in this repo is invalid, see
|
||||
# <https://github.com/polarmutex/tree-sitter-beancount/pull/137>.
|
||||
excludeBrokenTreeSitterJson = true;
|
||||
};
|
||||
|
||||
bibtex = {
|
||||
@@ -152,6 +155,13 @@
|
||||
meta = {
|
||||
license = lib.licenses.mit;
|
||||
};
|
||||
patches = [
|
||||
(fetchpatch {
|
||||
name = "Fix invalid `tree-sitter.json`";
|
||||
url = "https://github.com/UserNobody14/tree-sitter-dart/commit/81638dbbdb76a0e88ea8c31b95ec76b9625ddb84.diff";
|
||||
hash = "sha256-oaxuKQPN/gprO4OFWYItkj5dqd2xlq3SV6qr4YkSFjM=";
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
devicetree = {
|
||||
@@ -314,6 +324,9 @@
|
||||
meta = {
|
||||
license = lib.licenses.mit;
|
||||
};
|
||||
# The tree-sitter.json in this repo is invalid, see
|
||||
# <https://github.com/ember-tooling/tree-sitter-glimmer/pull/189>
|
||||
excludeBrokenTreeSitterJson = true;
|
||||
};
|
||||
|
||||
glsl = {
|
||||
@@ -450,6 +463,9 @@
|
||||
meta = {
|
||||
license = lib.licenses.cc0;
|
||||
};
|
||||
# The tree-sitter.json in this repo is invalid, see
|
||||
# <https://github.com/sogaiu/tree-sitter-janet-simple/pull/7>
|
||||
excludeBrokenTreeSitterJson = true;
|
||||
};
|
||||
|
||||
java = {
|
||||
@@ -625,6 +641,9 @@
|
||||
meta = {
|
||||
license = lib.licenses.mit;
|
||||
};
|
||||
# The tree-sitter.json in this repo is invalid, see
|
||||
# <https://github.com/Norgate-AV/tree-sitter-netlinx/pull/82>
|
||||
excludeBrokenTreeSitterJson = true;
|
||||
};
|
||||
|
||||
nickel = {
|
||||
@@ -1044,9 +1063,14 @@
|
||||
};
|
||||
|
||||
tlaplus = rec {
|
||||
# FIXME: remove language override after release is available that includes
|
||||
# FIXME: remove patch after release is available that includes
|
||||
# https://github.com/tlaplus-community/tree-sitter-tlaplus/pull/138
|
||||
language = "@tlaplus/tlaplus";
|
||||
patches = [
|
||||
(fetchpatch {
|
||||
url = "https://github.com/tlaplus-community/tree-sitter-tlaplus/commit/2d831940c782850f64dabf5b7b17e9e51f7f0ebb.diff";
|
||||
hash = "sha256-ski2aYo25kHXz3T+Z2Coitdywot3tUiEbDY7gH7mTHE=";
|
||||
})
|
||||
];
|
||||
version = "1.5.0";
|
||||
url = "github:tlaplus-community/tree-sitter-tlaplus?ref=${version}";
|
||||
hash = "sha256-k34gkAd0ueXEAww/Hc1mtBfn0Kp1pIBQtjDZ9GQeB4Q=";
|
||||
|
||||
@@ -19372,6 +19372,8 @@ self: super: with self; {
|
||||
|
||||
tree-sitter-c-sharp = callPackage ../development/python-modules/tree-sitter-c-sharp { };
|
||||
|
||||
tree-sitter-config = callPackage ../development/python-modules/tree-sitter-config { };
|
||||
|
||||
tree-sitter-embedded-template =
|
||||
callPackage ../development/python-modules/tree-sitter-embedded-template
|
||||
{ };
|
||||
|
||||
Reference in New Issue
Block a user