fork of https://github.com/tree-sitter/tree-sitter-graph

Prepare Excerpt for reuse for parse errors

Changed files
+139 -104
src
+24 -102
src/execution/error.rs
··· 5 5 // Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details. 6 6 // ------------------------------------------------------------------------------------------------ 7 7 8 - #[cfg(feature = "term-colors")] 9 - use colored::Colorize; 10 8 use std::path::Path; 11 9 use thiserror::Error; 12 10 13 - use crate::ast::{Stanza, Statement}; 11 + use crate::ast::Stanza; 12 + use crate::ast::Statement; 14 13 use crate::execution::CancellationError; 14 + use crate::parse_error::Excerpt; 15 15 use crate::Location; 16 16 17 17 /// An error that can occur while executing a graph DSL file ··· 213 213 write!( 214 214 f, 215 215 "{}", 216 - Excerpt::from_source(self.tsg_path, self.tsg, statement_location, 7) 216 + Excerpt::from_source( 217 + self.tsg_path, 218 + self.tsg, 219 + statement_location.row, 220 + statement_location.to_column_range(), 221 + 7 222 + ) 217 223 )?; 218 224 writeln!(f, "{}in stanza", " ".repeat(7))?; 219 225 write!( 220 226 f, 221 227 "{}", 222 - Excerpt::from_source(self.tsg_path, self.tsg, stanza_location, 7) 228 + Excerpt::from_source( 229 + self.tsg_path, 230 + self.tsg, 231 + stanza_location.row, 232 + stanza_location.to_column_range(), 233 + 7 234 + ) 223 235 )?; 224 236 writeln!(f, "{}matching ({}) node", " ".repeat(7), node_kind)?; 225 237 write!( 226 238 f, 227 239 "{}", 228 - Excerpt::from_source(self.source_path, self.source, source_location, 7) 240 + Excerpt::from_source( 241 + self.source_path, 242 + self.source, 243 + source_location.row, 244 + source_location.to_column_range(), 245 + 7 246 + ) 229 247 )?; 230 248 Ok(()) 231 249 } ··· 237 255 } 238 256 } 239 257 } 240 - 241 - /// Excerpts of source from either the target language file or the tsg rules file. 242 - struct Excerpt<'a> { 243 - path: &'a Path, 244 - source: Option<&'a str>, 245 - location: &'a Location, 246 - indent: usize, 247 - } 248 - 249 - impl<'a> Excerpt<'a> { 250 - pub fn from_source( 251 - path: &'a Path, 252 - source: &'a str, 253 - location: &'a Location, 254 - indent: usize, 255 - ) -> Excerpt<'a> { 256 - Excerpt { 257 - path, 258 - source: source.lines().nth(location.row), 259 - location, 260 - indent, 261 - } 262 - } 263 - 264 - fn gutter_width(&self) -> usize { 265 - ((self.location.row + 1) as f64).log10() as usize + 1 266 - } 267 - } 268 - 269 - impl<'a> std::fmt::Display for Excerpt<'a> { 270 - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 271 - // path and line/col 272 - write!( 273 - f, 274 - "{}{}:{}:{}:", 275 - " ".repeat(self.indent), 276 - white_bold(&self.path.to_str().unwrap_or("<unknown file>")), 277 - white_bold(&format!("{}", self.location.row + 1)), 278 - white_bold(&format!("{}", self.location.column + 1)), 279 - )?; 280 - if let Some(source) = self.source { 281 - writeln!(f)?; 282 - // first line: line number & source 283 - writeln!( 284 - f, 285 - "{}{}{}{}", 286 - " ".repeat(self.indent), 287 - blue(&format!("{}", self.location.row + 1)), 288 - blue(" | "), 289 - source, 290 - )?; 291 - // second line: caret 292 - writeln!( 293 - f, 294 - "{}{}{}{}{}", 295 - " ".repeat(self.indent), 296 - " ".repeat(self.gutter_width()), 297 - blue(" | "), 298 - " ".repeat(self.location.column), 299 - green_bold("^") 300 - )?; 301 - } else { 302 - writeln!(f, " <missing source>")?; 303 - } 304 - Ok(()) 305 - } 306 - } 307 - 308 - // coloring functions 309 - 310 - #[cfg(feature = "term-colors")] 311 - fn blue(str: &str) -> impl std::fmt::Display { 312 - str.blue() 313 - } 314 - #[cfg(not(feature = "term-colors"))] 315 - fn blue<'a>(str: &'a str) -> impl std::fmt::Display + 'a { 316 - str 317 - } 318 - 319 - #[cfg(feature = "term-colors")] 320 - fn green_bold(str: &str) -> impl std::fmt::Display { 321 - str.green().bold() 322 - } 323 - #[cfg(not(feature = "term-colors"))] 324 - fn green_bold<'a>(str: &'a str) -> impl std::fmt::Display + 'a { 325 - str 326 - } 327 - 328 - #[cfg(feature = "term-colors")] 329 - fn white_bold(str: &str) -> impl std::fmt::Display { 330 - str.white().bold() 331 - } 332 - #[cfg(not(feature = "term-colors"))] 333 - fn white_bold<'a>(str: &'a str) -> impl std::fmt::Display + 'a { 334 - str 335 - }
+110 -2
src/parse_error.rs
··· 7 7 8 8 //! Data types and functions for finding and displaying tree-sitter parse errors. 9 9 10 + #[cfg(feature = "term-colors")] 11 + use colored::Colorize; 12 + use std::ops::Range; 13 + use std::path::Path; 10 14 use tree_sitter::Node; 11 15 use tree_sitter::Tree; 12 16 ··· 57 61 } 58 62 } 59 63 60 - pub fn display(&self, source: &'tree str, verbose: bool) -> ParseErrorDisplay { 64 + pub fn display<'a: 'tree>( 65 + &'a self, 66 + source: &'tree str, 67 + verbose: bool, 68 + ) -> impl std::fmt::Display + 'a + 'tree { 61 69 ParseErrorDisplay { 62 70 error: self, 63 71 source, ··· 66 74 } 67 75 } 68 76 69 - pub struct ParseErrorDisplay<'tree> { 77 + struct ParseErrorDisplay<'tree> { 70 78 error: &'tree ParseError<'tree>, 71 79 source: &'tree str, 72 80 verbose: bool, ··· 308 316 // This is okay because Send and Sync _are_ implemented for Tree, which also holds ffi::TSTree 309 317 unsafe impl Send for TreeWithParseErrorVec {} 310 318 unsafe impl Sync for TreeWithParseErrorVec {} 319 + 320 + //----------------------------------------------------------------------------- 321 + 322 + /// Excerpts of source from either the target language file or the tsg rules file. 323 + pub(crate) struct Excerpt<'a> { 324 + path: &'a Path, 325 + source: Option<&'a str>, 326 + row: usize, 327 + columns: Range<usize>, 328 + indent: usize, 329 + } 330 + 331 + impl<'a> Excerpt<'a> { 332 + pub fn from_source( 333 + path: &'a Path, 334 + source: &'a str, 335 + row: usize, 336 + columns: Range<usize>, 337 + indent: usize, 338 + ) -> Excerpt<'a> { 339 + Excerpt { 340 + path, 341 + source: source.lines().nth(row), 342 + row, 343 + columns, 344 + indent, 345 + } 346 + } 347 + 348 + fn gutter_width(&self) -> usize { 349 + ((self.row + 1) as f64).log10() as usize + 1 350 + } 351 + } 352 + 353 + impl<'a> std::fmt::Display for Excerpt<'a> { 354 + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 355 + // path and line/col 356 + writeln!( 357 + f, 358 + "{}{}:{}:{}:", 359 + " ".repeat(self.indent), 360 + white_bold(&self.path.to_str().unwrap_or("<unknown file>")), 361 + white_bold(&format!("{}", self.row + 1)), 362 + white_bold(&format!("{}", self.columns.start + 1)), 363 + )?; 364 + if let Some(source) = self.source { 365 + // first line: line number & source 366 + writeln!( 367 + f, 368 + "{}{}{}{}", 369 + " ".repeat(self.indent), 370 + blue(&format!("{}", self.row + 1)), 371 + blue(" | "), 372 + source, 373 + )?; 374 + // second line: caret 375 + writeln!( 376 + f, 377 + "{}{}{}{}{}", 378 + " ".repeat(self.indent), 379 + " ".repeat(self.gutter_width()), 380 + blue(" | "), 381 + " ".repeat(self.columns.start), 382 + green_bold(&"^".repeat(self.columns.len())) 383 + )?; 384 + } else { 385 + writeln!(f, "{}{}", " ".repeat(self.indent), "<missing source>",)?; 386 + } 387 + Ok(()) 388 + } 389 + } 390 + 391 + // coloring functions 392 + 393 + #[cfg(feature = "term-colors")] 394 + fn blue(str: &str) -> impl std::fmt::Display { 395 + str.blue() 396 + } 397 + #[cfg(not(feature = "term-colors"))] 398 + fn blue<'a>(str: &'a str) -> impl std::fmt::Display + 'a { 399 + str 400 + } 401 + 402 + #[cfg(feature = "term-colors")] 403 + fn green_bold(str: &str) -> impl std::fmt::Display { 404 + str.green().bold() 405 + } 406 + #[cfg(not(feature = "term-colors"))] 407 + fn green_bold<'a>(str: &'a str) -> impl std::fmt::Display + 'a { 408 + str 409 + } 410 + 411 + #[cfg(feature = "term-colors")] 412 + fn white_bold(str: &str) -> impl std::fmt::Display { 413 + str.white().bold() 414 + } 415 + #[cfg(not(feature = "term-colors"))] 416 + fn white_bold<'a>(str: &'a str) -> impl std::fmt::Display + 'a { 417 + str 418 + }
+5
src/parser.rs
··· 7 7 8 8 use std::fmt::Display; 9 9 use std::iter::Peekable; 10 + use std::ops::Range; 10 11 use std::str::Chars; 11 12 12 13 use regex::Regex; ··· 91 92 } else { 92 93 self.column += 1; 93 94 } 95 + } 96 + 97 + pub(crate) fn to_column_range(&self) -> Range<usize> { 98 + self.column..self.column + 1 94 99 } 95 100 } 96 101