Skip to content

Commit

Permalink
feat: ropey and incremental file changes
Browse files Browse the repository at this point in the history
  • Loading branch information
meetmangukiya committed Jun 18, 2024
1 parent 31cf58f commit 92f68f9
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 58 deletions.
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ serde_json = "1.0.103"
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
foundry-compilers = "0.8.0"
ropey = "1.6.1"
96 changes: 42 additions & 54 deletions src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use foundry_compilers::{
project::ProjectCompiler,
ProjectCompileOutput,
};
use ropey::Rope;
use similar::{DiffOp, TextDiff};
use solang_parser::pt::SourceUnitPart;
use tokio::task::JoinSet;
Expand Down Expand Up @@ -354,7 +355,7 @@ impl BackendState {
.get(&file_path.to_string())
.unwrap()
.text
.clone());
.to_string());
}

// read from disk if the document is not owned by client
Expand Down Expand Up @@ -494,6 +495,8 @@ pub enum BackendError {
InvalidLocationError,
#[error("Option unwrap error")]
OptionUnwrap,
#[error("Ropey query error")]
RopeyQueryError,
}

enum FileAction {
Expand Down Expand Up @@ -615,8 +618,16 @@ impl Backend {
self.on_file_change(FileAction::Update, file_path).await;
}

pub fn update_file_range(&self, _file_path: &Url, _range: Range, _text: String) {
unimplemented!("update_file_range")
pub async fn update_file_range(&self, file_path: &Url, range: Range, text: String) {
{
let mut src = self
.state
.documents
.get_mut(&file_path.to_string())
.expect("given file doesnt exist in state");
src.update_range(range, text);
}
self.on_file_change(FileAction::Update, file_path).await;
}

async fn on_file_change(&self, action: FileAction, path: &Url) {
Expand Down Expand Up @@ -732,7 +743,7 @@ impl Backend {

#[derive(Debug)]
pub struct Source {
pub text: String,
pub text: Rope,
pub line_lengths: Vec<usize>,
}

Expand All @@ -741,11 +752,20 @@ impl Source {
let line_lengths = source.as_str().lines().map(|x| x.len()).collect();

Source {
text: source,
text: Rope::from_str(source.as_str()),
line_lengths,
}
}

pub fn update_range(&mut self, range: Range, text: String) {
let start = self.text.line_to_char(range.start.line as usize);
let start_char_idx = start + (range.start.character as usize);
let end = self.text.line_to_char(range.end.line as usize);
let end_char_idx = end + (range.end.character as usize);
self.text.remove(start_char_idx..end_char_idx);
self.text.insert(start_char_idx, text.as_str());
}

pub fn loc_to_range(
&self,
loc: &solang_parser::pt::Loc,
Expand All @@ -767,55 +787,23 @@ impl Source {
&self,
index: usize,
) -> Result<tower_lsp::lsp_types::Position, BackendError> {
let mut chars_read = 0;
for (i, line_length) in self.line_lengths.iter().enumerate() {
let line_number = i;
let last_char_pos = chars_read + line_length;
let first_char_pos = chars_read;
if index >= first_char_pos && index <= last_char_pos {
return Ok(tower_lsp::lsp_types::Position {
line: line_number as u32,
character: (index - first_char_pos) as u32,
});
}
chars_read += line_length + 1; // for \n
}
error!("position not found");
Err(BackendError::PositionNotFoundError)
}

#[allow(dead_code)]
fn position_to_byte_index(
&self,
position: &tower_lsp::lsp_types::Position,
) -> Result<usize, BackendError> {
let mut chars_read = 0;
for (i, line_length) in self.line_lengths.iter().enumerate() {
let line_number = i;
let _last_char_pos = chars_read + line_length;
let first_char_pos = chars_read;
if position.line as usize == line_number {
return Ok(first_char_pos + position.character as usize);
}
chars_read += line_length + 1; // for \n
}
Err(BackendError::PositionNotFoundError)
}

#[allow(dead_code)]
fn get_loc_substring(&self, loc: &solang_parser::pt::Loc) -> String {
if let solang_parser::pt::Loc::File(_, start, end) = loc {
self.text[*start..*end].to_string()
} else {
"".to_string()
}
}

#[allow(dead_code)]
fn get_range_substring(&self, range: &tower_lsp::lsp_types::Range) -> anyhow::Result<String> {
let start = self.position_to_byte_index(&range.start)?;
let end = self.position_to_byte_index(&range.end)?;
Ok(self.text[start..end].to_string())
let line_idx = self
.text
.try_byte_to_line(index)
.map_err(|_| BackendError::RopeyQueryError)?;
let line_char_idx = self
.text
.try_line_to_char(line_idx)
.map_err(|_| BackendError::RopeyQueryError)?;
let char_idx = self
.text
.try_byte_to_char(index)
.map_err(|_| BackendError::RopeyQueryError)?;

return Ok(tower_lsp::lsp_types::Position {
line: line_idx as u32,
character: (char_idx - line_char_idx) as u32,
});
}
}

Expand Down
7 changes: 3 additions & 4 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ impl LanguageServer for Backend {
text_document_sync: Some(TextDocumentSyncCapability::Options(
TextDocumentSyncOptions {
open_close: Some(true),
// TODO: maybe incremental would be better for perf
// Keeping it simple for now though
change: Some(TextDocumentSyncKind::FULL),
change: Some(TextDocumentSyncKind::INCREMENTAL),
..Default::default()
},
)),
Expand Down Expand Up @@ -72,7 +70,8 @@ impl LanguageServer for Backend {
for content_change in params.content_changes {
match content_change.range {
Some(range) => {
self.update_file_range(&file_path, range, content_change.text);
self.update_file_range(&file_path, range, content_change.text)
.await;
}
None => {
self.update_file(&file_path, content_change.text).await;
Expand Down

0 comments on commit 92f68f9

Please sign in to comment.