From 26262aaf05983c5b7f41cc438e287523268fe1eb Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 10 Aug 2018 22:23:17 +0300 Subject: extend selection via LSP --- libanalysis/src/arena.rs | 42 ----------------------- libanalysis/src/lib.rs | 89 +++++++++++++++++++++++++++++------------------- 2 files changed, 54 insertions(+), 77 deletions(-) delete mode 100644 libanalysis/src/arena.rs (limited to 'libanalysis/src') diff --git a/libanalysis/src/arena.rs b/libanalysis/src/arena.rs deleted file mode 100644 index fc0c25c54..000000000 --- a/libanalysis/src/arena.rs +++ /dev/null @@ -1,42 +0,0 @@ -use parking_lot::RwLock; - -const CHUNK_LEN: usize = 16; - -pub struct Arena { - chunks: RwLock>>, -} - -impl Arena { - pub fn new(&self) -> Arena { - Arena { - chunks: RwLock::new(vec![Vec::with_capacity(CHUNK_LEN)]), - } - } - - pub fn push(&self, value: T) -> usize { - let mut guard = self.chunks.write(); - let mut idx = (guard.len() - 1) * CHUNK_LEN; - let chunk = { - if guard.last().unwrap().len() == CHUNK_LEN { - guard.push(Vec::with_capacity(CHUNK_LEN)); - } - guard.last_mut().unwrap() - }; - assert!(chunk.len() < chunk.capacity()); - idx += chunk.len(); - chunk.push(value); - idx - } - - pub fn get(&self, idx: usize) -> &T { - let chunk_idx = idx / CHUNK_LEN; - let chunk_off = idx - chunk_idx * CHUNK_LEN; - let guard = self.chunks.read(); - let value = &guard[chunk_idx][chunk_off]; - unsafe { - // We are careful to not move values in chunks, - // so this hopefully is safe - ::std::mem::transmute::<&T, &T>(value) - } - } -} diff --git a/libanalysis/src/lib.rs b/libanalysis/src/lib.rs index 417a544ca..6a946a0b0 100644 --- a/libanalysis/src/lib.rs +++ b/libanalysis/src/lib.rs @@ -2,9 +2,11 @@ extern crate failure; extern crate parking_lot; #[macro_use] extern crate log; +extern crate once_cell; extern crate libsyntax2; +extern crate libeditor; -mod arena; +use once_cell::sync::OnceCell; use std::{ fs, @@ -14,6 +16,7 @@ use std::{ }; use parking_lot::RwLock; use libsyntax2::ast; +use libeditor::LineIndex; pub type Result = ::std::result::Result; @@ -39,7 +42,6 @@ impl WorldState { pub fn change_overlay(&mut self, path: PathBuf, text: Option) { let data = self.data_mut(); data.file_map.get_mut().remove(&path); - data.fs_map.get_mut().remove(&path); if let Some(text) = text { data.mem_map.insert(path, Arc::new(text)); } else { @@ -49,11 +51,9 @@ impl WorldState { fn data_mut(&mut self) -> &mut WorldData { if Arc::get_mut(&mut self.data).is_none() { - let fs_map = self.data.fs_map.read().clone(); let file_map = self.data.file_map.read().clone(); self.data = Arc::new(WorldData { mem_map: self.data.mem_map.clone(), - fs_map: RwLock::new(fs_map), file_map: RwLock::new(file_map), }); } @@ -64,43 +64,57 @@ impl WorldState { impl World { pub fn file_syntax(&self, path: &Path) -> Result { - { - let guard = self.data.file_map.read(); - if let Some(file) = guard.get(path) { - return Ok(file.clone()); - } - } - let file = self.with_file_text(path, |text| { - trace!("parsing file: {}", path.display()); - ast::File::parse(text) - })?; - let mut guard = self.data.file_map.write(); - let file = guard.entry(path.to_owned()) - .or_insert(file) - .clone(); - Ok(file) + let data = self.file_data(path)?; + let syntax = data.syntax + .get_or_init(|| { + trace!("parsing: {}", path.display()); + ast::File::parse(self.file_text(path, &data)) + }).clone(); + Ok(syntax) } - fn with_file_text R, R>(&self, path: &Path, f: F) -> Result { - if let Some(text) = self.data.mem_map.get(path) { - return Ok(f(&*text)); + pub fn file_line_index(&self, path: &Path) -> Result { + let data = self.file_data(path)?; + let index = data.lines + .get_or_init(|| { + trace!("calc line index: {}", path.display()); + LineIndex::new(self.file_text(path, &data)) + }); + Ok(index.clone()) + } + + fn file_text<'a>(&'a self, path: &Path, file_data: &'a FileData) -> &'a str { + match file_data.text.as_ref() { + Some(text) => text.as_str(), + None => self.data.mem_map[path].as_str() } + } + fn file_data(&self, path: &Path) -> Result> { { - let guard = self.data.fs_map.read(); - if let Some(text) = guard.get(path) { - return Ok(f(&*text)); + let guard = self.data.file_map.read(); + if let Some(data) = guard.get(path) { + return Ok(data.clone()); } } - trace!("loading file from disk: {}", path.display()); - let text = fs::read_to_string(path)?; - { - let mut guard = self.data.fs_map.write(); + + let text = if self.data.mem_map.contains_key(path) { + None + } else { + trace!("loading file from disk: {}", path.display()); + Some(fs::read_to_string(path)?) + }; + let res = { + let mut guard = self.data.file_map.write(); guard.entry(path.to_owned()) - .or_insert_with(|| Arc::new(text)); - } - let guard = self.data.fs_map.read(); - Ok(f(&guard[path])) + .or_insert_with(|| Arc::new(FileData { + text, + syntax: OnceCell::new(), + lines: OnceCell::new(), + })) + .clone() + }; + Ok(res) } } @@ -108,6 +122,11 @@ impl World { #[derive(Default)] struct WorldData { mem_map: HashMap>, - fs_map: RwLock>>, - file_map: RwLock>, + file_map: RwLock>>, +} + +struct FileData { + text: Option, + syntax: OnceCell, + lines: OnceCell, } -- cgit v1.2.3