This commit is contained in:
Aleksey Kladov 2018-08-30 12:51:46 +03:00
parent 0d6d74e78e
commit 1f2fb4e27f
5 changed files with 101 additions and 96 deletions

View file

@ -395,7 +395,7 @@ async function applySourceChange(change: SourceChange) {
let uri = client.protocol2CodeConverter.asUri(toReveal.textDocument.uri) let uri = client.protocol2CodeConverter.asUri(toReveal.textDocument.uri)
let position = client.protocol2CodeConverter.asPosition(toReveal.position) let position = client.protocol2CodeConverter.asPosition(toReveal.position)
let editor = vscode.window.activeTextEditor; let editor = vscode.window.activeTextEditor;
if (!editor || editor.document.uri != uri) return if (!editor || editor.document.uri.toString() != uri.toString()) return
if (!editor.selection.isEmpty) return if (!editor.selection.isEmpty) return
editor!.selection = new vscode.Selection(position, position) editor!.selection = new vscode.Selection(position, position)
} }

View file

@ -1,7 +1,7 @@
use relative_path::RelativePathBuf; use relative_path::{RelativePath, RelativePathBuf};
use libsyntax2::{File, TextRange, TextUnit, AtomEdit}; use libsyntax2::{File, TextRange, TextUnit, AtomEdit};
use libeditor; use libeditor;
use {imp::AnalysisImpl, FileId, Query}; use {imp::{AnalysisImpl, AnalysisHostImpl}, Query};
pub use libeditor::{ pub use libeditor::{
LocalEdit, StructureNode, LineIndex, FileSymbol, LocalEdit, StructureNode, LineIndex, FileSymbol,
@ -109,3 +109,34 @@ impl Analysis {
self.imp.diagnostics(file_id) self.imp.diagnostics(file_id)
} }
} }
pub trait FileResolver: Send + Sync + 'static {
fn file_stem(&self, id: FileId) -> String;
fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileId(pub u32);
#[derive(Debug)]
pub struct AnalysisHost {
pub(crate) imp: AnalysisHostImpl
}
impl AnalysisHost {
pub fn new() -> AnalysisHost {
AnalysisHost { imp: AnalysisHostImpl::new() }
}
pub fn analysis(&self, file_resolver: impl FileResolver) -> Analysis {
Analysis { imp: self.imp.analysis(file_resolver) }
}
pub fn change_file(&mut self, file_id: FileId, text: Option<String>) {
self.change_files(::std::iter::once((file_id, text)));
}
pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) {
self.imp.change_files(changes)
}
}

View file

@ -22,9 +22,65 @@ use {
FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit,
module_map::Problem, module_map::Problem,
symbol_index::FileSymbols, symbol_index::FileSymbols,
module_map::ModuleMap, module_map::{ModuleMap, ChangeKind},
}; };
#[derive(Debug)]
pub(crate) struct AnalysisHostImpl {
data: Arc<WorldData>
}
impl AnalysisHostImpl {
pub fn new() -> AnalysisHostImpl {
AnalysisHostImpl {
data: Arc::new(WorldData::default()),
}
}
pub fn analysis(
&self,
file_resolver: impl FileResolver,
) -> AnalysisImpl {
AnalysisImpl {
needs_reindex: AtomicBool::new(false),
file_resolver: Arc::new(file_resolver),
data: self.data.clone()
}
}
pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) {
let data = self.data_mut();
for (file_id, text) in changes {
let change_kind = if data.file_map.remove(&file_id).is_some() {
if text.is_some() {
ChangeKind::Update
} else {
ChangeKind::Delete
}
} else {
ChangeKind::Insert
};
data.module_map.update_file(file_id, change_kind);
data.file_map.remove(&file_id);
if let Some(text) = text {
let file_data = FileData::new(text);
data.file_map.insert(file_id, Arc::new(file_data));
} else {
data.file_map.remove(&file_id);
}
}
}
fn data_mut(&mut self) -> &mut WorldData {
if Arc::get_mut(&mut self.data).is_none() {
self.data = Arc::new(WorldData {
file_map: self.data.file_map.clone(),
module_map: self.data.module_map.clone(),
});
}
Arc::get_mut(&mut self.data).unwrap()
}
}
pub(crate) struct AnalysisImpl { pub(crate) struct AnalysisImpl {
pub(crate) needs_reindex: AtomicBool, pub(crate) needs_reindex: AtomicBool,

View file

@ -14,92 +14,10 @@ mod module_map;
mod api; mod api;
mod imp; mod imp;
use std::{
sync::{
Arc,
atomic::{AtomicBool},
},
};
use relative_path::RelativePath;
use self::{
module_map::{ChangeKind},
imp::{WorldData, FileData},
};
pub use self::symbol_index::Query; pub use self::symbol_index::Query;
pub use self::api::{ pub use self::api::{
Analysis, SourceChange, SourceFileEdit, FileSystemEdit, Position, Diagnostic, Runnable, RunnableKind AnalysisHost, Analysis, SourceChange, SourceFileEdit, FileSystemEdit, Position, Diagnostic, Runnable, RunnableKind,
FileId, FileResolver,
}; };
pub type Result<T> = ::std::result::Result<T, ::failure::Error>; pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
pub trait FileResolver: Send + Sync + 'static {
fn file_stem(&self, id: FileId) -> String;
fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>;
}
#[derive(Debug)]
pub struct WorldState {
data: Arc<WorldData>
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileId(pub u32);
impl WorldState {
pub fn new() -> WorldState {
WorldState {
data: Arc::new(WorldData::default()),
}
}
pub fn analysis(
&self,
file_resolver: impl FileResolver,
) -> Analysis {
let imp = imp::AnalysisImpl {
needs_reindex: AtomicBool::new(false),
file_resolver: Arc::new(file_resolver),
data: self.data.clone()
};
Analysis { imp }
}
pub fn change_file(&mut self, file_id: FileId, text: Option<String>) {
self.change_files(::std::iter::once((file_id, text)));
}
pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) {
let data = self.data_mut();
for (file_id, text) in changes {
let change_kind = if data.file_map.remove(&file_id).is_some() {
if text.is_some() {
ChangeKind::Update
} else {
ChangeKind::Delete
}
} else {
ChangeKind::Insert
};
data.module_map.update_file(file_id, change_kind);
data.file_map.remove(&file_id);
if let Some(text) = text {
let file_data = FileData::new(text);
data.file_map.insert(file_id, Arc::new(file_data));
} else {
data.file_map.remove(&file_id);
}
}
}
fn data_mut(&mut self) -> &mut WorldData {
if Arc::get_mut(&mut self.data).is_none() {
self.data = Arc::new(WorldData {
file_map: self.data.file_map.clone(),
module_map: self.data.module_map.clone(),
});
}
Arc::get_mut(&mut self.data).unwrap()
}
}

View file

@ -5,7 +5,7 @@ use std::{
}; };
use languageserver_types::Url; use languageserver_types::Url;
use libanalysis::{FileId, WorldState, Analysis}; use libanalysis::{FileId, AnalysisHost, Analysis};
use { use {
Result, Result,
@ -15,7 +15,7 @@ use {
#[derive(Debug)] #[derive(Debug)]
pub struct ServerWorldState { pub struct ServerWorldState {
pub analysis: WorldState, pub analysis_host: AnalysisHost,
pub path_map: PathMap, pub path_map: PathMap,
pub mem_map: HashMap<FileId, Option<String>>, pub mem_map: HashMap<FileId, Option<String>>,
} }
@ -29,7 +29,7 @@ pub struct ServerWorld {
impl ServerWorldState { impl ServerWorldState {
pub fn new() -> ServerWorldState { pub fn new() -> ServerWorldState {
ServerWorldState { ServerWorldState {
analysis: WorldState::new(), analysis_host: AnalysisHost::new(),
path_map: PathMap::new(), path_map: PathMap::new(),
mem_map: HashMap::new(), mem_map: HashMap::new(),
} }
@ -58,20 +58,20 @@ impl ServerWorldState {
} }
}); });
self.analysis.change_files(changes); self.analysis_host.change_files(changes);
} }
pub fn add_mem_file(&mut self, path: PathBuf, text: String) { pub fn add_mem_file(&mut self, path: PathBuf, text: String) {
let file_id = self.path_map.get_or_insert(path); let file_id = self.path_map.get_or_insert(path);
self.mem_map.insert(file_id, None); self.mem_map.insert(file_id, None);
self.analysis.change_file(file_id, Some(text)); self.analysis_host.change_file(file_id, Some(text));
} }
pub fn change_mem_file(&mut self, path: &Path, text: String) -> Result<()> { pub fn change_mem_file(&mut self, path: &Path, text: String) -> Result<()> {
let file_id = self.path_map.get_id(path).ok_or_else(|| { let file_id = self.path_map.get_id(path).ok_or_else(|| {
format_err!("change to unknown file: {}", path.display()) format_err!("change to unknown file: {}", path.display())
})?; })?;
self.analysis.change_file(file_id, Some(text)); self.analysis_host.change_file(file_id, Some(text));
Ok(()) Ok(())
} }
@ -85,13 +85,13 @@ impl ServerWorldState {
}; };
// Do this via file watcher ideally. // Do this via file watcher ideally.
let text = fs::read_to_string(path).ok(); let text = fs::read_to_string(path).ok();
self.analysis.change_file(file_id, text); self.analysis_host.change_file(file_id, text);
Ok(()) Ok(())
} }
pub fn snapshot(&self) -> ServerWorld { pub fn snapshot(&self) -> ServerWorld {
ServerWorld { ServerWorld {
analysis: self.analysis.analysis(self.path_map.clone()), analysis: self.analysis_host.analysis(self.path_map.clone()),
path_map: self.path_map.clone() path_map: self.path_map.clone()
} }
} }