From 21f25a53056804cdcb16cb89d767032ff54972da Mon Sep 17 00:00:00 2001 From: Amaan Qureshi Date: Mon, 12 Feb 2024 16:13:22 -0500 Subject: [PATCH] feat: improve error message for files with an unknown grammar path --- Cargo.lock | 1 + cli/Cargo.toml | 2 +- cli/src/main.rs | 6 ++++-- cli/src/tags.rs | 5 +++-- cli/src/test_highlight.rs | 32 ++++++++++++++++++++++++++------ cli/src/test_tags.rs | 27 +++++++++++++++++++++------ cli/src/util.rs | 35 +++++++++++++++++++++++++++++++++-- 7 files changed, 89 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f20cc58..dc9621c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1340,6 +1340,7 @@ dependencies = [ "cc", "dirs", "fs4", + "indoc", "libloading", "once_cell", "regex", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index ed0d890c..6d99e6df 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -34,6 +34,7 @@ dirs.workspace = true glob.workspace = true html-escape.workspace = true indexmap.workspace = true +indoc.workspace = true lazy_static.workspace = true log.workspace = true memchr.workspace = true @@ -80,7 +81,6 @@ tempfile.workspace = true pretty_assertions.workspace = true ctor.workspace = true unindent.workspace = true -indoc.workspace = true [build-dependencies] toml.workspace = true diff --git a/cli/src/main.rs b/cli/src/main.rs index 39fe1c52..e9308628 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -575,6 +575,7 @@ fn run() -> Result<()> { highlighter.parser = parser; test_highlight::test_highlights( &loader, + &config.get()?, &mut highlighter, &test_highlight_dir, test_options.apply_all_captures, @@ -586,7 +587,7 @@ fn run() -> Result<()> { if test_tag_dir.is_dir() { let mut tags_context = TagsContext::new(); tags_context.parser = parser; - test_tags::test_tags(&loader, &mut tags_context, &test_tag_dir)?; + test_tags::test_tags(&loader, &config.get()?, &mut tags_context, &test_tag_dir)?; } } @@ -662,7 +663,7 @@ fn run() -> Result<()> { if let Some(v) = loader.language_configuration_for_file_name(path)? { v } else { - eprintln!("No language found for path {path:?}"); + eprintln!("{}", util::lang_not_found_for_path(path, &loader_config)); continue; } } @@ -744,6 +745,7 @@ fn run() -> Result<()> { let paths = collect_paths(tags_options.paths_file.as_deref(), tags_options.paths)?; tags::generate_tags( &loader, + &config.get()?, tags_options.scope.as_deref(), &paths, tags_options.quiet, diff --git a/cli/src/tags.rs b/cli/src/tags.rs index 6210cb3b..14ecef0d 100644 --- a/cli/src/tags.rs +++ b/cli/src/tags.rs @@ -4,11 +4,12 @@ use std::io::{self, Write}; use std::path::Path; use std::time::Instant; use std::{fs, str}; -use tree_sitter_loader::Loader; +use tree_sitter_loader::{Config, Loader}; use tree_sitter_tags::TagsContext; pub fn generate_tags( loader: &Loader, + loader_config: &Config, scope: Option<&str>, paths: &[String], quiet: bool, @@ -35,7 +36,7 @@ pub fn generate_tags( if let Some(v) = loader.language_configuration_for_file_name(path)? { v } else { - eprintln!("No language found for path {path:?}"); + eprintln!("{}", util::lang_not_found_for_path(path, loader_config)); continue; } } diff --git a/cli/src/test_highlight.rs b/cli/src/test_highlight.rs index dd6b6811..63f80897 100644 --- a/cli/src/test_highlight.rs +++ b/cli/src/test_highlight.rs @@ -1,11 +1,16 @@ -use crate::query_testing::{parse_position_comments, Assertion}; -use ansi_term::Colour; -use anyhow::{anyhow, Result}; use std::fs; use std::path::Path; + +use ansi_term::Colour; +use anyhow::{anyhow, Result}; use tree_sitter::Point; use tree_sitter_highlight::{Highlight, HighlightConfiguration, HighlightEvent, Highlighter}; -use tree_sitter_loader::Loader; +use tree_sitter_loader::{Config, Loader}; + +use super::{ + query_testing::{parse_position_comments, Assertion}, + util, +}; #[derive(Debug)] pub struct Failure { @@ -40,16 +45,25 @@ impl std::fmt::Display for Failure { pub fn test_highlights( loader: &Loader, + loader_config: &Config, highlighter: &mut Highlighter, directory: &Path, apply_all_captures: bool, ) -> Result<()> { println!("syntax highlighting:"); - test_highlights_indented(loader, highlighter, directory, apply_all_captures, 2) + test_highlights_indented( + loader, + loader_config, + highlighter, + directory, + apply_all_captures, + 2, + ) } fn test_highlights_indented( loader: &Loader, + loader_config: &Config, highlighter: &mut Highlighter, directory: &Path, apply_all_captures: bool, @@ -70,6 +84,7 @@ fn test_highlights_indented( println!("{}:", test_file_name.into_string().unwrap()); if test_highlights_indented( loader, + loader_config, highlighter, &test_file_path, apply_all_captures, @@ -82,7 +97,12 @@ fn test_highlights_indented( } else { let (language, language_config) = loader .language_configuration_for_file_name(&test_file_path)? - .ok_or_else(|| anyhow!("No language found for path {test_file_path:?}"))?; + .ok_or_else(|| { + anyhow!( + "{}", + util::lang_not_found_for_path(test_file_path.as_path(), loader_config) + ) + })?; let highlight_config = language_config .highlight_config(language, apply_all_captures, None)? .ok_or_else(|| anyhow!("No highlighting config found for {test_file_path:?}"))?; diff --git a/cli/src/test_tags.rs b/cli/src/test_tags.rs index 85055f2b..11395e10 100644 --- a/cli/src/test_tags.rs +++ b/cli/src/test_tags.rs @@ -1,12 +1,17 @@ -use crate::query_testing::{parse_position_comments, Assertion}; -use ansi_term::Colour; -use anyhow::{anyhow, Result}; use std::fs; use std::path::Path; + +use ansi_term::Colour; +use anyhow::{anyhow, Result}; use tree_sitter::Point; -use tree_sitter_loader::Loader; +use tree_sitter_loader::{Config, Loader}; use tree_sitter_tags::{TagsConfiguration, TagsContext}; +use super::{ + query_testing::{parse_position_comments, Assertion}, + util, +}; + #[derive(Debug)] pub struct Failure { row: usize, @@ -38,7 +43,12 @@ impl std::fmt::Display for Failure { } } -pub fn test_tags(loader: &Loader, tags_context: &mut TagsContext, directory: &Path) -> Result<()> { +pub fn test_tags( + loader: &Loader, + loader_config: &Config, + tags_context: &mut TagsContext, + directory: &Path, +) -> Result<()> { let mut failed = false; println!("tags:"); @@ -48,7 +58,12 @@ pub fn test_tags(loader: &Loader, tags_context: &mut TagsContext, directory: &Pa let test_file_name = tag_test_file.file_name(); let (language, language_config) = loader .language_configuration_for_file_name(&test_file_path)? - .ok_or_else(|| anyhow!("No language found for path {:?}", test_file_path))?; + .ok_or_else(|| { + anyhow!( + "{}", + util::lang_not_found_for_path(test_file_path.as_path(), loader_config) + ) + })?; let tags_config = language_config .tags_config(language)? .ok_or_else(|| anyhow!("No tags config found for {:?}", test_file_path))?; diff --git a/cli/src/util.rs b/cli/src/util.rs index 3599f6fb..4ac9a082 100644 --- a/cli/src/util.rs +++ b/cli/src/util.rs @@ -1,13 +1,17 @@ -use anyhow::{anyhow, Context, Result}; use std::{ - path::PathBuf, + path::{Path, PathBuf}, process::{Child, ChildStdin, Command, Stdio}, sync::{ atomic::{AtomicUsize, Ordering}, Arc, }, }; + +use anyhow::{anyhow, Context, Result}; +use indoc::indoc; use tree_sitter::{Parser, Tree}; +use tree_sitter_config::Config; +use tree_sitter_loader::Config as LoaderConfig; const HTML_HEADER: &[u8] = b" @@ -18,6 +22,33 @@ svg { width: 100%; } "; +pub fn lang_not_found_for_path(path: &Path, loader_config: &LoaderConfig) -> String { + let path = path.display(); + format!( + indoc! {" + No language found for path `{}` + + If a language should be associated with this file extension, please ensure the path to `{}` is inside one of the following directories as specified by your 'config.json':\n\n{}\n + If the directory that contains the relevant grammar for `{}` is not listed above, please add the directory to the list of directories in your config file, {} + "}, + path, + path, + loader_config + .parser_directories + .iter() + .enumerate() + .map(|(i, d)| format!(" {}. {}", i + 1, d.display())) + .collect::>() + .join(" \n"), + path, + if let Ok(Some(config_path)) = Config::find_config_file() { + format!("located at {}", config_path.display()) + } else { + String::from("which you need to create by running `tree-sitter init-config`") + } + ) +} + #[must_use] pub fn cancel_on_signal() -> Arc { let result = Arc::new(AtomicUsize::new(0));