debugger beta: Autoscroll to recently saved debug scenario when saving a scenario (#31528)
I added a test to this too as one of my first steps of improving `NewSessionModal`'s test coverage. Release Notes: - debugger beta: Select saved debug config when opening debug.json from `NewSessionModal`
This commit is contained in:
parent
94c006236e
commit
86b75759d1
3 changed files with 319 additions and 137 deletions
|
@ -1,5 +1,5 @@
|
||||||
use collections::FxHashMap;
|
use collections::FxHashMap;
|
||||||
use language::LanguageRegistry;
|
use language::{LanguageRegistry, Point, Selection};
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
ops::Not,
|
ops::Not,
|
||||||
|
@ -12,7 +12,7 @@ use std::{
|
||||||
use dap::{
|
use dap::{
|
||||||
DapRegistry, DebugRequest, TelemetrySpawnLocation, adapters::DebugAdapterName, send_telemetry,
|
DapRegistry, DebugRequest, TelemetrySpawnLocation, adapters::DebugAdapterName, send_telemetry,
|
||||||
};
|
};
|
||||||
use editor::{Editor, EditorElement, EditorStyle};
|
use editor::{Anchor, Editor, EditorElement, EditorStyle, scroll::Autoscroll};
|
||||||
use fuzzy::{StringMatch, StringMatchCandidate};
|
use fuzzy::{StringMatch, StringMatchCandidate};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
Animation, AnimationExt as _, App, AppContext, DismissEvent, Entity, EventEmitter, FocusHandle,
|
Animation, AnimationExt as _, App, AppContext, DismissEvent, Entity, EventEmitter, FocusHandle,
|
||||||
|
@ -37,7 +37,7 @@ use crate::{attach_modal::AttachModal, debugger_panel::DebugPanel};
|
||||||
|
|
||||||
enum SaveScenarioState {
|
enum SaveScenarioState {
|
||||||
Saving,
|
Saving,
|
||||||
Saved(ProjectPath),
|
Saved((ProjectPath, SharedString)),
|
||||||
Failed(SharedString),
|
Failed(SharedString),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +284,177 @@ impl NewSessionModal {
|
||||||
self.launch_picker.read(cx).delegate.task_contexts.clone()
|
self.launch_picker.read(cx).delegate.task_contexts.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn save_debug_scenario(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
let Some((save_scenario, scenario_label)) = self
|
||||||
|
.debugger
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|debugger| self.debug_scenario(&debugger, cx))
|
||||||
|
.zip(self.task_contexts(cx).and_then(|tcx| tcx.worktree()))
|
||||||
|
.and_then(|(scenario, worktree_id)| {
|
||||||
|
self.debug_panel
|
||||||
|
.update(cx, |panel, cx| {
|
||||||
|
panel.save_scenario(&scenario, worktree_id, window, cx)
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
.zip(Some(scenario.label.clone()))
|
||||||
|
})
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.save_scenario_state = Some(SaveScenarioState::Saving);
|
||||||
|
|
||||||
|
cx.spawn(async move |this, cx| {
|
||||||
|
let res = save_scenario.await;
|
||||||
|
|
||||||
|
this.update(cx, |this, _| match res {
|
||||||
|
Ok(saved_file) => {
|
||||||
|
this.save_scenario_state =
|
||||||
|
Some(SaveScenarioState::Saved((saved_file, scenario_label)))
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
this.save_scenario_state =
|
||||||
|
Some(SaveScenarioState::Failed(error.to_string().into()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
cx.background_executor().timer(Duration::from_secs(3)).await;
|
||||||
|
this.update(cx, |this, _| this.save_scenario_state.take())
|
||||||
|
.ok();
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_save_state(&self, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
let this_entity = cx.weak_entity().clone();
|
||||||
|
|
||||||
|
div().when_some(self.save_scenario_state.as_ref(), {
|
||||||
|
let this_entity = this_entity.clone();
|
||||||
|
|
||||||
|
move |this, save_state| match save_state {
|
||||||
|
SaveScenarioState::Saved((saved_path, scenario_label)) => this.child(
|
||||||
|
IconButton::new("new-session-modal-go-to-file", IconName::ArrowUpRight)
|
||||||
|
.icon_size(IconSize::Small)
|
||||||
|
.icon_color(Color::Muted)
|
||||||
|
.on_click({
|
||||||
|
let this_entity = this_entity.clone();
|
||||||
|
let saved_path = saved_path.clone();
|
||||||
|
let scenario_label = scenario_label.clone();
|
||||||
|
move |_, window, cx| {
|
||||||
|
window
|
||||||
|
.spawn(cx, {
|
||||||
|
let this_entity = this_entity.clone();
|
||||||
|
let saved_path = saved_path.clone();
|
||||||
|
let scenario_label = scenario_label.clone();
|
||||||
|
|
||||||
|
async move |cx| {
|
||||||
|
let editor = this_entity
|
||||||
|
.update_in(cx, |this, window, cx| {
|
||||||
|
this.workspace.update(cx, |workspace, cx| {
|
||||||
|
workspace.open_path(
|
||||||
|
saved_path.clone(),
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})??
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
cx.update(|window, cx| {
|
||||||
|
if let Some(editor) = editor.act_as::<Editor>(cx) {
|
||||||
|
editor.update(cx, |editor, cx| {
|
||||||
|
let row = editor
|
||||||
|
.text(cx)
|
||||||
|
.lines()
|
||||||
|
.enumerate()
|
||||||
|
.find_map(|(row, text)| {
|
||||||
|
if text.contains(
|
||||||
|
scenario_label.as_ref(),
|
||||||
|
) {
|
||||||
|
Some(row)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let buffer = editor.buffer().read(cx);
|
||||||
|
let excerpt_id =
|
||||||
|
*buffer.excerpt_ids().first()?;
|
||||||
|
|
||||||
|
let snapshot = buffer
|
||||||
|
.as_singleton()?
|
||||||
|
.read(cx)
|
||||||
|
.snapshot();
|
||||||
|
|
||||||
|
let anchor = snapshot.anchor_before(
|
||||||
|
Point::new(row as u32, 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
let anchor = Anchor {
|
||||||
|
buffer_id: anchor.buffer_id,
|
||||||
|
excerpt_id,
|
||||||
|
text_anchor: anchor,
|
||||||
|
diff_base_anchor: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
editor.change_selections(
|
||||||
|
Some(Autoscroll::center()),
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
|selections| {
|
||||||
|
let id =
|
||||||
|
selections.new_selection_id();
|
||||||
|
selections.select_anchors(
|
||||||
|
vec![Selection {
|
||||||
|
id,
|
||||||
|
start: anchor,
|
||||||
|
end: anchor,
|
||||||
|
reversed: false,
|
||||||
|
goal: language::SelectionGoal::None
|
||||||
|
}],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
this_entity
|
||||||
|
.update(cx, |_, cx| cx.emit(DismissEvent))
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
anyhow::Ok(())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
SaveScenarioState::Saving => this.child(
|
||||||
|
Icon::new(IconName::Spinner)
|
||||||
|
.size(IconSize::Small)
|
||||||
|
.color(Color::Muted)
|
||||||
|
.with_animation(
|
||||||
|
"Spinner",
|
||||||
|
Animation::new(Duration::from_secs(3)).repeat(),
|
||||||
|
|icon, delta| icon.transform(Transformation::rotate(percentage(delta))),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SaveScenarioState::Failed(error_msg) => this.child(
|
||||||
|
IconButton::new("Failed Scenario Saved", IconName::X)
|
||||||
|
.icon_size(IconSize::Small)
|
||||||
|
.icon_color(Color::Error)
|
||||||
|
.tooltip(ui::Tooltip::text(error_msg.clone())),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn adapter_drop_down_menu(
|
fn adapter_drop_down_menu(
|
||||||
&mut self,
|
&mut self,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
|
@ -355,7 +526,7 @@ impl NewSessionModal {
|
||||||
static SELECT_DEBUGGER_LABEL: SharedString = SharedString::new_static("Select Debugger");
|
static SELECT_DEBUGGER_LABEL: SharedString = SharedString::new_static("Select Debugger");
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum NewSessionMode {
|
pub(crate) enum NewSessionMode {
|
||||||
Custom,
|
Custom,
|
||||||
Attach,
|
Attach,
|
||||||
Launch,
|
Launch,
|
||||||
|
@ -423,8 +594,6 @@ impl Render for NewSessionModal {
|
||||||
window: &mut ui::Window,
|
window: &mut ui::Window,
|
||||||
cx: &mut ui::Context<Self>,
|
cx: &mut ui::Context<Self>,
|
||||||
) -> impl ui::IntoElement {
|
) -> impl ui::IntoElement {
|
||||||
let this = cx.weak_entity().clone();
|
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.size_full()
|
.size_full()
|
||||||
.w(rems(34.))
|
.w(rems(34.))
|
||||||
|
@ -534,58 +703,7 @@ impl Render for NewSessionModal {
|
||||||
.child(
|
.child(
|
||||||
Button::new("new-session-modal-back", "Save to .zed/debug.json...")
|
Button::new("new-session-modal-back", "Save to .zed/debug.json...")
|
||||||
.on_click(cx.listener(|this, _, window, cx| {
|
.on_click(cx.listener(|this, _, window, cx| {
|
||||||
let Some(save_scenario) = this
|
this.save_debug_scenario(window, cx);
|
||||||
.debugger
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|debugger| this.debug_scenario(&debugger, cx))
|
|
||||||
.zip(
|
|
||||||
this.task_contexts(cx)
|
|
||||||
.and_then(|tcx| tcx.worktree()),
|
|
||||||
)
|
|
||||||
.and_then(|(scenario, worktree_id)| {
|
|
||||||
this.debug_panel
|
|
||||||
.update(cx, |panel, cx| {
|
|
||||||
panel.save_scenario(
|
|
||||||
&scenario,
|
|
||||||
worktree_id,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
})
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.save_scenario_state = Some(SaveScenarioState::Saving);
|
|
||||||
|
|
||||||
cx.spawn(async move |this, cx| {
|
|
||||||
let res = save_scenario.await;
|
|
||||||
|
|
||||||
this.update(cx, |this, _| match res {
|
|
||||||
Ok(saved_file) => {
|
|
||||||
this.save_scenario_state =
|
|
||||||
Some(SaveScenarioState::Saved(saved_file))
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
this.save_scenario_state =
|
|
||||||
Some(SaveScenarioState::Failed(
|
|
||||||
error.to_string().into(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
cx.background_executor()
|
|
||||||
.timer(Duration::from_secs(2))
|
|
||||||
.await;
|
|
||||||
this.update(cx, |this, _| {
|
|
||||||
this.save_scenario_state.take()
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
}))
|
}))
|
||||||
.disabled(
|
.disabled(
|
||||||
self.debugger.is_none()
|
self.debugger.is_none()
|
||||||
|
@ -598,83 +716,7 @@ impl Render for NewSessionModal {
|
||||||
|| self.save_scenario_state.is_some(),
|
|| self.save_scenario_state.is_some(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.when_some(self.save_scenario_state.as_ref(), {
|
.child(self.render_save_state(cx)),
|
||||||
let this_entity = this.clone();
|
|
||||||
|
|
||||||
move |this, save_state| match save_state {
|
|
||||||
SaveScenarioState::Saved(saved_path) => this.child(
|
|
||||||
IconButton::new(
|
|
||||||
"new-session-modal-go-to-file",
|
|
||||||
IconName::ArrowUpRight,
|
|
||||||
)
|
|
||||||
.icon_size(IconSize::Small)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.on_click({
|
|
||||||
let this_entity = this_entity.clone();
|
|
||||||
let saved_path = saved_path.clone();
|
|
||||||
move |_, window, cx| {
|
|
||||||
window
|
|
||||||
.spawn(cx, {
|
|
||||||
let this_entity = this_entity.clone();
|
|
||||||
let saved_path = saved_path.clone();
|
|
||||||
|
|
||||||
async move |cx| {
|
|
||||||
this_entity
|
|
||||||
.update_in(
|
|
||||||
cx,
|
|
||||||
|this, window, cx| {
|
|
||||||
this.workspace.update(
|
|
||||||
cx,
|
|
||||||
|workspace, cx| {
|
|
||||||
workspace.open_path(
|
|
||||||
saved_path
|
|
||||||
.clone(),
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)??
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
this_entity
|
|
||||||
.update(cx, |_, cx| {
|
|
||||||
cx.emit(DismissEvent)
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
anyhow::Ok(())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
SaveScenarioState::Saving => this.child(
|
|
||||||
Icon::new(IconName::Spinner)
|
|
||||||
.size(IconSize::Small)
|
|
||||||
.color(Color::Muted)
|
|
||||||
.with_animation(
|
|
||||||
"Spinner",
|
|
||||||
Animation::new(Duration::from_secs(3)).repeat(),
|
|
||||||
|icon, delta| {
|
|
||||||
icon.transform(Transformation::rotate(
|
|
||||||
percentage(delta),
|
|
||||||
))
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SaveScenarioState::Failed(error_msg) => this.child(
|
|
||||||
IconButton::new("Failed Scenario Saved", IconName::X)
|
|
||||||
.icon_size(IconSize::Small)
|
|
||||||
.icon_color(Color::Error)
|
|
||||||
.tooltip(ui::Tooltip::text(error_msg.clone())),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
.child(
|
.child(
|
||||||
Button::new("debugger-spawn", "Start")
|
Button::new("debugger-spawn", "Start")
|
||||||
|
@ -1162,6 +1204,42 @@ pub(crate) fn resolve_path(path: &mut String) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl NewSessionModal {
|
||||||
|
pub(crate) fn set_custom(
|
||||||
|
&mut self,
|
||||||
|
program: impl AsRef<str>,
|
||||||
|
cwd: impl AsRef<str>,
|
||||||
|
stop_on_entry: bool,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
|
self.mode = NewSessionMode::Custom;
|
||||||
|
self.debugger = Some(dap::adapters::DebugAdapterName("fake-adapter".into()));
|
||||||
|
|
||||||
|
self.custom_mode.update(cx, |custom, cx| {
|
||||||
|
custom.program.update(cx, |editor, cx| {
|
||||||
|
editor.clear(window, cx);
|
||||||
|
editor.set_text(program.as_ref(), window, cx);
|
||||||
|
});
|
||||||
|
|
||||||
|
custom.cwd.update(cx, |editor, cx| {
|
||||||
|
editor.clear(window, cx);
|
||||||
|
editor.set_text(cwd.as_ref(), window, cx);
|
||||||
|
});
|
||||||
|
|
||||||
|
custom.stop_on_entry = match stop_on_entry {
|
||||||
|
true => ToggleState::Selected,
|
||||||
|
_ => ToggleState::Unselected,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn save_scenario(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
self.save_debug_scenario(window, cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use paths::home_dir;
|
use paths::home_dir;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use dap::DapRegistry;
|
use dap::DapRegistry;
|
||||||
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
|
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
|
||||||
use project::{FakeFs, Project};
|
use project::{FakeFs, Fs, Project};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
@ -151,6 +151,106 @@ async fn test_debug_session_substitutes_variables_and_relativizes_paths(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_save_debug_scenario_to_file(executor: BackgroundExecutor, cx: &mut TestAppContext) {
|
||||||
|
init_test(cx);
|
||||||
|
|
||||||
|
let fs = FakeFs::new(executor.clone());
|
||||||
|
fs.insert_tree(
|
||||||
|
path!("/project"),
|
||||||
|
json!({
|
||||||
|
"main.rs": "fn main() {}"
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
|
||||||
|
let workspace = init_test_workspace(&project, cx).await;
|
||||||
|
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||||
|
|
||||||
|
workspace
|
||||||
|
.update(cx, |workspace, window, cx| {
|
||||||
|
crate::new_session_modal::NewSessionModal::show(workspace, window, cx);
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
cx.run_until_parked();
|
||||||
|
|
||||||
|
let modal = workspace
|
||||||
|
.update(cx, |workspace, _, cx| {
|
||||||
|
workspace.active_modal::<crate::new_session_modal::NewSessionModal>(cx)
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.expect("Modal should be active");
|
||||||
|
|
||||||
|
modal.update_in(cx, |modal, window, cx| {
|
||||||
|
modal.set_custom("/project/main", "/project", false, window, cx);
|
||||||
|
modal.save_scenario(window, cx);
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
|
||||||
|
let debug_json_content = fs
|
||||||
|
.load(path!("/project/.zed/debug.json").as_ref())
|
||||||
|
.await
|
||||||
|
.expect("debug.json should exist");
|
||||||
|
|
||||||
|
let expected_content = vec![
|
||||||
|
"[",
|
||||||
|
" {",
|
||||||
|
r#" "adapter": "fake-adapter","#,
|
||||||
|
r#" "label": "main (fake-adapter)","#,
|
||||||
|
r#" "request": "launch","#,
|
||||||
|
r#" "program": "/project/main","#,
|
||||||
|
r#" "cwd": "/project","#,
|
||||||
|
r#" "args": [],"#,
|
||||||
|
r#" "env": {}"#,
|
||||||
|
" }",
|
||||||
|
"]",
|
||||||
|
];
|
||||||
|
|
||||||
|
let actual_lines: Vec<&str> = debug_json_content.lines().collect();
|
||||||
|
pretty_assertions::assert_eq!(expected_content, actual_lines);
|
||||||
|
|
||||||
|
modal.update_in(cx, |modal, window, cx| {
|
||||||
|
modal.set_custom("/project/other", "/project", true, window, cx);
|
||||||
|
modal.save_scenario(window, cx);
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
|
||||||
|
let debug_json_content = fs
|
||||||
|
.load(path!("/project/.zed/debug.json").as_ref())
|
||||||
|
.await
|
||||||
|
.expect("debug.json should exist after second save");
|
||||||
|
|
||||||
|
let expected_content = vec![
|
||||||
|
"[",
|
||||||
|
" {",
|
||||||
|
r#" "adapter": "fake-adapter","#,
|
||||||
|
r#" "label": "main (fake-adapter)","#,
|
||||||
|
r#" "request": "launch","#,
|
||||||
|
r#" "program": "/project/main","#,
|
||||||
|
r#" "cwd": "/project","#,
|
||||||
|
r#" "args": [],"#,
|
||||||
|
r#" "env": {}"#,
|
||||||
|
" },",
|
||||||
|
" {",
|
||||||
|
r#" "adapter": "fake-adapter","#,
|
||||||
|
r#" "label": "other (fake-adapter)","#,
|
||||||
|
r#" "request": "launch","#,
|
||||||
|
r#" "program": "/project/other","#,
|
||||||
|
r#" "cwd": "/project","#,
|
||||||
|
r#" "args": [],"#,
|
||||||
|
r#" "env": {}"#,
|
||||||
|
" }",
|
||||||
|
"]",
|
||||||
|
];
|
||||||
|
|
||||||
|
let actual_lines: Vec<&str> = debug_json_content.lines().collect();
|
||||||
|
pretty_assertions::assert_eq!(expected_content, actual_lines);
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_dap_adapter_config_conversion_and_validation(cx: &mut TestAppContext) {
|
async fn test_dap_adapter_config_conversion_and_validation(cx: &mut TestAppContext) {
|
||||||
init_test(cx);
|
init_test(cx);
|
||||||
|
|
|
@ -270,7 +270,11 @@ pub fn task_contexts(
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.worktree_for_id(*worktree_id, cx)
|
.worktree_for_id(*worktree_id, cx)
|
||||||
.map_or(false, |worktree| is_visible_directory(&worktree, cx))
|
.map_or(false, |worktree| is_visible_directory(&worktree, cx))
|
||||||
});
|
})
|
||||||
|
.or(workspace
|
||||||
|
.visible_worktrees(cx)
|
||||||
|
.next()
|
||||||
|
.map(|tree| tree.read(cx).id()));
|
||||||
|
|
||||||
let active_editor = active_item.and_then(|item| item.act_as::<Editor>(cx));
|
let active_editor = active_item.and_then(|item| item.act_as::<Editor>(cx));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue