This commit is contained in:
Max Brunsfeld 2021-12-23 23:10:28 -08:00
parent d5a17053df
commit 4f774e2bde
4 changed files with 105 additions and 104 deletions

View file

@ -637,7 +637,7 @@ mod tests {
worktree.update(&mut cx, |worktree, cx| { worktree.update(&mut cx, |worktree, cx| {
worktree worktree
.update_diagnostic_entries( .update_point_utf16_diagnostics(
"lsp".into(), "lsp".into(),
Arc::from("/test/main.rs".as_ref()), Arc::from("/test/main.rs".as_ref()),
None, None,
@ -764,7 +764,7 @@ mod tests {
worktree.update(&mut cx, |worktree, cx| { worktree.update(&mut cx, |worktree, cx| {
worktree worktree
.update_diagnostic_entries( .update_point_utf16_diagnostics(
"lsp".into(), "lsp".into(),
Arc::from("/test/a.rs".as_ref()), Arc::from("/test/a.rs".as_ref()),
None, None,

View file

@ -66,12 +66,12 @@ pub struct BracketPair {
#[async_trait] #[async_trait]
pub trait DiagnosticSource: 'static + Send + Sync { pub trait DiagnosticSource: 'static + Send + Sync {
fn name(&self) -> &'static str; fn name(&self) -> Arc<str>;
async fn diagnose( async fn diagnose(
&self, &self,
path: Arc<Path>, path: Arc<Path>,
) -> Result<Vec<(PathBuf, Vec<DiagnosticEntry<Point>>)>>; ) -> Result<Vec<(PathBuf, Vec<DiagnosticEntry<usize>>)>>;
} }
pub struct Language { pub struct Language {

View file

@ -511,17 +511,22 @@ impl Project {
let worktree_path = worktree.abs_path().clone(); let worktree_path = worktree.abs_path().clone();
let worktree_handle = worktree_handle.downgrade(); let worktree_handle = worktree_handle.downgrade();
cx.spawn_weak(|_, mut cx| async move { cx.spawn_weak(|_, mut cx| async move {
if let Some(diagnostics) = let diagnostics =
diagnostic_source.diagnose(worktree_path).await.log_err() diagnostic_source.diagnose(worktree_path).await.log_err()?;
{ let worktree_handle = worktree_handle.upgrade(&cx)?;
if let Some(worktree_handle) = worktree_handle.upgrade(&cx) { worktree_handle.update(&mut cx, |worktree, cx| {
worktree_handle.update(&mut cx, |worktree, cx| { for (path, diagnostics) in diagnostics {
for (path, diagnostics) in diagnostics { worktree
todo!() .update_offset_diagnostics(
} diagnostic_source.name(),
}) path.into(),
diagnostics,
cx,
)
.log_err()?;
} }
} Some(())
})
}) })
.detach(); .detach();
} }

View file

@ -743,7 +743,7 @@ impl Worktree {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.update_diagnostic_entries( self.update_point_utf16_diagnostics(
provider_name, provider_name,
worktree_path, worktree_path,
params.version, params.version,
@ -752,87 +752,54 @@ impl Worktree {
) )
} }
pub fn update_diagnostics( pub fn update_offset_diagnostics(
&mut self, &mut self,
provider_name: Arc<str>, provider_name: Arc<str>,
mut params: lsp::PublishDiagnosticsParams, path: Arc<Path>,
disk_based_sources: &HashSet<String>, diagnostics: Vec<DiagnosticEntry<usize>>,
cx: &mut ModelContext<Worktree>, cx: &mut ModelContext<Worktree>,
) -> Result<()> { ) -> Result<()> {
let this = self.as_local_mut().ok_or_else(|| anyhow!("not local"))?; let this = self.as_local_mut().unwrap();
let abs_path = params for buffer in this.open_buffers.values() {
.uri if let Some(buffer) = buffer.upgrade(cx) {
.to_file_path() if buffer
.map_err(|_| anyhow!("URI is not a file"))?; .read(cx)
let worktree_path = Arc::from( .file()
abs_path .map_or(false, |file| *file.path() == path)
.strip_prefix(&this.abs_path) {
.context("path is not within worktree")?, let (remote_id, operation) = buffer.update(cx, |buffer, cx| {
); (
buffer.remote_id(),
let mut group_ids_by_diagnostic_range = HashMap::default(); buffer.update_diagnostics(
let mut diagnostics_by_group_id = HashMap::default(); provider_name,
let mut next_group_id = 0; None,
for diagnostic in &mut params.diagnostics { diagnostics
let source = diagnostic.source.as_ref(); .iter()
let code = diagnostic.code.as_ref(); .map(|entry| DiagnosticEntry {
let group_id = diagnostic_ranges(&diagnostic, &abs_path) range: buffer.offset_to_point_utf16(entry.range.start)
.find_map(|range| group_ids_by_diagnostic_range.get(&(source, code, range))) ..buffer.offset_to_point_utf16(entry.range.end),
.copied() diagnostic: entry.diagnostic.clone(),
.unwrap_or_else(|| { })
let group_id = post_inc(&mut next_group_id); .collect(),
for range in diagnostic_ranges(&diagnostic, &abs_path) { cx,
group_ids_by_diagnostic_range.insert((source, code, range), group_id); ),
} )
group_id });
}); self.send_buffer_update(remote_id, operation?, cx);
break;
diagnostics_by_group_id }
.entry(group_id) }
.or_insert(Vec::new())
.push(DiagnosticEntry {
range: diagnostic.range.start.to_point_utf16()
..diagnostic.range.end.to_point_utf16(),
diagnostic: Diagnostic {
code: diagnostic.code.clone().map(|code| match code {
lsp::NumberOrString::Number(code) => code.to_string(),
lsp::NumberOrString::String(code) => code,
}),
severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
message: mem::take(&mut diagnostic.message),
group_id,
is_primary: false,
is_valid: true,
is_disk_based: diagnostic
.source
.as_ref()
.map_or(false, |source| disk_based_sources.contains(source)),
},
});
} }
let diagnostics = diagnostics_by_group_id let this = self.as_local_mut().unwrap();
.into_values() this.diagnostic_summaries
.flat_map(|mut diagnostics| { .insert(path.clone(), DiagnosticSummary::new(&diagnostics));
let primary = diagnostics this.offset_diagnostics.insert(path.clone(), diagnostics);
.iter_mut() cx.emit(Event::DiagnosticsUpdated(path.clone()));
.min_by_key(|entry| entry.diagnostic.severity) Ok(())
.unwrap();
primary.diagnostic.is_primary = true;
diagnostics
})
.collect::<Vec<_>>();
self.update_diagnostic_entries(
provider_name,
worktree_path,
params.version,
diagnostics,
cx,
)
} }
pub fn update_diagnostic_entries( pub fn update_point_utf16_diagnostics(
&mut self, &mut self,
provider_name: Arc<str>, provider_name: Arc<str>,
path: Arc<Path>, path: Arc<Path>,
@ -868,11 +835,26 @@ impl Worktree {
let this = self.as_local_mut().unwrap(); let this = self.as_local_mut().unwrap();
this.diagnostic_summaries this.diagnostic_summaries
.insert(path.clone(), DiagnosticSummary::new(&diagnostics)); .insert(path.clone(), DiagnosticSummary::new(&diagnostics));
this.diagnostics.insert(path.clone(), diagnostics); this.point_utf16_diagnostics
.insert(path.clone(), diagnostics);
cx.emit(Event::DiagnosticsUpdated(path.clone())); cx.emit(Event::DiagnosticsUpdated(path.clone()));
Ok(()) Ok(())
} }
fn convert_diagnostics(
diagnostics: &[DiagnosticEntry<usize>],
buffer: &Buffer,
) -> Vec<DiagnosticEntry<PointUtf16>> {
diagnostics
.iter()
.map(|entry| DiagnosticEntry {
range: buffer.offset_to_point_utf16(entry.range.start)
..buffer.offset_to_point_utf16(entry.range.end),
diagnostic: entry.diagnostic.clone(),
})
.collect()
}
fn send_buffer_update( fn send_buffer_update(
&mut self, &mut self,
buffer_id: u64, buffer_id: u64,
@ -943,7 +925,8 @@ pub struct LocalWorktree {
loading_buffers: LoadingBuffers, loading_buffers: LoadingBuffers,
open_buffers: HashMap<usize, WeakModelHandle<Buffer>>, open_buffers: HashMap<usize, WeakModelHandle<Buffer>>,
shared_buffers: HashMap<PeerId, HashMap<u64, ModelHandle<Buffer>>>, shared_buffers: HashMap<PeerId, HashMap<u64, ModelHandle<Buffer>>>,
diagnostics: HashMap<Arc<Path>, Vec<DiagnosticEntry<PointUtf16>>>, point_utf16_diagnostics: HashMap<Arc<Path>, Vec<DiagnosticEntry<PointUtf16>>>,
offset_diagnostics: HashMap<Arc<Path>, Vec<DiagnosticEntry<usize>>>,
diagnostic_summaries: BTreeMap<Arc<Path>, DiagnosticSummary>, diagnostic_summaries: BTreeMap<Arc<Path>, DiagnosticSummary>,
queued_operations: Vec<(u64, Operation)>, queued_operations: Vec<(u64, Operation)>,
language_registry: Arc<LanguageRegistry>, language_registry: Arc<LanguageRegistry>,
@ -1051,7 +1034,8 @@ impl LocalWorktree {
loading_buffers: Default::default(), loading_buffers: Default::default(),
open_buffers: Default::default(), open_buffers: Default::default(),
shared_buffers: Default::default(), shared_buffers: Default::default(),
diagnostics: Default::default(), point_utf16_diagnostics: Default::default(),
offset_diagnostics: Default::default(),
diagnostic_summaries: Default::default(), diagnostic_summaries: Default::default(),
queued_operations: Default::default(), queued_operations: Default::default(),
language_registry: languages, language_registry: languages,
@ -1200,27 +1184,39 @@ impl LocalWorktree {
.update(&mut cx, |t, cx| t.as_local().unwrap().load(&path, cx)) .update(&mut cx, |t, cx| t.as_local().unwrap().load(&path, cx))
.await?; .await?;
let (diagnostics, language, language_server) = this.update(&mut cx, |this, cx| { let (point_utf16_diagnostics, offset_diagnostics, language, language_server) = this
let this = this.as_local_mut().unwrap(); .update(&mut cx, |this, cx| {
let diagnostics = this.diagnostics.remove(&path); let this = this.as_local_mut().unwrap();
let language = this let point_utf16_diagnostics = this.point_utf16_diagnostics.remove(&path);
.language_registry let offset_diagnostics = this.offset_diagnostics.remove(&path);
.select_language(file.full_path()) let language = this
.cloned(); .language_registry
let server = language .select_language(file.full_path())
.as_ref() .cloned();
.and_then(|language| this.register_language(language, cx)); let server = language
(diagnostics, language, server) .as_ref()
}); .and_then(|language| this.register_language(language, cx));
(
point_utf16_diagnostics,
offset_diagnostics,
language,
server,
)
});
let buffer = cx.add_model(|cx| { let buffer = cx.add_model(|cx| {
let mut buffer = Buffer::from_file(0, contents, Box::new(file), cx); let mut buffer = Buffer::from_file(0, contents, Box::new(file), cx);
buffer.set_language(language, language_server, cx); buffer.set_language(language, language_server, cx);
if let Some(diagnostics) = diagnostics { if let Some(diagnostics) = point_utf16_diagnostics {
buffer buffer
.update_diagnostics(todo!(), None, diagnostics, cx) .update_diagnostics(todo!(), None, diagnostics, cx)
.unwrap(); .unwrap();
} }
if let Some(diagnostics) = offset_diagnostics {
buffer
.update_offset_diagnostics(todo!(), None, diagnostics, cx)
.unwrap();
}
buffer buffer
}); });