feat(users/Profpatsch): set up a file watcher for tree sitter

Uses inotify to watch a file and print when it is modified, so we can
update the parser and display the sexp on the terminal.

Now the setup is good enough to start experiementing with queries on
the syntax tree.

Change-Id: I091587fc495ff627c79a69a52915aaaa8c51fcd2
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2411
Tested-by: BuildkiteCI
Reviewed-by: Profpatsch <mail@profpatsch.de>
This commit is contained in:
Profpatsch 2021-01-17 12:32:09 +01:00
parent f8b3e2a100
commit 80e1ece329
4 changed files with 136 additions and 10 deletions

View file

@ -13,6 +13,7 @@
avrlibc
bashInteractive
bat
bc
buildBazelPackage
buildFHSUserEnv
buildGoModule
@ -44,6 +45,7 @@
emacsPackagesGen
execline
fd
fdtools
fetchFromGitHub
fetchgit
fetchurl
@ -87,9 +89,11 @@
mkShell
moreutils
nano
ncurses
nginx
ninja
nix
ocamlPackages
openssh
openssl
overrideCC

View file

@ -1,6 +1,8 @@
{ depot, pkgs, ... }:
let
bins = depot.nix.getBins pkgs.coreutils ["printf" "echo"];
bins = depot.nix.getBins pkgs.coreutils [ "printf" "echo" "cat" "printenv" ]
// depot.nix.getBins pkgs.fdtools [ "multitee" ]
;
debugExec = msg: depot.nix.writeExecline "debug-exec" {} [
"if" [
@ -15,9 +17,19 @@ let
"fdmove" "-c" "1" "2" bins.printf "$@"
];
eprint-stdin = depot.nix.writeExecline "eprint-stdin" {} [
"pipeline" [ bins.multitee "0-1,2" ] "$@"
];
eprintenv = depot.nix.writeExecline "eprintenv" { readNArgs = 1; } [
"fdmove" "-c" "1" "2" bins.printenv "$1"
];
in {
inherit
debugExec
eprintf
eprint-stdin
eprintenv
;
}

View file

@ -50,4 +50,36 @@ rec {
buildDependencies = [ cc ];
sha256 = "0jwwbvs4icpra7m1ycvnyri5h3sbw4qrfvgnnvnk72h4w93qhzhr";
};
libc = pkgs.buildRustCrate {
pname = "libc";
crateName = "libc";
version = "0.2.82";
sha256 = "02zgn6c0xwh331hky417lbr29kmvrw3ylxs8822syyhjfjqszvsx";
};
bitflags = pkgs.buildRustCrate {
pname = "bitflags";
crateName = "bitflags";
version = "1.2.1";
sha256 = "0b77awhpn7yaqjjibm69ginfn996azx5vkzfjj39g3wbsqs7mkxg";
};
inotify-sys = pkgs.buildRustCrate {
pname = "inotify-sys";
crateName = "inotify-sys";
version = "0.1.5";
dependencies = [ libc ];
sha256 = "1yiy577xxhi0j90nbg9nkd8cqwc1xix62rz55jjngvxa5jl5613v";
};
inotify = pkgs.buildRustCrate {
pname = "inotify";
crateName = "inotify";
version = "0.9.2";
edition = "2018";
dependencies = [ bitflags libc inotify-sys ];
sha256 = "0fcknyvknglwwk1pdzdlb4m0ry2dym1yx8r5prf2v00pxnjk0hv2";
};
}

View file

@ -1,15 +1,17 @@
{ depot, pkgs, lib, ... }:
let
bins = depot.nix.getBins pkgs.coreutils [ "head" "printf" "cat" ]
// depot.nix.getBins pkgs.ncurses [ "tput" ]
// depot.nix.getBins pkgs.bc [ "bc" ]
// depot.nix.getBins pkgs.ocamlPackages.sexp [ "sexp" ];
print-ast = depot.users.Profpatsch.writers.rustSimple {
name = "print-ast";
dependencies = with depot.users.Profpatsch.rust-crates; [
libloading
tree-sitter
];
buildInputs = [
pkgs.tree-sitter
];
} ''
extern crate libloading;
extern crate tree_sitter;
@ -39,9 +41,7 @@ let
let mut parser = Parser::new();
let lang = _load_language(so, symbol_name).unwrap();
parser.set_language(lang).unwrap();
let mut bytes = Vec::new();
let mut file = std::fs::OpenOptions::new().read(true).open(file).unwrap();
file.read_to_end(&mut bytes);
let bytes = std::fs::read(&file).unwrap();
print!("{}", parser.parse(&bytes, None).unwrap().root_node().to_sexp());
}
@ -58,8 +58,85 @@ let
};
};
parse-nix-file = depot.nix.writeExecline "parse-nix-file" { readNArgs = 1; } [
print-ast "${tree-sitter-nix}/parser" "tree_sitter_nix" "$1"
watch-file-modified = depot.users.Profpatsch.writers.rustSimple {
name = "watch-file-modified";
dependencies = [ depot.users.Profpatsch.rust-crates.inotify ];
} ''
extern crate inotify;
use inotify::{EventMask, WatchMask, Inotify};
use std::io::Write;
fn main() {
let mut inotify = Inotify::init()
.expect("Failed to initialize inotify");
let file = std::env::args().nth(1).unwrap();
let file_watch = inotify
.add_watch(
&file,
WatchMask::MODIFY
)
.expect("Failed to add inotify watch");
fn to_netstring(s: &[u8]) -> Vec<u8> {
let len = s.len();
// length of the integer as ascii
let i_len = ((len as f64).log10() as usize) + 1;
let ns_len = i_len + 1 + len + 1;
let mut res = Vec::with_capacity(ns_len);
res.extend_from_slice(format!("{}:", len).as_bytes());
res.extend_from_slice(s);
res.push(b',');
res
}
let mut buffer = [0u8; 4096];
loop {
let events = inotify
.read_events_blocking(&mut buffer)
.expect("Failed to read inotify events");
for event in events {
if event.wd == file_watch {
std::io::stdout().write(&to_netstring(file.as_bytes()));
std::io::stdout().flush();
}
}
}
}
'';
# clear screen and set LINES and COLUMNS to terminal height & width
clear-screen = depot.nix.writeExecline "clear-screen" {} [
"if" [ bins.tput "clear" ]
"backtick" "-in" "LINES" [ bins.tput "lines" ]
"backtick" "-in" "COLUMNS" [ bins.tput "cols" ]
"$@"
];
print-nix-file = depot.nix.writeExecline "print-nix-file" { readNArgs = 1; } [
"pipeline" [ print-ast "${tree-sitter-nix}/parser" "tree_sitter_nix" "$1" ]
"pipeline" [ bins.sexp "print" ]
clear-screen
"importas" "-ui" "lines" "LINES"
"backtick" "-in" "ls" [
"pipeline"
# when you pull out bc to decrement an integer its time to switch to python lol
[ bins.printf "x=%s; --x\n" "$lines" ]
bins.bc
]
"importas" "-ui" "l" "ls"
bins.head "-n\${l}"
];
print-nix-file-on-update = depot.nix.writeExecline "print-nix-file-on-update" { readNArgs = 1; } [
"if" [ print-nix-file "$1" ]
"pipeline" [ watch-file-modified "$1" ]
"forstdin" "-d" "" "file"
"importas" "file" "file"
print-nix-file "$file"
];
# copied from nixpkgs
@ -104,6 +181,7 @@ in {
inherit
print-ast
tree-sitter-nix
parse-nix-file
print-nix-file-on-update
watch-file-modified
;
}