From 74199c40fb3c1c390440d244740791eae0d871d9 Mon Sep 17 00:00:00 2001 From: Nicolas BACQUEY Date: Wed, 20 Nov 2024 16:32:43 +0100 Subject: [PATCH] shameful algebra on text blocks/text positions --- topiary-core/src/tree_sitter.rs | 67 ++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/topiary-core/src/tree_sitter.rs b/topiary-core/src/tree_sitter.rs index 2ef41b5f..9d3dab0a 100644 --- a/topiary-core/src/tree_sitter.rs +++ b/topiary-core/src/tree_sitter.rs @@ -1,4 +1,4 @@ -use std::{collections::HashSet, fmt::Display}; +use std::{cmp::{Ord, Ordering}, collections::HashSet, fmt::Display}; use serde::Serialize; use topiary_tree_sitter_facade::{ @@ -22,7 +22,8 @@ pub enum Visualisation { /// Refers to a position within the code. Used for error reporting, and for /// comparing input with formatted output. The numbers are 1-based, because that /// is how editors usually refer to a position. Derived from tree_sitter::Point. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] +/// Note that the order is the standard western reading order. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize)] pub struct Position { pub row: u32, pub column: u32, @@ -245,6 +246,68 @@ fn previous_non_comment<'tree>(node: Node<'tree>) -> Option> { } } +// Some section of contiguous characters in the input. +// It is assumed that `start <= end`, according to the order on `Position`. +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct InputSection { + start: Position, + end: Position, +} + +// This order only applies to disjoint sections, where it is the western reading order. +impl PartialOrd for InputSection { + fn partial_cmp(&self, other: &Self) -> Option { + if self.end <= other.start { + Some(Ordering::Less) + } else if other.end <= self.start { + Some(Ordering::Greater) + } else if self == other { + Some(Ordering::Equal) + } else { + None + } + } +} + +pub trait Diff { + fn substract(self: &mut Self, other: &T) -> Result<(), E>; +} + +impl Diff for Position { + fn substract(self: &mut Self, other: &InputSection) -> FormatterResult<()> { + if *self <= other.start { + // Nothing happens here + Ok(()) + } else if other.end <= *self { + let mut row = self.row; + let mut column = self.column; + if row == other.end.row { + column = column + other.start.column - other.end.column + } else { + row = row + other.start.row - other.end.row + } + *self = Position{row, column}; + Ok(()) + } else { + Err(FormatterError::Internal("Tried to substract a section from a point it contains".into(), None)) + } + } +} + +impl Diff for InputSection { + fn substract(self: &mut Self, other: &Self) -> FormatterResult<()> { + if *self <= *other { + // Nothing happens here + Ok(()) + } else if other <= self { + self.start.substract(other)?; + self.end.substract(other) + } else { + Err(FormatterError::Internal("Tried to diff input sections that weren't comparable".into(), None)) + } + } +} + // Use the following heuristics to find a comment's anchor: // If the comment is only prefixed by blank symbols on its line, then the anchor is the // next non-comment sibling node.