mirror of
https://github.com/zed-industries/zed.git
synced 2026-07-14 18:32:18 +00:00
Compare commits
5 commits
collab-sta
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48a0cbcfd8 | ||
|
|
3e76813825 | ||
|
|
ba0eea3f49 | ||
|
|
ef2430c8f3 | ||
|
|
72656afa6d |
6 changed files with 873 additions and 339 deletions
|
|
@ -331,13 +331,12 @@ impl Editor {
|
|||
self.set_max_diagnostics_severity(new_severity, cx);
|
||||
if self.diagnostics_enabled {
|
||||
self.active_diagnostics = ActiveDiagnostic::None;
|
||||
self.refresh_inline_diagnostics(false, window, cx);
|
||||
} else {
|
||||
self.inline_diagnostics_update = Task::ready(());
|
||||
self.inline_diagnostics.clear();
|
||||
} else {
|
||||
self.refresh_inline_diagnostics(false, window, cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub(super) fn all_diagnostics_active(&self) -> bool {
|
||||
|
|
@ -464,6 +463,7 @@ impl Editor {
|
|||
{
|
||||
self.inline_diagnostics_update = Task::ready(());
|
||||
self.inline_diagnostics.clear();
|
||||
cx.notify();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -596,3 +596,158 @@ impl Editor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
actions::{ToggleDiagnostics, ToggleInlineDiagnostics},
|
||||
editor_tests::init_test,
|
||||
test::editor_test_context::EditorTestContext,
|
||||
};
|
||||
use gpui::{TestAppContext, UpdateGlobal};
|
||||
use indoc::indoc;
|
||||
use language::DiagnosticSourceKind;
|
||||
use lsp::LanguageServerId;
|
||||
use settings::{DelayMs, SettingsStore};
|
||||
use std::sync::{
|
||||
Arc,
|
||||
atomic::{self, AtomicUsize},
|
||||
};
|
||||
use util::path;
|
||||
|
||||
fn setup_inline_diagnostics(cx: &mut EditorTestContext) {
|
||||
cx.update(|_, cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings(cx, |settings| {
|
||||
let inline = settings
|
||||
.diagnostics
|
||||
.get_or_insert_default()
|
||||
.inline
|
||||
.get_or_insert_default();
|
||||
inline.enabled = Some(true);
|
||||
inline.update_debounce_ms = Some(DelayMs(0));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
cx.set_state(indoc! {"
|
||||
fn func(abc dˇef: i32) -> u32 {
|
||||
}
|
||||
"});
|
||||
|
||||
let lsp_store =
|
||||
cx.update_editor(|editor, _, cx| editor.project().unwrap().read(cx).lsp_store());
|
||||
cx.update(|_, cx| {
|
||||
lsp_store.update(cx, |lsp_store, cx| {
|
||||
lsp_store
|
||||
.update_diagnostics(
|
||||
LanguageServerId(0),
|
||||
lsp::PublishDiagnosticsParams {
|
||||
uri: lsp::Uri::from_file_path(path!("/root/file")).unwrap(),
|
||||
version: None,
|
||||
diagnostics: vec![lsp::Diagnostic {
|
||||
range: lsp::Range::new(
|
||||
lsp::Position::new(0, 12),
|
||||
lsp::Position::new(0, 15),
|
||||
),
|
||||
severity: Some(lsp::DiagnosticSeverity::ERROR),
|
||||
message: "cannot find value `def`".to_string(),
|
||||
..Default::default()
|
||||
}],
|
||||
},
|
||||
None,
|
||||
DiagnosticSourceKind::Pushed,
|
||||
&[],
|
||||
cx,
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, _, _| {
|
||||
assert_eq!(
|
||||
editor.inline_diagnostics.len(),
|
||||
1,
|
||||
"inline diagnostics should appear after the language server publishes them"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_toggle_diagnostics_refreshes_inline_diagnostics(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
setup_inline_diagnostics(&mut cx);
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.toggle_diagnostics(&ToggleDiagnostics, window, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
cx.update_editor(|editor, _, _| {
|
||||
assert_eq!(
|
||||
editor.inline_diagnostics.len(),
|
||||
0,
|
||||
"inline diagnostics should be cleared after disabling diagnostics"
|
||||
);
|
||||
});
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.toggle_diagnostics(&ToggleDiagnostics, window, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
cx.update_editor(|editor, _, _| {
|
||||
assert_eq!(
|
||||
editor.inline_diagnostics.len(),
|
||||
1,
|
||||
"inline diagnostics should reappear after re-enabling diagnostics, without further editor events"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_toggle_inline_diagnostics_notifies_on_hide(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
setup_inline_diagnostics(&mut cx);
|
||||
|
||||
let notify_count = Arc::new(AtomicUsize::new(0));
|
||||
let editor = cx.editor.clone();
|
||||
let _subscription = cx.update({
|
||||
let notify_count = notify_count.clone();
|
||||
move |_, cx| {
|
||||
cx.observe(&editor, move |_, _| {
|
||||
notify_count.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.toggle_inline_diagnostics(&ToggleInlineDiagnostics, window, cx);
|
||||
});
|
||||
cx.update_editor(|editor, _, _| {
|
||||
assert_eq!(
|
||||
editor.inline_diagnostics.len(),
|
||||
0,
|
||||
"inline diagnostics should be cleared after toggling them off"
|
||||
);
|
||||
});
|
||||
assert_eq!(
|
||||
notify_count.load(atomic::Ordering::SeqCst),
|
||||
1,
|
||||
"toggling inline diagnostics off should notify to repaint the editor"
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.toggle_inline_diagnostics(&ToggleInlineDiagnostics, window, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
cx.update_editor(|editor, _, _| {
|
||||
assert_eq!(
|
||||
editor.inline_diagnostics.len(),
|
||||
1,
|
||||
"inline diagnostics should reappear after toggling them back on"
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -12,11 +12,10 @@ use windows::Win32::{
|
|||
Foundation::{FILETIME, LPARAM, WPARAM},
|
||||
Media::{timeBeginPeriod, timeEndPeriod},
|
||||
System::Threading::{
|
||||
CloseThreadpoolTimer, CloseThreadpoolWork, CreateThreadpoolTimer, CreateThreadpoolWork,
|
||||
GetCurrentThread, PTP_CALLBACK_INSTANCE, PTP_TIMER, PTP_WORK, SetThreadPriority,
|
||||
SetThreadpoolTimer, SubmitThreadpoolWork, THREAD_PRIORITY_TIME_CRITICAL,
|
||||
CloseThreadpoolTimer, CreateThreadpoolTimer, GetCurrentThread, PTP_CALLBACK_INSTANCE,
|
||||
PTP_TIMER, SetThreadPriority, SetThreadpoolTimer, THREAD_PRIORITY_TIME_CRITICAL,
|
||||
TP_CALLBACK_ENVIRON_V3, TP_CALLBACK_PRIORITY, TP_CALLBACK_PRIORITY_HIGH,
|
||||
TP_CALLBACK_PRIORITY_LOW, TP_CALLBACK_PRIORITY_NORMAL,
|
||||
TP_CALLBACK_PRIORITY_LOW, TP_CALLBACK_PRIORITY_NORMAL, TrySubmitThreadpoolCallback,
|
||||
},
|
||||
UI::WindowsAndMessaging::PostMessageW,
|
||||
};
|
||||
|
|
@ -66,11 +65,8 @@ impl WindowsDispatcher {
|
|||
let context = runnable.into_raw().as_ptr() as *mut c_void;
|
||||
|
||||
unsafe {
|
||||
if let Ok(work) =
|
||||
CreateThreadpoolWork(Some(run_work_callback), Some(context), Some(&environ))
|
||||
{
|
||||
SubmitThreadpoolWork(work);
|
||||
}
|
||||
TrySubmitThreadpoolCallback(Some(run_work_callback), Some(context), Some(&environ))
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -179,11 +175,9 @@ impl PlatformDispatcher for WindowsDispatcher {
|
|||
unsafe extern "system" fn run_work_callback(
|
||||
_instance: PTP_CALLBACK_INSTANCE,
|
||||
context: *mut c_void,
|
||||
work: PTP_WORK,
|
||||
) {
|
||||
let runnable = unsafe { RunnableVariant::from_raw(NonNull::new_unchecked(context as *mut ())) };
|
||||
WindowsDispatcher::execute_runnable(runnable);
|
||||
unsafe { CloseThreadpoolWork(work) };
|
||||
}
|
||||
|
||||
unsafe extern "system" fn run_timer_callback(
|
||||
|
|
|
|||
|
|
@ -76,8 +76,6 @@ actions!(
|
|||
SetPreviewHidden,
|
||||
/// Opens the footer's actions menu.
|
||||
ToggleActionsMenu,
|
||||
/// Take the picker's content and open it in a multibuffer
|
||||
ToMultiBuffer,
|
||||
/// Toggles multi-select mode, in which clicking items adds them to
|
||||
/// the selection instead of opening them
|
||||
ToggleMultiSelect,
|
||||
|
|
|
|||
|
|
@ -3,13 +3,11 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use gpui::{
|
||||
Action, AnyElement, App, AppContext as _, Context, Entity, IntoElement, Pixels, StyledText,
|
||||
Task, Window, px,
|
||||
AnyElement, App, AppContext as _, Context, Entity, IntoElement, Pixels, StyledText, Task,
|
||||
Window, px,
|
||||
};
|
||||
use language::{Bias, Buffer, HighlightedText, HighlightedTextBuilder, ToPoint};
|
||||
use picker::{
|
||||
MatchLocation, PreviewBackend, PreviewLayout, PreviewSource, PreviewUpdate, ToMultiBuffer,
|
||||
};
|
||||
use picker::{MatchLocation, PreviewBackend, PreviewLayout, PreviewSource, PreviewUpdate};
|
||||
use project::{Project, Symbol};
|
||||
use rope::Point;
|
||||
use settings::Settings;
|
||||
|
|
@ -335,7 +333,7 @@ impl EditorPreview {
|
|||
div()
|
||||
.flex_1()
|
||||
.overflow_hidden()
|
||||
.child(self.editor_as_giant_button())
|
||||
.child(self.occluded_editor())
|
||||
.into_any_element()
|
||||
}
|
||||
}
|
||||
|
|
@ -357,7 +355,7 @@ impl EditorPreview {
|
|||
.child(content)
|
||||
}
|
||||
|
||||
fn editor_as_giant_button(&self) -> impl IntoElement {
|
||||
fn occluded_editor(&self) -> impl IntoElement {
|
||||
div()
|
||||
.relative()
|
||||
.size_full()
|
||||
|
|
@ -367,10 +365,7 @@ impl EditorPreview {
|
|||
.id("picker-preview-editor")
|
||||
.absolute()
|
||||
.inset_0()
|
||||
.occlude()
|
||||
.on_click(|_, window, cx| {
|
||||
window.dispatch_action(ToMultiBuffer.boxed_clone(), cx);
|
||||
}),
|
||||
.occlude(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,12 @@ impl merge_from::MergeFrom for AllLanguageSettingsContent {
|
|||
language_settings.merge_from(&other.defaults);
|
||||
if let Some(mut language_server_overrides) = language_server_overrides {
|
||||
if let Some(disabled) = &globally_disabled_servers {
|
||||
for disabled_server in disabled {
|
||||
if let Some(enabled_server) = disabled_server.strip_prefix('!') {
|
||||
language_server_overrides.retain(|entry| entry != enabled_server);
|
||||
}
|
||||
}
|
||||
|
||||
let insert_before = language_server_overrides
|
||||
.iter()
|
||||
.position(|entry| entry == REST_OF_LANGUAGE_SERVERS)
|
||||
|
|
@ -1327,6 +1333,55 @@ mod test {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_global_language_server_disable_overrides_per_language_enable() {
|
||||
let mut base = AllLanguageSettingsContent {
|
||||
defaults: LanguageSettingsContent {
|
||||
language_servers: Some(vec![REST_OF_LANGUAGE_SERVERS.into()]),
|
||||
..LanguageSettingsContent::default()
|
||||
},
|
||||
languages: LanguageToSettingsMap(
|
||||
[(
|
||||
"TypeScript".into(),
|
||||
LanguageSettingsContent {
|
||||
language_servers: Some(vec![
|
||||
"!typescript-language-server".into(),
|
||||
"vtsls".into(),
|
||||
REST_OF_LANGUAGE_SERVERS.into(),
|
||||
]),
|
||||
..LanguageSettingsContent::default()
|
||||
},
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
),
|
||||
..AllLanguageSettingsContent::default()
|
||||
};
|
||||
|
||||
let user = AllLanguageSettingsContent {
|
||||
defaults: LanguageSettingsContent {
|
||||
language_servers: Some(vec!["!vtsls".into(), REST_OF_LANGUAGE_SERVERS.into()]),
|
||||
..LanguageSettingsContent::default()
|
||||
},
|
||||
..AllLanguageSettingsContent::default()
|
||||
};
|
||||
|
||||
base.merge_from(&user);
|
||||
|
||||
let expected = vec![
|
||||
"!typescript-language-server".to_string(),
|
||||
"!vtsls".to_string(),
|
||||
REST_OF_LANGUAGE_SERVERS.to_string(),
|
||||
];
|
||||
assert_eq!(
|
||||
base.languages
|
||||
.0
|
||||
.get("TypeScript")
|
||||
.and_then(|settings| settings.language_servers.as_deref()),
|
||||
Some(expected.as_slice()),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_language_servers_merge_no_per_language_config_uses_global() {
|
||||
let mut base = AllLanguageSettingsContent {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue