pesto - read doc-comments from postions: init

This commit is contained in:
hsjobeki 2023-11-23 14:34:12 +01:00
parent eac456913d
commit e6e4b81fa1
No known key found for this signature in database
24 changed files with 1042 additions and 0 deletions

View File

@ -1,5 +1,25 @@
{
"nodes": {
"crane": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1700327093,
"narHash": "sha256-OgYvlBABxJYWhZ/HBd0bPVcIEkT+xDhDCpRYqtVhYWY=",
"owner": "ipetkov",
"repo": "crane",
"rev": "ae7cd510e508ee03d792005c2f1c0a3ff25ecb80",
"type": "github"
},
"original": {
"owner": "ipetkov",
"repo": "crane",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
@ -253,6 +273,7 @@
},
"root": {
"inputs": {
"crane": "crane",
"flake-parts": "flake-parts",
"floco": "floco",
"nix": "nix",

View File

@ -17,6 +17,9 @@
treefmt-nix.url = "github:numtide/treefmt-nix";
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
crane.url = "github:ipetkov/crane";
crane.inputs.nixpkgs.follows = "nixpkgs";
floco.url = "github:aakropotkin/floco";
floco.inputs.nixpkgs.follows = "nixpkgs";
};
@ -29,6 +32,7 @@
./preCommit.nix
./website/flake-module.nix
./pasta/flake-module.nix
./pesto/flake-module.nix
];
});
}

10
pasta/.envrc Normal file
View File

@ -0,0 +1,10 @@
source_up
files=(../../flake.nix flake-module.nix)
if type nix_direnv_watch_file &>/dev/null; then
nix_direnv_watch_file "${files[@]}"
else
watch_file "${files[@]}"
fi
use flake .#pasta --builders ''

10
pesto/.envrc Normal file
View File

@ -0,0 +1,10 @@
source_up
files=(../../flake.nix flake-module.nix Cargo.lock)
if type nix_direnv_watch_file &>/dev/null; then
nix_direnv_watch_file "${files[@]}"
else
watch_file "${files[@]}"
fi
use flake .#pesto --builders ''

1
pesto/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
target

480
pesto/Cargo.lock generated Normal file
View File

@ -0,0 +1,480 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
[[package]]
name = "anstyle-parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "clap"
version = "4.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "countme"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
[[package]]
name = "dissimilar"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632"
[[package]]
name = "expect-test"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30d9eafeadd538e68fb28016364c9732d78e420b9ff8853fa5e4058861e9f8d3"
dependencies = [
"dissimilar",
"once_cell",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "itoa"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "memchr"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "pesto"
version = "0.1.0"
dependencies = [
"clap",
"expect-test",
"regex",
"rnix",
"rowan",
"serde",
"serde_json",
"textwrap",
"walkdir",
]
[[package]]
name = "proc-macro2"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rnix"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb35cedbeb70e0ccabef2a31bcff0aebd114f19566086300b8f42c725fc2cb5f"
dependencies = [
"rowan",
]
[[package]]
name = "rowan"
version = "0.15.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "906057e449592587bf6724f00155bf82a6752c868d78a8fb3aa41f4e6357cfe8"
dependencies = [
"countme",
"hashbrown",
"memoffset",
"rustc-hash",
"text-size",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "ryu"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "serde"
version = "1.0.193"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.193"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "smawk"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "text-size"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233"
[[package]]
name = "textwrap"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
dependencies = [
"smawk",
"unicode-linebreak",
"unicode-width",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-linebreak"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "walkdir"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

22
pesto/Cargo.toml Normal file
View File

@ -0,0 +1,22 @@
[package]
name = "pesto"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rnix = "0.11.0"
# version defined by rnix
rowan = { version = "*" }
regex = "1.9.5"
textwrap = "0.16.0"
walkdir = "2.4.0"
clap = { version = "4.4.4", features = ["derive"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
expect-test = "1.4.0"
# [dev-dependencies]

21
pesto/README.md Normal file
View File

@ -0,0 +1,21 @@
# Pesto
Pesto gives you the extra sauce on top of your lambda noodles.
From a given lambda position extract doc comments and some metadata.
## Plugin for Noogle
Extract 'nixdoc style comments' or doc-comment (RFC145) from a given file position.
Usage:
```sh
pesto --file "attrsets.nix" --line "11" --column "3"
->
{
"doc": "content",
"arguments": {},
"countApplied": 3
}
```

12
pesto/fixtures/pos.json Normal file
View File

@ -0,0 +1,12 @@
[
{
"file": "./test.nix",
"line": 5,
"column": 9
},
{
"file": "./test.nix",
"line": 5,
"column": 12
}
]

5
pesto/fixtures/test.nix Normal file
View File

@ -0,0 +1,5 @@
let
# *Docs
# TODO: fix it later
foo = x: y: x;
in foo

33
pesto/flake-module.nix Normal file
View File

@ -0,0 +1,33 @@
{ inputs, ... }: {
perSystem = { self', inputs', pkgs, system, ... }:
let
craneLib = inputs.crane.lib.${system};
src = craneLib.cleanCargoSource (craneLib.path ./.);
commonArgs = {
inherit src;
strictDeps = true;
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
};
pesto = craneLib.buildPackage commonArgs;
checks = {
inherit pesto;
pestoClippy = craneLib.cargoClippy (commonArgs // {
cargoClippyExtraArgs = "--all-targets -- --deny warnings";
});
pestoFmt = craneLib.cargoFmt { inherit src; };
pesto-nextest = craneLib.cargoNextest (commonArgs // {
partitions = 1;
partitionType = "count";
});
};
in {
packages = { inherit pesto; };
inherit checks;
devShells.pesto = craneLib.devShell {
# Inherit inputs from checks.
inherit checks;
};
};
}

113
pesto/src/comment.rs Normal file
View File

@ -0,0 +1,113 @@
use rnix::ast::{self, AstToken};
use rnix::{match_ast, SyntaxNode};
use rowan::ast::AstNode;
/// Implements functions for doc-comments according to rfc145.
pub trait DocComment {
fn doc_text(&self) -> Option<&str>;
}
impl DocComment for ast::Comment {
/// Function returns the contents of the doc-comment, if the [ast::Comment] is a
/// doc-comment, or None otherwise.
///
/// Note: [ast::Comment] holds both the single-line and multiline comment.
///
/// /**{content}*/
/// -> {content}
///
/// It is named `doc_text` to complement [ast::Comment::text].
fn doc_text(&self) -> Option<&str> {
let text = self.syntax().text();
// Check whether this is a doc-comment
if text.starts_with(r#"/**"#) && self.text().starts_with('*') {
match text.strip_prefix(r#"/**"#) {
Some(t) => t.strip_suffix(r#"*/"#),
_ => None,
}
} else {
None
}
}
}
/// Function retrieves a doc-comment from the [ast::Expr]
///
/// Returns an [Option<String>] of the first suitable doc-comment.
/// Returns [None] in case no suitable comment was found.
///
/// Doc-comments can appear in two places for any expression
///
/// ```nix
/// # (1) directly before the expression (anonymous)
/// /** Doc */
/// bar: bar;
///
/// # (2) when assigning a name.
/// {
/// /** Doc */
/// foo = bar: bar;
/// }
/// ```
///
/// If the doc-comment is not found in place (1) the search continues at place (2)
/// More precisely before the NODE_ATTRPATH_VALUE (ast)
/// If no doc-comment was found in place (1) or (2) this function returns None.
pub fn get_expr_docs(expr: &SyntaxNode) -> Option<String> {
if let Some(doc) = get_doc_comment(expr) {
// Found in place (1)
doc.doc_text().map(|v| v.to_owned())
} else if let Some(ref parent) = expr.parent() {
match_ast! {
match parent {
ast::AttrpathValue(_) => {
if let Some(doc_comment) = get_doc_comment(parent) {
doc_comment.doc_text().map(|v| v.to_owned())
}else{
None
}
},
_ => {
// Yet unhandled ast-nodes
None
}
}
}
// None
} else {
// There is no parent;
// No further places where a doc-comment could be.
None
}
}
/// Looks backwards from the given expression
/// Only whitespace or non-doc-comments are allowed in between an expression and the doc-comment.
/// Any other Node or Token stops the peek.
fn get_doc_comment(expr: &SyntaxNode) -> Option<ast::Comment> {
let mut prev = expr.prev_sibling_or_token();
loop {
match prev {
Some(rnix::NodeOrToken::Token(ref token)) => {
match_ast! { match token {
ast::Whitespace(_) => {
prev = token.prev_sibling_or_token();
},
ast::Comment(it) => {
if it.doc_text().is_some() {
break Some(it);
}else{
//Ignore non-doc comments.
prev = token.prev_sibling_or_token();
}
},
_ => {
break None;
}
}}
}
_ => break None,
};
}
}

76
pesto/src/main.rs Normal file
View File

@ -0,0 +1,76 @@
mod comment;
mod position;
mod tests;
use clap::Parser;
use std::{collections::HashMap, fs, path::PathBuf, println};
use crate::position::{DocComment, DocIndex, FilePosition, LambdaDoc, TextPosition};
#[derive(Debug, Parser)]
#[command(author, version, about)]
struct Options {
/// Json file containing a list of file positions.
/// Format: [{ file: String, line: Number, column: Number }]
#[arg(long, conflicts_with_all=["line", "column", "file"])]
pos_file: Option<PathBuf>,
/// Path to the *.nix file that should be inspected.
/// If provided, --line and --column must also be set.
#[arg(long, requires_all=["line", "column", "file"])]
file: Option<PathBuf>,
/// Line of the expression.
#[arg(short, long, requires_all=["line", "column", "file"])]
line: Option<usize>,
/// Column of the expression.
#[arg(short, long, requires_all=["line", "column", "file"])]
column: Option<usize>,
}
pub fn main() {
// let mut output = io::stdout();
let opts = Options::parse();
if let Some(nix_file) = opts.file {
let pos = DocIndex::new(&nix_file);
if let Some(docs) = pos.get_docs(opts.line.unwrap(), opts.column.unwrap()) {
println!("{:?}", docs);
}
}
if let Some(pos_file) = opts.pos_file {
let raw_pos = fs::read_to_string(&pos_file).unwrap();
let positions: Vec<FilePosition> = serde_json::from_str(&raw_pos).unwrap();
// TODO: group positions by file, to avoid opening the same file again.
let mut positions_by_file: HashMap<&PathBuf, Vec<&FilePosition>> = HashMap::new();
for position in positions.iter() {
match positions_by_file.get_mut(&position.file) {
Some(list) => list.push(position),
None => {
//
positions_by_file.insert(&position.file, vec![position]);
}
};
}
for (f, p) in positions_by_file.iter() {
println!("{:?} {:?}", f, p);
}
let res: Vec<Vec<Option<LambdaDoc>>> = positions_by_file
.iter()
.map(|(file, positions)| {
let index = DocIndex::new(&file);
let docs: Vec<Option<LambdaDoc>> = positions
.iter()
.map(move |pos| index.get_docs(pos.line, pos.column))
.collect();
docs
})
.collect();
println!("{:?}", res);
// if let Some(docs) = pos.get_docs() {
// println!("{:?}", docs);
// }
}
}

158
pesto/src/position.rs Normal file
View File

@ -0,0 +1,158 @@
use core::panic;
use rnix::ast::{self};
use rnix::{match_ast, SyntaxNode};
use rowan::TextSize;
use rowan::{ast::AstNode, WalkEvent};
use serde::{Deserialize, Serialize};
use std::{fs, path::PathBuf, println};
use crate::comment::get_expr_docs;
#[derive(Debug, Serialize, Deserialize)]
pub struct TextPosition {
pub line: usize,
pub column: usize,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct FilePosition {
pub file: PathBuf,
pub line: usize,
pub column: usize,
}
#[derive(Debug)]
pub struct DocIndex<'a> {
file: &'a PathBuf,
src: Option<String>,
}
pub trait DocComment<'a> {
fn new(file: &'a PathBuf) -> Self;
fn get_pos_idx(&self, line: usize, column: usize) -> Option<TextSize>;
fn node_at_pos(&self, line: usize, column: usize) -> Option<SyntaxNode>;
fn get_docs(&self, line: usize, column: usize) -> Option<LambdaDoc>;
}
fn get_src(path: &PathBuf) -> Option<String> {
println!("reading {:?}", path);
if let Ok(src) = fs::read_to_string(&path) {
return Some(src);
}
panic!("could not read file");
}
impl<'a> DocComment<'a> for DocIndex<'a> {
fn new(file: &'a PathBuf) -> Self {
Self {
file: file,
src: get_src(file),
}
}
fn get_pos_idx(&self, l: usize, c: usize) -> Option<TextSize> {
if let Some(src) = &self.src {
let mut result: usize = 0;
let mut pos = None;
for (line, content) in src.lines().enumerate() {
if line + 1 == l {
for (col, _) in content.chars().enumerate() {
if col + 1 == c {
pos = Some(result + col);
break;
}
}
}
if pos.is_some() {
break;
}
result += content.len() + 1;
}
return pos.map(|pos| TextSize::from(u32::try_from(pos).unwrap()));
}
// Could not read source
None
}
fn node_at_pos(&self, line: usize, column: usize) -> Option<SyntaxNode> {
let src = &self.src;
let pos_idx = &self.get_pos_idx(line, column).unwrap();
if let Some(src) = src {
let ast = rnix::Root::parse(&src).ok().expect("failed to parse input");
let mut expr = None;
for ev in ast.syntax().preorder() {
match ev {
WalkEvent::Enter(node) => {
if node.text_range().start() == *pos_idx {
expr = Some(node);
break;
}
}
_ => {}
}
}
return expr;
}
None
}
fn get_docs(&self, line: usize, column: usize) -> Option<LambdaDoc> {
let expr = self.node_at_pos(line, column);
println!("L{}:C{}, {:?}", line, column, expr);
expr.map(|e| {
let (outer_lambda, count_applied) = get_parent_lambda(&e);
LambdaDoc {
pos: FilePosition {
file: self.file.clone(),
line,
column,
},
content: get_expr_docs(&outer_lambda),
count_applied,
}
})
}
}
#[derive(Debug)]
pub struct LambdaDoc {
pos: FilePosition,
content: Option<String>,
count_applied: i32,
}
fn get_parent_lambda(expr: &SyntaxNode) -> (SyntaxNode, i32) {
let mut count_outer_lambda = 0;
let mut lambda_parent = peek_parent_lambda(expr);
let mut res = expr.to_owned();
loop {
match lambda_parent {
Some(ref node) => {
count_outer_lambda += 1;
res = node.clone();
lambda_parent = peek_parent_lambda(node);
}
None => break,
}
}
return (res, count_outer_lambda);
}
fn peek_parent_lambda(expr: &SyntaxNode) -> Option<SyntaxNode> {
match expr.parent() {
Some(parent) => match_ast! {
match parent {
ast::Lambda(_) => {
Some(parent)
},
_ => {
None
}
}
},
None => None,
}
}

48
pesto/src/tests.rs Normal file
View File

@ -0,0 +1,48 @@
#[cfg(test)]
mod tests {
use std::{ffi::OsStr, format, fs, path::PathBuf};
use crate::position::{DocComment, DocIndex, TextPosition};
use expect_test::expect_file;
fn dir_tests<F>(dir: &str, get_actual: F)
where
F: Fn(&PathBuf, (usize, usize)) -> String,
{
let base_path: PathBuf = [env!("CARGO_MANIFEST_DIR"), "test_data", dir]
.iter()
.collect();
let entries = base_path.read_dir().unwrap();
for entry in entries {
let path = entry.unwrap().path();
if path.extension() != Some(OsStr::new("nix")) {
continue;
}
println!("testing: {}", path.display());
let mut pos_path = path.clone();
pos_path.set_extension("pos");
let raw_pos = fs::read_to_string(&pos_path).unwrap();
let pos: TextPosition = serde_json::from_str(&raw_pos).unwrap();
let actual = get_actual(&path, (pos.line, pos.column));
expect_file![path.with_extension("expect")].assert_eq(&actual);
}
}
#[test]
fn test_main() {
dir_tests("atom", |path, (line, column)| {
let pos = DocIndex::new(path);
format!("{:?}", pos.get_docs(line,column))
})
}
}

View File

@ -0,0 +1 @@
Some(LambdaDoc { content: Some("Docs"), count_applied: 1 })

View File

@ -0,0 +1,4 @@
let
# *Docs
foo = x: y: z: b: x;
in foo

View File

@ -0,0 +1,4 @@
{
"line": 3,
"column": 12
}

View File

@ -0,0 +1 @@
Some(LambdaDoc { content: Some("Docs"), count_applied: 3 })

View File

@ -0,0 +1,4 @@
let
# *Docs
foo = x: y: z: b: x;
in foo

View File

@ -0,0 +1,4 @@
{
"line": 3,
"column": 18
}

View File

@ -0,0 +1 @@
Some(LambdaDoc { content: Some("Docs"), count_applied: 0 })

View File

@ -0,0 +1,5 @@
let
# *Docs
# TODO: fix it later
foo = x: x;
in foo

View File

@ -0,0 +1,4 @@
{
"line": 5,
"column": 9
}