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

View File

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

View File

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

View File

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