Mountain/ApplicationState/DTO/RPCRangeDTO.rs
1//! # RPCRangeDTO
2//!
3//! # RESPONSIBILITY
4//! - Data transfer object for line/column-based text ranges
5//! - Serializable format for gRPC/IPC transmission
6//! - Used by Mountain to represent document edit ranges
7//!
8//! # FIELDS
9//! - StartLineNumber: Start line (0-based)
10//! - StartColumn: Start column (0-based)
11//! - EndLineNumber: End line (0-based)
12//! - EndColumn: End column (0-based)
13
14use serde::Deserialize;
15
16/// Maximum line number to prevent invalid ranges
17const MAX_LINE_NUMBER:usize = 1_000_000;
18
19/// Maximum column number to prevent invalid ranges
20const MAX_COLUMN_NUMBER:usize = 1_000_000;
21
22/// Represents a line and column-based range in a text document.
23/// Compatible with VS Code LSP position/range definitions.
24#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
25#[serde(rename_all = "PascalCase")]
26pub struct RPCRangeDTO {
27 /// Start line number (0-based)
28 pub StartLineNumber:usize,
29
30 /// Start column number (0-based)
31 pub StartColumn:usize,
32
33 /// End line number (0-based)
34 pub EndLineNumber:usize,
35
36 /// End column number (0-based)
37 pub EndColumn:usize,
38}
39
40impl RPCRangeDTO {
41 /// Creates a new RPCRangeDTO with validation.
42 ///
43 /// # Arguments
44 /// * `StartLineNumber` - Start line (0-based)
45 /// * `StartColumn` - Start column (0-based)
46 /// * `EndLineNumber` - End line (0-based)
47 /// * `EndColumn` - End column (0-based)
48 ///
49 /// # Returns
50 /// Result containing the DTO or validation error
51 pub fn New(StartLineNumber:usize, StartColumn:usize, EndLineNumber:usize, EndColumn:usize) -> Result<Self, String> {
52 // Validate line numbers
53 if StartLineNumber > MAX_LINE_NUMBER || EndLineNumber > MAX_LINE_NUMBER {
54 return Err(format!("Line numbers exceed maximum of {}", MAX_LINE_NUMBER));
55 }
56
57 // Validate column numbers
58 if StartColumn > MAX_COLUMN_NUMBER || EndColumn > MAX_COLUMN_NUMBER {
59 return Err(format!("Column numbers exceed maximum of {}", MAX_COLUMN_NUMBER));
60 }
61
62 // Validate position consistency
63 if StartLineNumber > EndLineNumber {
64 return Err("Start line number cannot be greater than end line number".to_string());
65 }
66
67 // Validate column consistency within same line
68 if StartLineNumber == EndLineNumber && StartColumn > EndColumn {
69 return Err("Start column cannot be greater than end column on the same line".to_string());
70 }
71
72 Ok(Self { StartLineNumber, StartColumn, EndLineNumber, EndColumn })
73 }
74
75 /// Checks if this is an empty range (start equals end).
76 pub fn IsEmpty(&self) -> bool { self.StartLineNumber == self.EndLineNumber && self.StartColumn == self.EndColumn }
77
78 /// Creates a range for inserting/replacing text at a specific position.
79 ///
80 /// # Arguments
81 /// * `LineNumber` - Line number (0-based)
82 /// * `Column` - Column number (0-based)
83 ///
84 /// # Returns
85 /// New RPCRangeDTO for position-based operations
86 pub fn Position(LineNumber:usize, Column:usize) -> Result<Self, String> {
87 Self::New(LineNumber, Column, LineNumber, Column)
88 }
89
90 /// Creates a range for a single line.
91 ///
92 /// # Arguments
93 /// * `LineNumber` - Line number (0-based)
94 /// * `StartColumn` - Start column
95 /// * `EndColumn` - End column
96 ///
97 /// # Returns
98 /// New RPCRangeDTO for single-line range
99 pub fn LineRange(LineNumber:usize, StartColumn:usize, EndColumn:usize) -> Result<Self, String> {
100 Self::New(LineNumber, StartColumn, LineNumber, EndColumn)
101 }
102}