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;