use increparse::{CancelToken, Edit, Engine, Executor, RunReport, Session, Span};
use lsp_types::{Location, Position, Range, TextDocumentContentChangeEvent, Uri};
use crate::encoding::PositionEncoding;
use crate::line_index::LineIndex;
pub struct Document<C> {
uri: Uri,
language_id: String,
text: String,
session: Session<C>,
version: i32,
encoding: PositionEncoding,
index: LineIndex,
}
impl<C: Clone + PartialEq + Send + 'static> Document<C> {
pub fn open(
uri: Uri,
version: i32,
language_id: String,
text: String,
encoding: PositionEncoding,
root_ctx: C,
) -> Self {
let index = LineIndex::new(&text);
let session = Session::new(0, Span::new(0, text.len(), 0), root_ctx);
Self {
uri,
language_id,
text,
session,
version,
encoding,
index,
}
}
pub fn uri(&self) -> &Uri {
&self.uri
}
pub fn language_id(&self) -> &str {
&self.language_id
}
pub fn text(&self) -> &str {
&self.text
}
pub fn version(&self) -> i32 {
self.version
}
pub fn encoding(&self) -> PositionEncoding {
self.encoding
}
pub fn line_index(&self) -> &LineIndex {
&self.index
}
pub fn session(&self) -> &Session<C> {
&self.session
}
pub fn session_mut(&mut self) -> &mut Session<C> {
&mut self.session
}
pub fn revision(&self) -> u64 {
self.session.revision()
}
pub fn location(&self, span: Span) -> Location {
Location {
uri: self.uri.clone(),
range: self.range(span),
}
}
pub fn range(&self, span: Span) -> Range {
Range {
start: self.index.position(&self.text, span.start, self.encoding),
end: self.index.position(&self.text, span.end, self.encoding),
}
}
pub fn offset(&self, position: Position) -> usize {
self.index
.offset(&self.text, position, self.encoding)
.unwrap_or(self.text.len())
}
pub fn apply_changes<E>(
&mut self,
engine: &Engine<C>,
version: i32,
changes: &[TextDocumentContentChangeEvent],
exec: &E,
cancel: &CancelToken,
) -> RunReport
where
E: Executor,
{
for change in changes {
match change.range {
None => {
let edit = Edit::replace(0, self.text.len(), change.text.len());
self.text = change.text.clone();
self.session.edit(edit);
}
Some(range) => {
let start = self.offset(range.start);
let end = self.offset(range.end).max(start);
let edit = Edit::replace(start, end, start + change.text.len());
self.text.replace_range(start..end, &change.text);
self.session.edit(edit);
}
}
self.index = LineIndex::new(&self.text);
}
self.version = version;
self.session.run(engine, &self.text, exec, cancel)
}
}