Mountain/ApplicationState/DTO/
DocumentStateDTO.rs

1//! # DocumentStateDTO
2//!
3//! Defines the Data Transfer Object for storing the state of a single open
4//! text document in memory.
5
6#![allow(non_snake_case, non_camel_case_types)]
7
8use Common::Error::CommonError::CommonError;
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11use url::Url;
12
13use super::RPCModelContentChangeDTO::RPCModelContentChangeDTO;
14use crate::ApplicationState::Internal::{AnalyzeTextLinesAndEOL, URLSerializationHelper};
15
16/// Represents the complete in-memory state of a single text document.
17#[derive(Serialize, Deserialize, Clone, Debug)]
18#[serde(rename_all = "PascalCase")]
19pub struct DocumentStateDTO {
20	/// The unique resource identifier for this document.
21	#[serde(with = "URLSerializationHelper")]
22	pub URI:Url,
23
24	/// The VS Code language identifier (e.g., "rust", "typescript").
25	pub LanguageIdentifier:String,
26
27	/// The version number, incremented on each change from the client.
28	pub Version:i64,
29
30	/// The content of the document, split into lines.
31	pub Lines:Vec<String>,
32
33	/// The detected end-of-line sequence (e.g., `\n` or `\r\n`).
34	pub EOL:String,
35
36	/// A flag indicating if the in-memory version has unsaved changes.
37	pub IsDirty:bool,
38
39	/// The detected file encoding (e.g., "utf8").
40	pub Encoding:String,
41
42	/// An internal version number, used for tracking changes within the host.
43	pub VersionIdentifier:i64,
44}
45
46impl DocumentStateDTO {
47	/// Creates a new `DocumentStateDTO` from its initial content.
48	pub fn Create(URI:Url, LanguageIdentifier:Option<String>, Content:String) -> Self {
49		let (Lines, EOL) = AnalyzeTextLinesAndEOL(&Content);
50
51		let LanguageID = LanguageIdentifier.unwrap_or_else(|| "plaintext".to_string());
52
53		let Encoding = "utf8".to_string();
54
55		Self {
56			URI,
57
58			LanguageIdentifier:LanguageID,
59
60			Version:1,
61
62			Lines,
63
64			EOL,
65
66			IsDirty:false,
67
68			Encoding,
69
70			VersionIdentifier:1,
71		}
72	}
73
74	/// Reconstructs the full text content of the document from its lines.
75	pub fn GetText(&self) -> String { self.Lines.join(&self.EOL) }
76
77	/// Converts the struct to a `serde_json::Value`, useful for notifications.
78	pub fn ToDTO(&self) -> Result<Value, CommonError> {
79		serde_json::to_value(self).map_err(|Error| CommonError::SerializationError { Description:Error.to_string() })
80	}
81
82	/// Applies a set of changes to the document. This can be a full text
83	/// replacement or a collection of delta changes.
84	pub fn ApplyChanges(&mut self, NewVersion:i64, ChangesValue:&Value) -> Result<(), CommonError> {
85		// Ignore stale changes.
86		if NewVersion <= self.Version {
87			return Ok(());
88		}
89
90		// Attempt to deserialize as an array of delta changes first.
91		if let Ok(RPCChange) = serde_json::from_value::<Vec<RPCModelContentChangeDTO>>(ChangesValue.clone()) {
92			// A full implementation would apply each delta change to the `Lines` vector.
93			// This is a complex operation involving coordinate transformations.
94			// For now, we will log that this is a stub and only update the version.
95			log::warn!(
96				"Applying changes to {} by version bump only (delta application is a stub).",
97				self.URI
98			);
99
100			// In a real implementation:
101			self.Lines = ApplyDeltaChanges(&self.Lines, &self.EOL, &RPCChange);
102		} else if let Some(FullText) = ChangesValue.as_str() {
103			// If it's not deltas, check if it's a full text replacement.
104			let (NewLines, NewEOL) = AnalyzeTextLinesAndEOL(FullText);
105
106			self.Lines = NewLines;
107
108			self.EOL = NewEOL;
109		} else {
110			return Err(CommonError::InvalidArgument {
111				ArgumentName:"ChangesValue".into(),
112
113				Reason:format!(
114					"Invalid change format for {}: expected string or RPCModelContentChangeDTO array.",
115					self.URI
116				),
117			});
118		}
119
120		// Update metadata after changes have been applied.
121		self.Version = NewVersion;
122
123		self.VersionIdentifier += 1;
124
125		self.IsDirty = true;
126
127		Ok(())
128	}
129}
130
131fn ApplyDeltaChanges(_Line:&[String], _EOL:&str, _RPCChange:&[RPCModelContentChangeDTO]) -> Vec<String> { todo!() }