Skip to main content

reovim_driver_syntax/
textobject.rs

1//! Semantic text object types for treesitter-based code navigation.
2//!
3//! Defines [`TextObjectKind`], [`TextObjectScope`], and [`TextObjectRange`]
4//! used by the [`SyntaxDriver::textobject_range()`](super::SyntaxDriver::textobject_range)
5//! method to resolve language-aware text objects (e.g., inner function, around class).
6
7/// Kind of semantic text object.
8///
9/// Maps to treesitter query capture prefixes (e.g., `Function` -> `"function"`).
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum TextObjectKind {
12    /// Function or method body.
13    Function,
14    /// Class, struct, enum, trait, or impl block.
15    Class,
16    /// Function argument or parameter.
17    Argument,
18    /// Conditional (if/else, match/switch).
19    Conditional,
20    /// Loop (for, while, loop).
21    Loop,
22    /// Comment (line or block).
23    Comment,
24    /// Block (braces, indented block).
25    Block,
26}
27
28impl TextObjectKind {
29    /// Get the treesitter capture name prefix for this kind.
30    ///
31    /// Used to construct capture names like `"function.inner"` or `"class.outer"`.
32    #[must_use]
33    pub const fn capture_name(&self) -> &'static str {
34        match self {
35            Self::Function => "function",
36            Self::Class => "class",
37            Self::Argument => "argument",
38            Self::Conditional => "conditional",
39            Self::Loop => "loop",
40            Self::Comment => "comment",
41            Self::Block => "block",
42        }
43    }
44}
45
46impl std::fmt::Display for TextObjectKind {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        f.write_str(self.capture_name())
49    }
50}
51
52/// Inner vs around scope for text objects.
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
54pub enum TextObjectScope {
55    /// Inner content only (e.g., function body without signature).
56    Inner,
57    /// Full construct including delimiters (e.g., entire function).
58    Outer,
59}
60
61impl TextObjectScope {
62    /// Get the treesitter capture name suffix.
63    #[must_use]
64    pub const fn suffix(&self) -> &'static str {
65        match self {
66            Self::Inner => "inner",
67            Self::Outer => "outer",
68        }
69    }
70}
71
72impl std::fmt::Display for TextObjectScope {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        f.write_str(self.suffix())
75    }
76}
77
78/// Result of a text object query — byte and position range in the buffer.
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub struct TextObjectRange {
81    /// Byte offset where the text object starts.
82    pub start_byte: usize,
83    /// Byte offset where the text object ends.
84    pub end_byte: usize,
85    /// Start row (0-indexed).
86    pub start_row: u32,
87    /// Start column (0-indexed).
88    pub start_col: u32,
89    /// End row (0-indexed).
90    pub end_row: u32,
91    /// End column (0-indexed).
92    pub end_col: u32,
93}
94
95impl TextObjectRange {
96    /// Create a new text object range.
97    #[must_use]
98    pub const fn new(
99        start_byte: usize,
100        end_byte: usize,
101        start_row: u32,
102        start_col: u32,
103        end_row: u32,
104        end_col: u32,
105    ) -> Self {
106        Self {
107            start_byte,
108            end_byte,
109            start_row,
110            start_col,
111            end_row,
112            end_col,
113        }
114    }
115
116    /// Get the byte length of this range.
117    #[must_use]
118    pub const fn byte_len(&self) -> usize {
119        self.end_byte - self.start_byte
120    }
121}
122
123#[cfg(test)]
124#[path = "textobject_tests.rs"]
125mod tests;