diff --git a/pkl-html-highlighter/Cargo.lock b/pkl-html-highlighter/Cargo.lock
index 1f2a549d48..e6cf05a6ae 100644
--- a/pkl-html-highlighter/Cargo.lock
+++ b/pkl-html-highlighter/Cargo.lock
@@ -59,14 +59,17 @@ dependencies = [
"windows-sys",
]
+[[package]]
+name = "anyhow"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+
[[package]]
name = "cc"
-version = "1.0.83"
+version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
-dependencies = [
- "libc",
-]
+checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f"
[[package]]
name = "clap"
@@ -120,12 +123,6 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
-[[package]]
-name = "libc"
-version = "0.2.152"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
-
[[package]]
name = "memchr"
version = "2.7.1"
@@ -136,6 +133,7 @@ checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
name = "pkl_html_highlighter"
version = "0.6.0"
dependencies = [
+ "anyhow",
"clap",
"tree-sitter-highlight",
"tree-sitter-pkl",
@@ -161,9 +159,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.10.2"
+version = "1.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
dependencies = [
"aho-corasick",
"memchr",
@@ -173,9 +171,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.3"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
@@ -207,18 +205,18 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.56"
+version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
+checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.56"
+version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
+checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
diff --git a/pkl-html-highlighter/Cargo.toml b/pkl-html-highlighter/Cargo.toml
index 2a9948fd59..10ceaaa5f3 100644
--- a/pkl-html-highlighter/Cargo.toml
+++ b/pkl-html-highlighter/Cargo.toml
@@ -8,6 +8,7 @@ authors = ["pkl-oss@group.apple.com"]
tree-sitter-highlight = "0.20"
tree-sitter-pkl = { git = "ssh://git@github.com/apple/tree-sitter-pkl.git", tag = "0.16.0" }
clap = { version = "4.4.2", features = ["derive"] }
+anyhow = "1.0.40"
[net]
git-fetch-with-cli = true
diff --git a/pkl-html-highlighter/src/main.rs b/pkl-html-highlighter/src/main.rs
index 22318ae7af..f03e6741ee 100644
--- a/pkl-html-highlighter/src/main.rs
+++ b/pkl-html-highlighter/src/main.rs
@@ -13,12 +13,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// ===----------------------------------------------------------------------===//
-use std::process::exit;
-use std::{fs, io};
-use std::io::Read;
+use anyhow::{Context, Result};
use clap::Parser;
+use std::fs;
+use std::io::{self, Read};
+use std::process::exit;
use tree_sitter_highlight::{HighlightConfiguration, Highlighter, HtmlRenderer};
-use tree_sitter_pkl;
#[derive(Parser)]
struct CliArgs {
@@ -57,72 +57,111 @@ static QUERY_NAMES: [&str; 26] = [
"title.function.invoke",
"params",
"comment",
- "doctag"
+ "doctag",
];
-fn highlight_expr(contents: String, highlights_query: String) -> String {
- let highlighted = highlight(format!("expr = {}", contents), highlights_query, false);
- let stripped = highlighted.strip_prefix("expr = ").unwrap();
- return String::from(stripped);
+fn highlight_expr(contents: &str, highlights_query: &str) -> Result {
+ let highlighted = highlight(&format!("expr = {}", contents), highlights_query, false)?;
+ let stripped = highlighted
+ .strip_prefix(
+ "expr = ",
+ )
+ .context("Failed to strip prefix from highlighted output")?;
+ Ok(String::from(stripped))
}
-pub fn highlight(contents: String, highlights_query: String, is_expr: bool) -> String {
+pub fn highlight(contents: &str, highlights_query: &str, is_expr: bool) -> Result {
// highlight each line as if it were an expression.
if is_expr {
return highlight_expr(contents, highlights_query);
}
+
let mut pkl_config = HighlightConfiguration::new(
tree_sitter_pkl::language(),
- highlights_query.as_str(),
+ highlights_query,
tree_sitter_pkl::INJECTIONS_QUERY,
tree_sitter_pkl::LOCALS_QUERY,
- ).unwrap();
+ )?;
+
let attrs = &QUERY_NAMES.map(|it| {
let classes = it
- .split(".")
+ .split('.')
.enumerate()
// The first scope is prefixed with hljs-.
// Subscopes receive N number of underscores.
// https://highlightjs.readthedocs.io/en/stable/css-classes-reference.html#a-note-on-scopes-with-sub-scopes
- .map(|(idx, it)|
- if idx == 0 {
- format!("hljs-{}", it)
- } else {
- format!("{}{}", it, "_".repeat(idx))
- }
- )
+ .map(|(idx, it)| {
+ if idx == 0 {
+ format!("hljs-{}", it)
+ } else {
+ format!("{}{}", it, "_".repeat(idx))
+ }
+ })
.collect::>()
.join(" ");
format!("class=\"{}\"", classes)
});
pkl_config.configure(&QUERY_NAMES);
-
let mut highlighter = Highlighter::new();
- let events = highlighter.highlight(
- &pkl_config,
- contents.as_bytes(),
- None,
- |_| None
- ).unwrap();
+ let events = highlighter.highlight(&pkl_config, contents.as_bytes(), None, |_| None)?;
+
let mut renderer = HtmlRenderer::new();
- renderer.render(
- events,
- contents.as_bytes(),
- &move |it| &attrs[it.0].as_bytes()
- ).unwrap();
- renderer.lines().collect::>().join("")
+ renderer.render(events, contents.as_bytes(), &move |it| {
+ attrs[it.0].as_bytes()
+ })?;
+ Ok(renderer.lines().collect::>().join(""))
}
-fn main() {
+fn run() -> Result<()> {
let args: CliArgs = CliArgs::parse();
- if args.queries.is_none() {
- print!("Missing required argument: --queries ");
- exit(1)
- }
- let queries = fs::read_to_string(args.queries.unwrap().as_str()).unwrap();
+ let queries_path = args
+ .queries
+ .ok_or_else(|| anyhow::anyhow!("Missing required argument: --queries "))?;
+ let queries = fs::read_to_string(&queries_path)
+ .with_context(|| format!("Failed to read queries from path: {}", queries_path))?;
+
let mut buf = String::new();
- io::stdin().read_to_string(&mut buf).expect("Failed to read stdin!");
- let result = highlight(buf, queries, args.expr);
- print!("{}", result)
+ io::stdin()
+ .read_to_string(&mut buf)
+ .context("Failed to read from stdin")?;
+ let result = highlight(&buf, &queries, args.expr)?;
+ print!("{}", result);
+ Ok(())
+}
+
+fn main() {
+ if let Err(err) = run() {
+ eprintln!("Error: {:#}", err);
+ exit(1);
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ static TEST_HIGHLIGHT_QUERY: &str = "(source_file) @keyword";
+
+ #[test]
+ fn test_highlight_expr() {
+ let expr = "let x = 42";
+ let result = highlight_expr(expr, TEST_HIGHLIGHT_QUERY).unwrap();
+ assert!(result.contains("hljs-operator"));
+ }
+
+ #[test]
+ fn test_highlight_document() {
+ let doc = "let x = 42";
+ let result = highlight(doc, TEST_HIGHLIGHT_QUERY, false).unwrap();
+ assert!(result.contains("hljs-operator"));
+ }
+
+ #[test]
+ fn test_highlight_fails_on_invalid_query() {
+ let doc = "let x = 42";
+ let invalid_query = "(invalid_query) @unknown";
+ let result = highlight(doc, invalid_query, false);
+ assert!(result.is_err());
+ }
}