Compare commits
11 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
55ba01dcbb | ||
![]() |
9ee9501550 | ||
![]() |
fcd5601a1f | ||
![]() |
60326b2d62 | ||
![]() |
2027b20af4 | ||
![]() |
a70c760c39 | ||
![]() |
fe24fbb4b4 | ||
![]() |
740d68d485 | ||
![]() |
90be090d35 | ||
![]() |
557b7c71dc | ||
![]() |
8937d0dada |
34 changed files with 512 additions and 127 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -9951,7 +9951,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "tree-sitter"
|
||||
version = "0.20.10"
|
||||
source = "git+https://github.com/tree-sitter/tree-sitter?rev=3b0159d25559b603af566ade3c83d930bf466db1#3b0159d25559b603af566ade3c83d930bf466db1"
|
||||
source = "git+https://github.com/tree-sitter/tree-sitter?rev=b5f461a69bf3df7298b1903574d506179e6390b0#b5f461a69bf3df7298b1903574d506179e6390b0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"regex",
|
||||
|
@ -11554,7 +11554,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zed"
|
||||
version = "0.115.0"
|
||||
version = "0.115.3"
|
||||
dependencies = [
|
||||
"activity_indicator",
|
||||
"ai",
|
||||
|
|
|
@ -200,7 +200,7 @@ tree-sitter-vue = {git = "https://github.com/zed-industries/tree-sitter-vue", re
|
|||
tree-sitter-uiua = {git = "https://github.com/shnarazk/tree-sitter-uiua", rev = "9260f11be5900beda4ee6d1a24ab8ddfaf5a19b2"}
|
||||
|
||||
[patch.crates-io]
|
||||
tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "3b0159d25559b603af566ade3c83d930bf466db1" }
|
||||
tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "b5f461a69bf3df7298b1903574d506179e6390b0" }
|
||||
async-task = { git = "https://github.com/zed-industries/async-task", rev = "341b57d6de98cdfd7b418567b8de2022ca993a6e" }
|
||||
|
||||
# TODO - Remove when a version is released with this PR: https://github.com/servo/core-foundation-rs/pull/457
|
||||
|
|
|
@ -530,12 +530,17 @@
|
|||
"alt-cmd-shift-c": "project_panel::CopyRelativePath",
|
||||
"f2": "project_panel::Rename",
|
||||
"enter": "project_panel::Rename",
|
||||
"space": "project_panel::Open",
|
||||
"backspace": "project_panel::Delete",
|
||||
"alt-cmd-r": "project_panel::RevealInFinder",
|
||||
"alt-shift-f": "project_panel::NewSearchInDirectory"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "ProjectPanel && not_editing",
|
||||
"bindings": {
|
||||
"space": "project_panel::Open"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "CollabPanel && not_editing",
|
||||
"bindings": {
|
||||
|
|
|
@ -116,12 +116,13 @@ struct CreateUserResponse {
|
|||
#[derive(Debug, Deserialize)]
|
||||
struct Panic {
|
||||
version: String,
|
||||
release_channel: String,
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[instrument(skip(panic))]
|
||||
async fn trace_panic(panic: Json<Panic>) -> Result<()> {
|
||||
tracing::error!(version = %panic.version, text = %panic.text, "panic report");
|
||||
tracing::error!(version = %panic.version, release_channel = %panic.release_channel, text = %panic.text, "panic report");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -3941,7 +3941,7 @@ async fn test_collaborating_with_diagnostics(
|
|||
// Ensure client B observes the new diagnostics.
|
||||
project_b.read_with(cx_b, |project, cx| {
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(cx).collect::<Vec<_>>(),
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>(),
|
||||
&[(
|
||||
ProjectPath {
|
||||
worktree_id,
|
||||
|
@ -3961,14 +3961,14 @@ async fn test_collaborating_with_diagnostics(
|
|||
let project_c = client_c.build_remote_project(project_id, cx_c).await;
|
||||
let project_c_diagnostic_summaries =
|
||||
Rc::new(RefCell::new(project_c.read_with(cx_c, |project, cx| {
|
||||
project.diagnostic_summaries(cx).collect::<Vec<_>>()
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>()
|
||||
})));
|
||||
project_c.update(cx_c, |_, cx| {
|
||||
let summaries = project_c_diagnostic_summaries.clone();
|
||||
cx.subscribe(&project_c, {
|
||||
move |p, _, event, cx| {
|
||||
if let project::Event::DiskBasedDiagnosticsFinished { .. } = event {
|
||||
*summaries.borrow_mut() = p.diagnostic_summaries(cx).collect();
|
||||
*summaries.borrow_mut() = p.diagnostic_summaries(false, cx).collect();
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -4018,7 +4018,7 @@ async fn test_collaborating_with_diagnostics(
|
|||
deterministic.run_until_parked();
|
||||
project_b.read_with(cx_b, |project, cx| {
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(cx).collect::<Vec<_>>(),
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>(),
|
||||
[(
|
||||
ProjectPath {
|
||||
worktree_id,
|
||||
|
@ -4034,7 +4034,7 @@ async fn test_collaborating_with_diagnostics(
|
|||
});
|
||||
project_c.read_with(cx_c, |project, cx| {
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(cx).collect::<Vec<_>>(),
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>(),
|
||||
[(
|
||||
ProjectPath {
|
||||
worktree_id,
|
||||
|
@ -4097,13 +4097,22 @@ async fn test_collaborating_with_diagnostics(
|
|||
);
|
||||
deterministic.run_until_parked();
|
||||
project_a.read_with(cx_a, |project, cx| {
|
||||
assert_eq!(project.diagnostic_summaries(cx).collect::<Vec<_>>(), [])
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>(),
|
||||
[]
|
||||
)
|
||||
});
|
||||
project_b.read_with(cx_b, |project, cx| {
|
||||
assert_eq!(project.diagnostic_summaries(cx).collect::<Vec<_>>(), [])
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>(),
|
||||
[]
|
||||
)
|
||||
});
|
||||
project_c.read_with(cx_c, |project, cx| {
|
||||
assert_eq!(project.diagnostic_summaries(cx).collect::<Vec<_>>(), [])
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>(),
|
||||
[]
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -3688,7 +3688,7 @@ async fn test_collaborating_with_diagnostics(
|
|||
|
||||
project_b.read_with(cx_b, |project, cx| {
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(cx).collect::<Vec<_>>(),
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>(),
|
||||
&[(
|
||||
ProjectPath {
|
||||
worktree_id,
|
||||
|
@ -3708,14 +3708,14 @@ async fn test_collaborating_with_diagnostics(
|
|||
let project_c = client_c.build_remote_project(project_id, cx_c).await;
|
||||
let project_c_diagnostic_summaries =
|
||||
Rc::new(RefCell::new(project_c.read_with(cx_c, |project, cx| {
|
||||
project.diagnostic_summaries(cx).collect::<Vec<_>>()
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>()
|
||||
})));
|
||||
project_c.update(cx_c, |_, cx| {
|
||||
let summaries = project_c_diagnostic_summaries.clone();
|
||||
cx.subscribe(&project_c, {
|
||||
move |p, _, event, cx| {
|
||||
if let project::Event::DiskBasedDiagnosticsFinished { .. } = event {
|
||||
*summaries.borrow_mut() = p.diagnostic_summaries(cx).collect();
|
||||
*summaries.borrow_mut() = p.diagnostic_summaries(false, cx).collect();
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -3766,7 +3766,7 @@ async fn test_collaborating_with_diagnostics(
|
|||
|
||||
project_b.read_with(cx_b, |project, cx| {
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(cx).collect::<Vec<_>>(),
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>(),
|
||||
[(
|
||||
ProjectPath {
|
||||
worktree_id,
|
||||
|
@ -3783,7 +3783,7 @@ async fn test_collaborating_with_diagnostics(
|
|||
|
||||
project_c.read_with(cx_c, |project, cx| {
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(cx).collect::<Vec<_>>(),
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>(),
|
||||
[(
|
||||
ProjectPath {
|
||||
worktree_id,
|
||||
|
@ -3844,15 +3844,24 @@ async fn test_collaborating_with_diagnostics(
|
|||
executor.run_until_parked();
|
||||
|
||||
project_a.read_with(cx_a, |project, cx| {
|
||||
assert_eq!(project.diagnostic_summaries(cx).collect::<Vec<_>>(), [])
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>(),
|
||||
[]
|
||||
)
|
||||
});
|
||||
|
||||
project_b.read_with(cx_b, |project, cx| {
|
||||
assert_eq!(project.diagnostic_summaries(cx).collect::<Vec<_>>(), [])
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>(),
|
||||
[]
|
||||
)
|
||||
});
|
||||
|
||||
project_c.read_with(cx_c, |project, cx| {
|
||||
assert_eq!(project.diagnostic_summaries(cx).collect::<Vec<_>>(), [])
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(false, cx).collect::<Vec<_>>(),
|
||||
[]
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ impl View for ProjectDiagnosticsEditor {
|
|||
json!({
|
||||
"project": json!({
|
||||
"language_servers": project.language_server_statuses().collect::<Vec<_>>(),
|
||||
"summary": project.diagnostic_summary(cx),
|
||||
"summary": project.diagnostic_summary(false, cx),
|
||||
}),
|
||||
"summary": self.summary,
|
||||
"paths_to_update": self.paths_to_update.iter().map(|(server_id, paths)|
|
||||
|
@ -195,7 +195,7 @@ impl ProjectDiagnosticsEditor {
|
|||
});
|
||||
|
||||
let project = project_handle.read(cx);
|
||||
let summary = project.diagnostic_summary(cx);
|
||||
let summary = project.diagnostic_summary(false, cx);
|
||||
let mut this = Self {
|
||||
project: project_handle,
|
||||
summary,
|
||||
|
@ -241,7 +241,7 @@ impl ProjectDiagnosticsEditor {
|
|||
let mut new_summaries: HashMap<LanguageServerId, HashSet<ProjectPath>> = self
|
||||
.project
|
||||
.read(cx)
|
||||
.diagnostic_summaries(cx)
|
||||
.diagnostic_summaries(false, cx)
|
||||
.fold(HashMap::default(), |mut summaries, (path, server_id, _)| {
|
||||
summaries.entry(server_id).or_default().insert(path);
|
||||
summaries
|
||||
|
@ -320,7 +320,7 @@ impl ProjectDiagnosticsEditor {
|
|||
.context("rechecking diagnostics for paths")?;
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.summary = this.project.read(cx).diagnostic_summary(cx);
|
||||
this.summary = this.project.read(cx).diagnostic_summary(false, cx);
|
||||
cx.emit(Event::TitleChanged);
|
||||
})?;
|
||||
anyhow::Ok(())
|
||||
|
|
|
@ -34,19 +34,19 @@ impl DiagnosticIndicator {
|
|||
}
|
||||
project::Event::DiskBasedDiagnosticsFinished { language_server_id }
|
||||
| project::Event::LanguageServerRemoved(language_server_id) => {
|
||||
this.summary = project.read(cx).diagnostic_summary(cx);
|
||||
this.summary = project.read(cx).diagnostic_summary(false, cx);
|
||||
this.in_progress_checks.remove(language_server_id);
|
||||
cx.notify();
|
||||
}
|
||||
project::Event::DiagnosticsUpdated { .. } => {
|
||||
this.summary = project.read(cx).diagnostic_summary(cx);
|
||||
this.summary = project.read(cx).diagnostic_summary(false, cx);
|
||||
cx.notify();
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
.detach();
|
||||
Self {
|
||||
summary: project.read(cx).diagnostic_summary(cx),
|
||||
summary: project.read(cx).diagnostic_summary(false, cx),
|
||||
in_progress_checks: project
|
||||
.read(cx)
|
||||
.language_servers_running_disk_based_diagnostics()
|
||||
|
|
|
@ -165,7 +165,7 @@ impl ProjectDiagnosticsEditor {
|
|||
});
|
||||
|
||||
let project = project_handle.read(cx);
|
||||
let summary = project.diagnostic_summary(cx);
|
||||
let summary = project.diagnostic_summary(false, cx);
|
||||
let mut this = Self {
|
||||
project: project_handle,
|
||||
summary,
|
||||
|
@ -252,7 +252,7 @@ impl ProjectDiagnosticsEditor {
|
|||
let mut new_summaries: HashMap<LanguageServerId, HashSet<ProjectPath>> = self
|
||||
.project
|
||||
.read(cx)
|
||||
.diagnostic_summaries(cx)
|
||||
.diagnostic_summaries(false, cx)
|
||||
.fold(HashMap::default(), |mut summaries, (path, server_id, _)| {
|
||||
summaries.entry(server_id).or_default().insert(path);
|
||||
summaries
|
||||
|
@ -332,7 +332,7 @@ impl ProjectDiagnosticsEditor {
|
|||
.context("rechecking diagnostics for paths")?;
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.summary = this.project.read(cx).diagnostic_summary(cx);
|
||||
this.summary = this.project.read(cx).diagnostic_summary(false, cx);
|
||||
cx.emit(ItemEvent::UpdateTab);
|
||||
cx.emit(ItemEvent::UpdateBreadcrumbs);
|
||||
})?;
|
||||
|
|
|
@ -77,13 +77,13 @@ impl DiagnosticIndicator {
|
|||
|
||||
project::Event::DiskBasedDiagnosticsFinished { language_server_id }
|
||||
| project::Event::LanguageServerRemoved(language_server_id) => {
|
||||
this.summary = project.read(cx).diagnostic_summary(cx);
|
||||
this.summary = project.read(cx).diagnostic_summary(false, cx);
|
||||
this.in_progress_checks.remove(language_server_id);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
project::Event::DiagnosticsUpdated { .. } => {
|
||||
this.summary = project.read(cx).diagnostic_summary(cx);
|
||||
this.summary = project.read(cx).diagnostic_summary(false, cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ impl DiagnosticIndicator {
|
|||
.detach();
|
||||
|
||||
Self {
|
||||
summary: project.read(cx).diagnostic_summary(cx),
|
||||
summary: project.read(cx).diagnostic_summary(false, cx),
|
||||
in_progress_checks: project
|
||||
.read(cx)
|
||||
.language_servers_running_disk_based_diagnostics()
|
||||
|
|
|
@ -518,6 +518,7 @@ impl PickerDelegate for FileFinderDelegate {
|
|||
}
|
||||
|
||||
fn update_matches(&mut self, raw_query: String, cx: &mut ViewContext<FileFinder>) -> Task<()> {
|
||||
let raw_query = raw_query.trim();
|
||||
if raw_query.is_empty() {
|
||||
let project = self.project.read(cx);
|
||||
self.latest_search_id = post_inc(&mut self.search_count);
|
||||
|
@ -539,7 +540,6 @@ impl PickerDelegate for FileFinderDelegate {
|
|||
cx.notify();
|
||||
Task::ready(())
|
||||
} else {
|
||||
let raw_query = &raw_query;
|
||||
let query = PathLikeWithPosition::parse_str(raw_query, |path_like_str| {
|
||||
Ok::<_, std::convert::Infallible>(FileSearchQuery {
|
||||
raw_query: raw_query.to_owned(),
|
||||
|
@ -735,6 +735,7 @@ mod tests {
|
|||
cx.dispatch_action(window.into(), Toggle);
|
||||
|
||||
let finder = cx.read(|cx| workspace.read(cx).modal::<FileFinder>().unwrap());
|
||||
|
||||
finder
|
||||
.update(cx, |finder, cx| {
|
||||
finder.delegate_mut().update_matches("bna".to_string(), cx)
|
||||
|
@ -743,7 +744,6 @@ mod tests {
|
|||
finder.read_with(cx, |finder, _| {
|
||||
assert_eq!(finder.delegate().matches.len(), 2);
|
||||
});
|
||||
|
||||
let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
|
||||
cx.dispatch_action(window.into(), SelectNext);
|
||||
cx.dispatch_action(window.into(), Confirm);
|
||||
|
@ -762,6 +762,49 @@ mod tests {
|
|||
"bandana"
|
||||
);
|
||||
});
|
||||
|
||||
for bandana_query in [
|
||||
"bandana",
|
||||
" bandana",
|
||||
"bandana ",
|
||||
" bandana ",
|
||||
" ndan ",
|
||||
" band ",
|
||||
] {
|
||||
finder
|
||||
.update(cx, |finder, cx| {
|
||||
finder
|
||||
.delegate_mut()
|
||||
.update_matches(bandana_query.to_string(), cx)
|
||||
})
|
||||
.await;
|
||||
finder.read_with(cx, |finder, _| {
|
||||
assert_eq!(
|
||||
finder.delegate().matches.len(),
|
||||
1,
|
||||
"Wrong number of matches for bandana query '{bandana_query}'"
|
||||
);
|
||||
});
|
||||
let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
|
||||
cx.dispatch_action(window.into(), SelectNext);
|
||||
cx.dispatch_action(window.into(), Confirm);
|
||||
active_pane
|
||||
.condition(cx, |pane, _| pane.active_item().is_some())
|
||||
.await;
|
||||
cx.read(|cx| {
|
||||
let active_item = active_pane.read(cx).active_item().unwrap();
|
||||
assert_eq!(
|
||||
active_item
|
||||
.as_any()
|
||||
.downcast_ref::<Editor>()
|
||||
.unwrap()
|
||||
.read(cx)
|
||||
.title(cx),
|
||||
"bandana",
|
||||
"Wrong match for bandana query '{bandana_query}'"
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
|
|
|
@ -552,6 +552,7 @@ impl PickerDelegate for FileFinderDelegate {
|
|||
raw_query: String,
|
||||
cx: &mut ViewContext<Picker<Self>>,
|
||||
) -> Task<()> {
|
||||
let raw_query = raw_query.trim();
|
||||
if raw_query.is_empty() {
|
||||
let project = self.project.read(cx);
|
||||
self.latest_search_id = post_inc(&mut self.search_count);
|
||||
|
@ -573,7 +574,6 @@ impl PickerDelegate for FileFinderDelegate {
|
|||
cx.notify();
|
||||
Task::ready(())
|
||||
} else {
|
||||
let raw_query = &raw_query;
|
||||
let query = PathLikeWithPosition::parse_str(raw_query, |path_like_str| {
|
||||
Ok::<_, std::convert::Infallible>(FileSearchQuery {
|
||||
raw_query: raw_query.to_owned(),
|
||||
|
@ -768,18 +768,49 @@ mod tests {
|
|||
let (picker, workspace, cx) = build_find_picker(project, cx);
|
||||
|
||||
cx.simulate_input("bna");
|
||||
|
||||
picker.update(cx, |picker, _| {
|
||||
assert_eq!(picker.delegate.matches.len(), 2);
|
||||
});
|
||||
|
||||
cx.dispatch_action(SelectNext);
|
||||
cx.dispatch_action(Confirm);
|
||||
|
||||
cx.read(|cx| {
|
||||
let active_editor = workspace.read(cx).active_item_as::<Editor>(cx).unwrap();
|
||||
assert_eq!(active_editor.read(cx).title(cx), "bandana");
|
||||
});
|
||||
|
||||
for bandana_query in [
|
||||
"bandana",
|
||||
" bandana",
|
||||
"bandana ",
|
||||
" bandana ",
|
||||
" ndan ",
|
||||
" band ",
|
||||
] {
|
||||
picker
|
||||
.update(cx, |picker, cx| {
|
||||
picker
|
||||
.delegate
|
||||
.update_matches(bandana_query.to_string(), cx)
|
||||
})
|
||||
.await;
|
||||
picker.update(cx, |picker, _| {
|
||||
assert_eq!(
|
||||
picker.delegate.matches.len(),
|
||||
1,
|
||||
"Wrong number of matches for bandana query '{bandana_query}'"
|
||||
);
|
||||
});
|
||||
cx.dispatch_action(SelectNext);
|
||||
cx.dispatch_action(Confirm);
|
||||
cx.read(|cx| {
|
||||
let active_editor = workspace.read(cx).active_item_as::<Editor>(cx).unwrap();
|
||||
assert_eq!(
|
||||
active_editor.read(cx).title(cx),
|
||||
"bandana",
|
||||
"Wrong match for bandana query '{bandana_query}'"
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
|
|
|
@ -197,8 +197,12 @@ impl CachedLspAdapter {
|
|||
self.adapter.code_action_kinds()
|
||||
}
|
||||
|
||||
pub fn workspace_configuration(&self, cx: &mut AppContext) -> BoxFuture<'static, Value> {
|
||||
self.adapter.workspace_configuration(cx)
|
||||
pub fn workspace_configuration(
|
||||
&self,
|
||||
workspace_root: &Path,
|
||||
cx: &mut AppContext,
|
||||
) -> BoxFuture<'static, Value> {
|
||||
self.adapter.workspace_configuration(workspace_root, cx)
|
||||
}
|
||||
|
||||
pub fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
|
||||
|
@ -312,7 +316,7 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||
None
|
||||
}
|
||||
|
||||
fn workspace_configuration(&self, _: &mut AppContext) -> BoxFuture<'static, Value> {
|
||||
fn workspace_configuration(&self, _: &Path, _: &mut AppContext) -> BoxFuture<'static, Value> {
|
||||
futures::future::ready(serde_json::json!({})).boxed()
|
||||
}
|
||||
|
||||
|
|
|
@ -200,8 +200,12 @@ impl CachedLspAdapter {
|
|||
self.adapter.code_action_kinds()
|
||||
}
|
||||
|
||||
pub fn workspace_configuration(&self, cx: &mut AppContext) -> BoxFuture<'static, Value> {
|
||||
self.adapter.workspace_configuration(cx)
|
||||
pub fn workspace_configuration(
|
||||
&self,
|
||||
workspace_root: &Path,
|
||||
cx: &mut AppContext,
|
||||
) -> BoxFuture<'static, Value> {
|
||||
self.adapter.workspace_configuration(workspace_root, cx)
|
||||
}
|
||||
|
||||
pub fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
|
||||
|
@ -315,7 +319,7 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||
None
|
||||
}
|
||||
|
||||
fn workspace_configuration(&self, _: &mut AppContext) -> BoxFuture<'static, Value> {
|
||||
fn workspace_configuration(&self, _: &Path, _: &mut AppContext) -> BoxFuture<'static, Value> {
|
||||
futures::future::ready(serde_json::json!({})).boxed()
|
||||
}
|
||||
|
||||
|
|
|
@ -429,8 +429,8 @@ impl LanguageServer {
|
|||
let root_uri = Url::from_file_path(&self.root_path).unwrap();
|
||||
#[allow(deprecated)]
|
||||
let params = InitializeParams {
|
||||
process_id: Default::default(),
|
||||
root_path: Default::default(),
|
||||
process_id: None,
|
||||
root_path: None,
|
||||
root_uri: Some(root_uri.clone()),
|
||||
initialization_options: options,
|
||||
capabilities: ClientCapabilities {
|
||||
|
@ -451,12 +451,15 @@ impl LanguageServer {
|
|||
inlay_hint: Some(InlayHintWorkspaceClientCapabilities {
|
||||
refresh_support: Some(true),
|
||||
}),
|
||||
diagnostic: Some(DiagnosticWorkspaceClientCapabilities {
|
||||
refresh_support: None,
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
text_document: Some(TextDocumentClientCapabilities {
|
||||
definition: Some(GotoCapability {
|
||||
link_support: Some(true),
|
||||
..Default::default()
|
||||
dynamic_registration: None,
|
||||
}),
|
||||
code_action: Some(CodeActionClientCapabilities {
|
||||
code_action_literal_support: Some(CodeActionLiteralSupport {
|
||||
|
@ -501,7 +504,7 @@ impl LanguageServer {
|
|||
}),
|
||||
hover: Some(HoverClientCapabilities {
|
||||
content_format: Some(vec![MarkupKind::Markdown]),
|
||||
..Default::default()
|
||||
dynamic_registration: None,
|
||||
}),
|
||||
inlay_hint: Some(InlayHintClientCapabilities {
|
||||
resolve_support: Some(InlayHintResolveClientCapabilities {
|
||||
|
@ -515,6 +518,20 @@ impl LanguageServer {
|
|||
}),
|
||||
dynamic_registration: Some(false),
|
||||
}),
|
||||
publish_diagnostics: Some(PublishDiagnosticsClientCapabilities {
|
||||
related_information: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
formatting: Some(DynamicRegistrationClientCapabilities {
|
||||
dynamic_registration: None,
|
||||
}),
|
||||
on_type_formatting: Some(DynamicRegistrationClientCapabilities {
|
||||
dynamic_registration: None,
|
||||
}),
|
||||
diagnostic: Some(DiagnosticClientCapabilities {
|
||||
related_document_support: Some(true),
|
||||
dynamic_registration: None,
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
experimental: Some(json!({
|
||||
|
@ -524,15 +541,15 @@ impl LanguageServer {
|
|||
work_done_progress: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
general: None,
|
||||
},
|
||||
trace: Default::default(),
|
||||
trace: None,
|
||||
workspace_folders: Some(vec![WorkspaceFolder {
|
||||
uri: root_uri,
|
||||
name: Default::default(),
|
||||
}]),
|
||||
client_info: Default::default(),
|
||||
locale: Default::default(),
|
||||
client_info: None,
|
||||
locale: None,
|
||||
};
|
||||
|
||||
let response = self.request::<request::Initialize>(params).await?;
|
||||
|
|
|
@ -434,8 +434,8 @@ impl LanguageServer {
|
|||
let root_uri = Url::from_file_path(&self.root_path).unwrap();
|
||||
#[allow(deprecated)]
|
||||
let params = InitializeParams {
|
||||
process_id: Default::default(),
|
||||
root_path: Default::default(),
|
||||
process_id: None,
|
||||
root_path: None,
|
||||
root_uri: Some(root_uri.clone()),
|
||||
initialization_options: options,
|
||||
capabilities: ClientCapabilities {
|
||||
|
@ -456,12 +456,15 @@ impl LanguageServer {
|
|||
inlay_hint: Some(InlayHintWorkspaceClientCapabilities {
|
||||
refresh_support: Some(true),
|
||||
}),
|
||||
diagnostic: Some(DiagnosticWorkspaceClientCapabilities {
|
||||
refresh_support: None,
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
text_document: Some(TextDocumentClientCapabilities {
|
||||
definition: Some(GotoCapability {
|
||||
link_support: Some(true),
|
||||
..Default::default()
|
||||
dynamic_registration: None,
|
||||
}),
|
||||
code_action: Some(CodeActionClientCapabilities {
|
||||
code_action_literal_support: Some(CodeActionLiteralSupport {
|
||||
|
@ -503,7 +506,7 @@ impl LanguageServer {
|
|||
}),
|
||||
hover: Some(HoverClientCapabilities {
|
||||
content_format: Some(vec![MarkupKind::Markdown]),
|
||||
..Default::default()
|
||||
dynamic_registration: None,
|
||||
}),
|
||||
inlay_hint: Some(InlayHintClientCapabilities {
|
||||
resolve_support: Some(InlayHintResolveClientCapabilities {
|
||||
|
@ -517,6 +520,20 @@ impl LanguageServer {
|
|||
}),
|
||||
dynamic_registration: Some(false),
|
||||
}),
|
||||
publish_diagnostics: Some(PublishDiagnosticsClientCapabilities {
|
||||
related_information: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
formatting: Some(DynamicRegistrationClientCapabilities {
|
||||
dynamic_registration: None,
|
||||
}),
|
||||
on_type_formatting: Some(DynamicRegistrationClientCapabilities {
|
||||
dynamic_registration: None,
|
||||
}),
|
||||
diagnostic: Some(DiagnosticClientCapabilities {
|
||||
related_document_support: Some(true),
|
||||
dynamic_registration: None,
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
experimental: Some(json!({
|
||||
|
@ -526,15 +543,15 @@ impl LanguageServer {
|
|||
work_done_progress: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
general: None,
|
||||
},
|
||||
trace: Default::default(),
|
||||
trace: None,
|
||||
workspace_folders: Some(vec![WorkspaceFolder {
|
||||
uri: root_uri,
|
||||
name: Default::default(),
|
||||
}]),
|
||||
client_info: Default::default(),
|
||||
locale: Default::default(),
|
||||
client_info: None,
|
||||
locale: None,
|
||||
};
|
||||
|
||||
let response = self.request::<request::Initialize>(params).await?;
|
||||
|
|
|
@ -2641,8 +2641,9 @@ impl Project {
|
|||
});
|
||||
|
||||
for (adapter, server) in servers {
|
||||
let workspace_config =
|
||||
cx.update(|cx| adapter.workspace_configuration(cx)).await;
|
||||
let workspace_config = cx
|
||||
.update(|cx| adapter.workspace_configuration(server.root_path(), cx))
|
||||
.await;
|
||||
server
|
||||
.notify::<lsp::notification::DidChangeConfiguration>(
|
||||
lsp::DidChangeConfigurationParams {
|
||||
|
@ -2753,7 +2754,7 @@ impl Project {
|
|||
stderr_capture.clone(),
|
||||
language.clone(),
|
||||
adapter.clone(),
|
||||
worktree_path,
|
||||
Arc::clone(&worktree_path),
|
||||
ProjectLspAdapterDelegate::new(self, cx),
|
||||
cx,
|
||||
) {
|
||||
|
@ -2776,6 +2777,7 @@ impl Project {
|
|||
cx.spawn_weak(|this, mut cx| async move {
|
||||
let result = Self::setup_and_insert_language_server(
|
||||
this,
|
||||
&worktree_path,
|
||||
override_options,
|
||||
pending_server,
|
||||
adapter.clone(),
|
||||
|
@ -2891,6 +2893,7 @@ impl Project {
|
|||
|
||||
async fn setup_and_insert_language_server(
|
||||
this: WeakModelHandle<Self>,
|
||||
worktree_path: &Path,
|
||||
override_initialization_options: Option<serde_json::Value>,
|
||||
pending_server: PendingLanguageServer,
|
||||
adapter: Arc<CachedLspAdapter>,
|
||||
|
@ -2903,6 +2906,7 @@ impl Project {
|
|||
this,
|
||||
override_initialization_options,
|
||||
pending_server,
|
||||
worktree_path,
|
||||
adapter.clone(),
|
||||
server_id,
|
||||
cx,
|
||||
|
@ -2932,11 +2936,14 @@ impl Project {
|
|||
this: WeakModelHandle<Self>,
|
||||
override_options: Option<serde_json::Value>,
|
||||
pending_server: PendingLanguageServer,
|
||||
worktree_path: &Path,
|
||||
adapter: Arc<CachedLspAdapter>,
|
||||
server_id: LanguageServerId,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<Arc<LanguageServer>> {
|
||||
let workspace_config = cx.update(|cx| adapter.workspace_configuration(cx)).await;
|
||||
let workspace_config = cx
|
||||
.update(|cx| adapter.workspace_configuration(worktree_path, cx))
|
||||
.await;
|
||||
let language_server = pending_server.task.await?;
|
||||
|
||||
language_server
|
||||
|
@ -2964,11 +2971,14 @@ impl Project {
|
|||
language_server
|
||||
.on_request::<lsp::request::WorkspaceConfiguration, _, _>({
|
||||
let adapter = adapter.clone();
|
||||
let worktree_path = worktree_path.to_path_buf();
|
||||
move |params, mut cx| {
|
||||
let adapter = adapter.clone();
|
||||
let worktree_path = worktree_path.clone();
|
||||
async move {
|
||||
let workspace_config =
|
||||
cx.update(|cx| adapter.workspace_configuration(cx)).await;
|
||||
let workspace_config = cx
|
||||
.update(|cx| adapter.workspace_configuration(&worktree_path, cx))
|
||||
.await;
|
||||
Ok(params
|
||||
.items
|
||||
.into_iter()
|
||||
|
@ -6523,9 +6533,15 @@ impl Project {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn diagnostic_summary(&self, cx: &AppContext) -> DiagnosticSummary {
|
||||
pub fn diagnostic_summary(&self, include_ignored: bool, cx: &AppContext) -> DiagnosticSummary {
|
||||
let mut summary = DiagnosticSummary::default();
|
||||
for (_, _, path_summary) in self.diagnostic_summaries(cx) {
|
||||
for (_, _, path_summary) in
|
||||
self.diagnostic_summaries(include_ignored, cx)
|
||||
.filter(|(path, _, _)| {
|
||||
let worktree = self.entry_for_path(&path, cx).map(|entry| entry.is_ignored);
|
||||
include_ignored || worktree == Some(false)
|
||||
})
|
||||
{
|
||||
summary.error_count += path_summary.error_count;
|
||||
summary.warning_count += path_summary.warning_count;
|
||||
}
|
||||
|
@ -6534,6 +6550,7 @@ impl Project {
|
|||
|
||||
pub fn diagnostic_summaries<'a>(
|
||||
&'a self,
|
||||
include_ignored: bool,
|
||||
cx: &'a AppContext,
|
||||
) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
|
||||
self.visible_worktrees(cx).flat_map(move |worktree| {
|
||||
|
@ -6544,6 +6561,10 @@ impl Project {
|
|||
.map(move |(path, server_id, summary)| {
|
||||
(ProjectPath { worktree_id, path }, server_id, summary)
|
||||
})
|
||||
.filter(move |(path, _, _)| {
|
||||
let worktree = self.entry_for_path(&path, cx).map(|entry| entry.is_ignored);
|
||||
include_ignored || worktree == Some(false)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -806,7 +806,7 @@ async fn test_single_file_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
||||
async fn test_omitted_diagnostics(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
|
@ -814,7 +814,12 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
"/root",
|
||||
json!({
|
||||
"dir": {
|
||||
".git": {
|
||||
"HEAD": "ref: refs/heads/main",
|
||||
},
|
||||
".gitignore": "b.rs",
|
||||
"a.rs": "let a = 1;",
|
||||
"b.rs": "let b = 2;",
|
||||
},
|
||||
"other.rs": "let b = c;"
|
||||
}),
|
||||
|
@ -822,6 +827,13 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
.await;
|
||||
|
||||
let project = Project::test(fs, ["/root/dir".as_ref()], cx).await;
|
||||
let (worktree, _) = project
|
||||
.update(cx, |project, cx| {
|
||||
project.find_or_create_local_worktree("/root/dir", true, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let main_worktree_id = worktree.read_with(cx, |tree, _| tree.id());
|
||||
|
||||
let (worktree, _) = project
|
||||
.update(cx, |project, cx| {
|
||||
|
@ -829,12 +841,30 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let worktree_id = worktree.read_with(cx, |tree, _| tree.id());
|
||||
let other_worktree_id = worktree.read_with(cx, |tree, _| tree.id());
|
||||
|
||||
let server_id = LanguageServerId(0);
|
||||
project.update(cx, |project, cx| {
|
||||
project
|
||||
.update_diagnostics(
|
||||
LanguageServerId(0),
|
||||
server_id,
|
||||
lsp::PublishDiagnosticsParams {
|
||||
uri: Url::from_file_path("/root/dir/b.rs").unwrap(),
|
||||
version: None,
|
||||
diagnostics: vec![lsp::Diagnostic {
|
||||
range: lsp::Range::new(lsp::Position::new(0, 4), lsp::Position::new(0, 5)),
|
||||
severity: Some(lsp::DiagnosticSeverity::ERROR),
|
||||
message: "unused variable 'b'".to_string(),
|
||||
..Default::default()
|
||||
}],
|
||||
},
|
||||
&[],
|
||||
cx,
|
||||
)
|
||||
.unwrap();
|
||||
project
|
||||
.update_diagnostics(
|
||||
server_id,
|
||||
lsp::PublishDiagnosticsParams {
|
||||
uri: Url::from_file_path("/root/other.rs").unwrap(),
|
||||
version: None,
|
||||
|
@ -851,11 +881,34 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
.unwrap();
|
||||
});
|
||||
|
||||
let buffer = project
|
||||
.update(cx, |project, cx| project.open_buffer((worktree_id, ""), cx))
|
||||
let main_ignored_buffer = project
|
||||
.update(cx, |project, cx| {
|
||||
project.open_buffer((main_worktree_id, "b.rs"), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
buffer.read_with(cx, |buffer, _| {
|
||||
main_ignored_buffer.read_with(cx, |buffer, _| {
|
||||
let chunks = chunks_with_diagnostics(buffer, 0..buffer.len());
|
||||
assert_eq!(
|
||||
chunks
|
||||
.iter()
|
||||
.map(|(s, d)| (s.as_str(), *d))
|
||||
.collect::<Vec<_>>(),
|
||||
&[
|
||||
("let ", None),
|
||||
("b", Some(DiagnosticSeverity::ERROR)),
|
||||
(" = 2;", None),
|
||||
],
|
||||
"Gigitnored buffers should still get in-buffer diagnostics",
|
||||
);
|
||||
});
|
||||
let other_buffer = project
|
||||
.update(cx, |project, cx| {
|
||||
project.open_buffer((other_worktree_id, ""), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
other_buffer.read_with(cx, |buffer, _| {
|
||||
let chunks = chunks_with_diagnostics(buffer, 0..buffer.len());
|
||||
assert_eq!(
|
||||
chunks
|
||||
|
@ -866,13 +919,29 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
("let b = ", None),
|
||||
("c", Some(DiagnosticSeverity::ERROR)),
|
||||
(";", None),
|
||||
]
|
||||
],
|
||||
"Buffers from hidden projects should still get in-buffer diagnostics"
|
||||
);
|
||||
});
|
||||
|
||||
project.read_with(cx, |project, cx| {
|
||||
assert_eq!(project.diagnostic_summaries(cx).next(), None);
|
||||
assert_eq!(project.diagnostic_summary(cx).error_count, 0);
|
||||
assert_eq!(project.diagnostic_summaries(false, cx).next(), None);
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(true, cx).collect::<Vec<_>>(),
|
||||
vec![(
|
||||
ProjectPath {
|
||||
worktree_id: main_worktree_id,
|
||||
path: Arc::from(Path::new("b.rs")),
|
||||
},
|
||||
server_id,
|
||||
DiagnosticSummary {
|
||||
error_count: 1,
|
||||
warning_count: 0,
|
||||
}
|
||||
)]
|
||||
);
|
||||
assert_eq!(project.diagnostic_summary(false, cx).error_count, 0);
|
||||
assert_eq!(project.diagnostic_summary(true, cx).error_count, 1);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1145,7 +1214,7 @@ async fn test_restarting_server_with_diagnostics_published(cx: &mut gpui::TestAp
|
|||
});
|
||||
project.read_with(cx, |project, cx| {
|
||||
assert_eq!(
|
||||
project.diagnostic_summary(cx),
|
||||
project.diagnostic_summary(false, cx),
|
||||
DiagnosticSummary {
|
||||
error_count: 1,
|
||||
warning_count: 0,
|
||||
|
@ -1171,7 +1240,7 @@ async fn test_restarting_server_with_diagnostics_published(cx: &mut gpui::TestAp
|
|||
});
|
||||
project.read_with(cx, |project, cx| {
|
||||
assert_eq!(
|
||||
project.diagnostic_summary(cx),
|
||||
project.diagnostic_summary(false, cx),
|
||||
DiagnosticSummary {
|
||||
error_count: 0,
|
||||
warning_count: 0,
|
||||
|
@ -1763,7 +1832,7 @@ async fn test_diagnostics_from_multiple_language_servers(cx: &mut gpui::TestAppC
|
|||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
project.diagnostic_summary(cx),
|
||||
project.diagnostic_summary(false, cx),
|
||||
DiagnosticSummary {
|
||||
error_count: 2,
|
||||
warning_count: 0,
|
||||
|
|
|
@ -2677,8 +2677,9 @@ impl Project {
|
|||
})?;
|
||||
|
||||
for (adapter, server) in servers {
|
||||
let workspace_config =
|
||||
cx.update(|cx| adapter.workspace_configuration(cx))?.await;
|
||||
let workspace_config = cx
|
||||
.update(|cx| adapter.workspace_configuration(server.root_path(), cx))?
|
||||
.await;
|
||||
server
|
||||
.notify::<lsp::notification::DidChangeConfiguration>(
|
||||
lsp::DidChangeConfigurationParams {
|
||||
|
@ -2790,7 +2791,7 @@ impl Project {
|
|||
stderr_capture.clone(),
|
||||
language.clone(),
|
||||
adapter.clone(),
|
||||
worktree_path,
|
||||
Arc::clone(&worktree_path),
|
||||
ProjectLspAdapterDelegate::new(self, cx),
|
||||
cx,
|
||||
) {
|
||||
|
@ -2822,6 +2823,7 @@ impl Project {
|
|||
cx.spawn(move |this, mut cx| async move {
|
||||
let result = Self::setup_and_insert_language_server(
|
||||
this.clone(),
|
||||
&worktree_path,
|
||||
initialization_options,
|
||||
pending_server,
|
||||
adapter.clone(),
|
||||
|
@ -2942,6 +2944,7 @@ impl Project {
|
|||
|
||||
async fn setup_and_insert_language_server(
|
||||
this: WeakModel<Self>,
|
||||
worktree_path: &Path,
|
||||
initialization_options: Option<serde_json::Value>,
|
||||
pending_server: PendingLanguageServer,
|
||||
adapter: Arc<CachedLspAdapter>,
|
||||
|
@ -2954,6 +2957,7 @@ impl Project {
|
|||
this.clone(),
|
||||
initialization_options,
|
||||
pending_server,
|
||||
worktree_path,
|
||||
adapter.clone(),
|
||||
server_id,
|
||||
cx,
|
||||
|
@ -2983,11 +2987,14 @@ impl Project {
|
|||
this: WeakModel<Self>,
|
||||
initialization_options: Option<serde_json::Value>,
|
||||
pending_server: PendingLanguageServer,
|
||||
worktree_path: &Path,
|
||||
adapter: Arc<CachedLspAdapter>,
|
||||
server_id: LanguageServerId,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<Arc<LanguageServer>> {
|
||||
let workspace_config = cx.update(|cx| adapter.workspace_configuration(cx))?.await;
|
||||
let workspace_config = cx
|
||||
.update(|cx| adapter.workspace_configuration(worktree_path, cx))?
|
||||
.await;
|
||||
let language_server = pending_server.task.await?;
|
||||
|
||||
language_server
|
||||
|
@ -3016,11 +3023,14 @@ impl Project {
|
|||
language_server
|
||||
.on_request::<lsp::request::WorkspaceConfiguration, _, _>({
|
||||
let adapter = adapter.clone();
|
||||
let worktree_path = worktree_path.to_path_buf();
|
||||
move |params, cx| {
|
||||
let adapter = adapter.clone();
|
||||
let worktree_path = worktree_path.clone();
|
||||
async move {
|
||||
let workspace_config =
|
||||
cx.update(|cx| adapter.workspace_configuration(cx))?.await;
|
||||
let workspace_config = cx
|
||||
.update(|cx| adapter.workspace_configuration(&worktree_path, cx))?
|
||||
.await;
|
||||
Ok(params
|
||||
.items
|
||||
.into_iter()
|
||||
|
@ -6596,9 +6606,15 @@ impl Project {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn diagnostic_summary(&self, cx: &AppContext) -> DiagnosticSummary {
|
||||
pub fn diagnostic_summary(&self, include_ignored: bool, cx: &AppContext) -> DiagnosticSummary {
|
||||
let mut summary = DiagnosticSummary::default();
|
||||
for (_, _, path_summary) in self.diagnostic_summaries(cx) {
|
||||
for (_, _, path_summary) in
|
||||
self.diagnostic_summaries(include_ignored, cx)
|
||||
.filter(|(path, _, _)| {
|
||||
let worktree = self.entry_for_path(&path, cx).map(|entry| entry.is_ignored);
|
||||
include_ignored || worktree == Some(false)
|
||||
})
|
||||
{
|
||||
summary.error_count += path_summary.error_count;
|
||||
summary.warning_count += path_summary.warning_count;
|
||||
}
|
||||
|
@ -6607,17 +6623,23 @@ impl Project {
|
|||
|
||||
pub fn diagnostic_summaries<'a>(
|
||||
&'a self,
|
||||
include_ignored: bool,
|
||||
cx: &'a AppContext,
|
||||
) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
|
||||
self.visible_worktrees(cx).flat_map(move |worktree| {
|
||||
let worktree = worktree.read(cx);
|
||||
let worktree_id = worktree.id();
|
||||
worktree
|
||||
.diagnostic_summaries()
|
||||
.map(move |(path, server_id, summary)| {
|
||||
(ProjectPath { worktree_id, path }, server_id, summary)
|
||||
})
|
||||
})
|
||||
self.visible_worktrees(cx)
|
||||
.flat_map(move |worktree| {
|
||||
let worktree = worktree.read(cx);
|
||||
let worktree_id = worktree.id();
|
||||
worktree
|
||||
.diagnostic_summaries()
|
||||
.map(move |(path, server_id, summary)| {
|
||||
(ProjectPath { worktree_id, path }, server_id, summary)
|
||||
})
|
||||
})
|
||||
.filter(move |(path, _, _)| {
|
||||
let worktree = self.entry_for_path(&path, cx).map(|entry| entry.is_ignored);
|
||||
include_ignored || worktree == Some(false)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn disk_based_diagnostics_started(
|
||||
|
|
|
@ -823,7 +823,7 @@ async fn test_single_file_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
||||
async fn test_omitted_diagnostics(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.executor());
|
||||
|
@ -831,7 +831,12 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
"/root",
|
||||
json!({
|
||||
"dir": {
|
||||
".git": {
|
||||
"HEAD": "ref: refs/heads/main",
|
||||
},
|
||||
".gitignore": "b.rs",
|
||||
"a.rs": "let a = 1;",
|
||||
"b.rs": "let b = 2;",
|
||||
},
|
||||
"other.rs": "let b = c;"
|
||||
}),
|
||||
|
@ -839,6 +844,13 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
.await;
|
||||
|
||||
let project = Project::test(fs, ["/root/dir".as_ref()], cx).await;
|
||||
let (worktree, _) = project
|
||||
.update(cx, |project, cx| {
|
||||
project.find_or_create_local_worktree("/root/dir", true, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let main_worktree_id = worktree.read_with(cx, |tree, _| tree.id());
|
||||
|
||||
let (worktree, _) = project
|
||||
.update(cx, |project, cx| {
|
||||
|
@ -846,12 +858,30 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let worktree_id = worktree.update(cx, |tree, _| tree.id());
|
||||
let other_worktree_id = worktree.update(cx, |tree, _| tree.id());
|
||||
|
||||
let server_id = LanguageServerId(0);
|
||||
project.update(cx, |project, cx| {
|
||||
project
|
||||
.update_diagnostics(
|
||||
LanguageServerId(0),
|
||||
server_id,
|
||||
lsp::PublishDiagnosticsParams {
|
||||
uri: Url::from_file_path("/root/dir/b.rs").unwrap(),
|
||||
version: None,
|
||||
diagnostics: vec![lsp::Diagnostic {
|
||||
range: lsp::Range::new(lsp::Position::new(0, 4), lsp::Position::new(0, 5)),
|
||||
severity: Some(lsp::DiagnosticSeverity::ERROR),
|
||||
message: "unused variable 'b'".to_string(),
|
||||
..Default::default()
|
||||
}],
|
||||
},
|
||||
&[],
|
||||
cx,
|
||||
)
|
||||
.unwrap();
|
||||
project
|
||||
.update_diagnostics(
|
||||
server_id,
|
||||
lsp::PublishDiagnosticsParams {
|
||||
uri: Url::from_file_path("/root/other.rs").unwrap(),
|
||||
version: None,
|
||||
|
@ -868,11 +898,34 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
.unwrap();
|
||||
});
|
||||
|
||||
let buffer = project
|
||||
.update(cx, |project, cx| project.open_buffer((worktree_id, ""), cx))
|
||||
let main_ignored_buffer = project
|
||||
.update(cx, |project, cx| {
|
||||
project.open_buffer((main_worktree_id, "b.rs"), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
buffer.update(cx, |buffer, _| {
|
||||
main_ignored_buffer.update(cx, |buffer, _| {
|
||||
let chunks = chunks_with_diagnostics(buffer, 0..buffer.len());
|
||||
assert_eq!(
|
||||
chunks
|
||||
.iter()
|
||||
.map(|(s, d)| (s.as_str(), *d))
|
||||
.collect::<Vec<_>>(),
|
||||
&[
|
||||
("let ", None),
|
||||
("b", Some(DiagnosticSeverity::ERROR)),
|
||||
(" = 2;", None),
|
||||
],
|
||||
"Gigitnored buffers should still get in-buffer diagnostics",
|
||||
);
|
||||
});
|
||||
let other_buffer = project
|
||||
.update(cx, |project, cx| {
|
||||
project.open_buffer((other_worktree_id, ""), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
other_buffer.update(cx, |buffer, _| {
|
||||
let chunks = chunks_with_diagnostics(buffer, 0..buffer.len());
|
||||
assert_eq!(
|
||||
chunks
|
||||
|
@ -883,13 +936,29 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
("let b = ", None),
|
||||
("c", Some(DiagnosticSeverity::ERROR)),
|
||||
(";", None),
|
||||
]
|
||||
],
|
||||
"Buffers from hidden projects should still get in-buffer diagnostics"
|
||||
);
|
||||
});
|
||||
|
||||
project.update(cx, |project, cx| {
|
||||
assert_eq!(project.diagnostic_summaries(cx).next(), None);
|
||||
assert_eq!(project.diagnostic_summary(cx).error_count, 0);
|
||||
assert_eq!(project.diagnostic_summaries(false, cx).next(), None);
|
||||
assert_eq!(
|
||||
project.diagnostic_summaries(true, cx).collect::<Vec<_>>(),
|
||||
vec![(
|
||||
ProjectPath {
|
||||
worktree_id: main_worktree_id,
|
||||
path: Arc::from(Path::new("b.rs")),
|
||||
},
|
||||
server_id,
|
||||
DiagnosticSummary {
|
||||
error_count: 1,
|
||||
warning_count: 0,
|
||||
}
|
||||
)]
|
||||
);
|
||||
assert_eq!(project.diagnostic_summary(false, cx).error_count, 0);
|
||||
assert_eq!(project.diagnostic_summary(true, cx).error_count, 1);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1162,7 +1231,7 @@ async fn test_restarting_server_with_diagnostics_published(cx: &mut gpui::TestAp
|
|||
});
|
||||
project.update(cx, |project, cx| {
|
||||
assert_eq!(
|
||||
project.diagnostic_summary(cx),
|
||||
project.diagnostic_summary(false, cx),
|
||||
DiagnosticSummary {
|
||||
error_count: 1,
|
||||
warning_count: 0,
|
||||
|
@ -1188,7 +1257,7 @@ async fn test_restarting_server_with_diagnostics_published(cx: &mut gpui::TestAp
|
|||
});
|
||||
project.update(cx, |project, cx| {
|
||||
assert_eq!(
|
||||
project.diagnostic_summary(cx),
|
||||
project.diagnostic_summary(false, cx),
|
||||
DiagnosticSummary {
|
||||
error_count: 0,
|
||||
warning_count: 0,
|
||||
|
@ -1777,7 +1846,7 @@ async fn test_diagnostics_from_multiple_language_servers(cx: &mut gpui::TestAppC
|
|||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
project.diagnostic_summary(cx),
|
||||
project.diagnostic_summary(false, cx),
|
||||
DiagnosticSummary {
|
||||
error_count: 2,
|
||||
warning_count: 0,
|
||||
|
|
|
@ -1627,9 +1627,21 @@ impl View for ProjectPanel {
|
|||
}
|
||||
}
|
||||
|
||||
fn update_keymap_context(&self, keymap: &mut KeymapContext, _: &AppContext) {
|
||||
fn update_keymap_context(&self, keymap: &mut KeymapContext, cx: &AppContext) {
|
||||
Self::reset_to_default_keymap_context(keymap);
|
||||
keymap.add_identifier("menu");
|
||||
|
||||
if let Some(window) = cx.active_window() {
|
||||
window.read_with(cx, |cx| {
|
||||
let identifier = if self.filename_editor.is_focused(cx) {
|
||||
"editing"
|
||||
} else {
|
||||
"not_editing"
|
||||
};
|
||||
|
||||
keymap.add_identifier(identifier);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext<Self>) {
|
||||
|
|
|
@ -10,8 +10,9 @@ use anyhow::{anyhow, Result};
|
|||
use gpui::{
|
||||
actions, div, px, uniform_list, Action, AppContext, AssetSource, AsyncWindowContext,
|
||||
ClipboardItem, Div, EventEmitter, FocusHandle, Focusable, FocusableView, InteractiveElement,
|
||||
Model, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render, Stateful, Styled,
|
||||
Task, UniformListScrollHandle, View, ViewContext, VisualContext as _, WeakView, WindowContext,
|
||||
KeyContext, Model, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render, Stateful,
|
||||
Styled, Task, UniformListScrollHandle, View, ViewContext, VisualContext as _, WeakView,
|
||||
WindowContext,
|
||||
};
|
||||
use menu::{Confirm, SelectNext, SelectPrev};
|
||||
use project::{
|
||||
|
@ -1403,6 +1404,22 @@ impl ProjectPanel {
|
|||
// );
|
||||
// })
|
||||
}
|
||||
|
||||
fn dispatch_context(&self, cx: &ViewContext<Self>) -> KeyContext {
|
||||
let mut dispatch_context = KeyContext::default();
|
||||
dispatch_context.add("ProjectPanel");
|
||||
dispatch_context.add("menu");
|
||||
|
||||
let identifier = if self.filename_editor.focus_handle(cx).is_focused(cx) {
|
||||
"editing"
|
||||
} else {
|
||||
"not_editing"
|
||||
};
|
||||
|
||||
dispatch_context.add(identifier);
|
||||
|
||||
dispatch_context
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for ProjectPanel {
|
||||
|
@ -1415,7 +1432,8 @@ impl Render for ProjectPanel {
|
|||
div()
|
||||
.id("project-panel")
|
||||
.size_full()
|
||||
.key_context("ProjectPanel")
|
||||
.relative()
|
||||
.key_context(self.dispatch_context(cx))
|
||||
.on_action(cx.listener(Self::select_next))
|
||||
.on_action(cx.listener(Self::select_prev))
|
||||
.on_action(cx.listener(Self::expand_selected_entry))
|
||||
|
|
|
@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathansobo@gmail.com>"]
|
|||
description = "The fast, collaborative code editor."
|
||||
edition = "2021"
|
||||
name = "zed"
|
||||
version = "0.115.0"
|
||||
version = "0.115.3"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
|
|
|
@ -1 +1 @@
|
|||
dev
|
||||
stable
|
|
@ -105,6 +105,7 @@ impl LspAdapter for JsonLspAdapter {
|
|||
|
||||
fn workspace_configuration(
|
||||
&self,
|
||||
_workspace_root: &Path,
|
||||
cx: &mut AppContext,
|
||||
) -> BoxFuture<'static, serde_json::Value> {
|
||||
let action_names = cx.all_action_names().collect::<Vec<_>>();
|
||||
|
|
|
@ -29,7 +29,6 @@ pub struct IntelephenseLspAdapter {
|
|||
impl IntelephenseLspAdapter {
|
||||
const SERVER_PATH: &'static str = "node_modules/intelephense/lib/intelephense.js";
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
|
||||
Self { node }
|
||||
}
|
||||
|
|
|
@ -107,7 +107,11 @@ impl LspAdapter for TailwindLspAdapter {
|
|||
}))
|
||||
}
|
||||
|
||||
fn workspace_configuration(&self, _: &mut AppContext) -> BoxFuture<'static, Value> {
|
||||
fn workspace_configuration(
|
||||
&self,
|
||||
_workspace_root: &Path,
|
||||
_: &mut AppContext,
|
||||
) -> BoxFuture<'static, Value> {
|
||||
future::ready(json!({
|
||||
"tailwindCSS": {
|
||||
"emmetCompletions": true,
|
||||
|
|
|
@ -205,7 +205,6 @@ pub struct EsLintLspAdapter {
|
|||
impl EsLintLspAdapter {
|
||||
const SERVER_PATH: &'static str = "vscode-eslint/server/out/eslintServer.js";
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
|
||||
EsLintLspAdapter { node }
|
||||
}
|
||||
|
@ -213,13 +212,23 @@ impl EsLintLspAdapter {
|
|||
|
||||
#[async_trait]
|
||||
impl LspAdapter for EsLintLspAdapter {
|
||||
fn workspace_configuration(&self, _: &mut AppContext) -> BoxFuture<'static, Value> {
|
||||
fn workspace_configuration(
|
||||
&self,
|
||||
workspace_root: &Path,
|
||||
_: &mut AppContext,
|
||||
) -> BoxFuture<'static, Value> {
|
||||
future::ready(json!({
|
||||
"": {
|
||||
"validate": "on",
|
||||
"rulesCustomizations": [],
|
||||
"run": "onType",
|
||||
"nodePath": null,
|
||||
"workingDirectory": {"mode": "auto"},
|
||||
"workspaceFolder": {
|
||||
"uri": workspace_root,
|
||||
"name": workspace_root.file_name()
|
||||
.unwrap_or_else(|| workspace_root.as_os_str()),
|
||||
},
|
||||
}
|
||||
}))
|
||||
.boxed()
|
||||
|
|
|
@ -93,7 +93,11 @@ impl LspAdapter for YamlLspAdapter {
|
|||
) -> Option<LanguageServerBinary> {
|
||||
get_cached_server_binary(container_dir, &*self.node).await
|
||||
}
|
||||
fn workspace_configuration(&self, cx: &mut AppContext) -> BoxFuture<'static, Value> {
|
||||
fn workspace_configuration(
|
||||
&self,
|
||||
_workspace_root: &Path,
|
||||
cx: &mut AppContext,
|
||||
) -> BoxFuture<'static, Value> {
|
||||
let tab_size = all_language_settings(None, cx)
|
||||
.language(Some("YAML"))
|
||||
.tab_size;
|
||||
|
|
|
@ -105,6 +105,7 @@ impl LspAdapter for JsonLspAdapter {
|
|||
|
||||
fn workspace_configuration(
|
||||
&self,
|
||||
_workspace_root: &Path,
|
||||
cx: &mut AppContext,
|
||||
) -> BoxFuture<'static, serde_json::Value> {
|
||||
let action_names = cx.all_action_names();
|
||||
|
|
|
@ -29,7 +29,6 @@ pub struct IntelephenseLspAdapter {
|
|||
impl IntelephenseLspAdapter {
|
||||
const SERVER_PATH: &'static str = "node_modules/intelephense/lib/intelephense.js";
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
|
||||
Self { node }
|
||||
}
|
||||
|
|
|
@ -107,7 +107,11 @@ impl LspAdapter for TailwindLspAdapter {
|
|||
}))
|
||||
}
|
||||
|
||||
fn workspace_configuration(&self, _: &mut AppContext) -> BoxFuture<'static, Value> {
|
||||
fn workspace_configuration(
|
||||
&self,
|
||||
_workspace_root: &Path,
|
||||
_: &mut AppContext,
|
||||
) -> BoxFuture<'static, Value> {
|
||||
future::ready(json!({
|
||||
"tailwindCSS": {
|
||||
"emmetCompletions": true,
|
||||
|
|
|
@ -205,7 +205,6 @@ pub struct EsLintLspAdapter {
|
|||
impl EsLintLspAdapter {
|
||||
const SERVER_PATH: &'static str = "vscode-eslint/server/out/eslintServer.js";
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
|
||||
EsLintLspAdapter { node }
|
||||
}
|
||||
|
@ -213,13 +212,23 @@ impl EsLintLspAdapter {
|
|||
|
||||
#[async_trait]
|
||||
impl LspAdapter for EsLintLspAdapter {
|
||||
fn workspace_configuration(&self, _: &mut AppContext) -> BoxFuture<'static, Value> {
|
||||
fn workspace_configuration(
|
||||
&self,
|
||||
workspace_root: &Path,
|
||||
_: &mut AppContext,
|
||||
) -> BoxFuture<'static, Value> {
|
||||
future::ready(json!({
|
||||
"": {
|
||||
"validate": "on",
|
||||
"rulesCustomizations": [],
|
||||
"run": "onType",
|
||||
"nodePath": null,
|
||||
"workingDirectory": {"mode": "auto"},
|
||||
"workspaceFolder": {
|
||||
"uri": workspace_root,
|
||||
"name": workspace_root.file_name()
|
||||
.unwrap_or_else(|| workspace_root.as_os_str()),
|
||||
},
|
||||
}
|
||||
}))
|
||||
.boxed()
|
||||
|
|
|
@ -93,7 +93,11 @@ impl LspAdapter for YamlLspAdapter {
|
|||
) -> Option<LanguageServerBinary> {
|
||||
get_cached_server_binary(container_dir, &*self.node).await
|
||||
}
|
||||
fn workspace_configuration(&self, cx: &mut AppContext) -> BoxFuture<'static, Value> {
|
||||
fn workspace_configuration(
|
||||
&self,
|
||||
_workspace_root: &Path,
|
||||
cx: &mut AppContext,
|
||||
) -> BoxFuture<'static, Value> {
|
||||
let tab_size = all_language_settings(None, cx)
|
||||
.language(Some("YAML"))
|
||||
.tab_size;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue