Compare commits
14 Commits
acp-rewind
...
v0.191.1-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f19e4262b | ||
|
|
8124758685 | ||
|
|
441d738061 | ||
|
|
fa003793ed | ||
|
|
38e00a72a9 | ||
|
|
c14c370671 | ||
|
|
bc6d75b4af | ||
|
|
55d751a1c9 | ||
|
|
2562daaa6d | ||
|
|
10d00e18c9 | ||
|
|
720fe2f437 | ||
|
|
28f14093d1 | ||
|
|
ff6662052d | ||
|
|
d8d6866191 |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -19742,7 +19742,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zed"
|
||||
version = "0.191.0"
|
||||
version = "0.191.1"
|
||||
dependencies = [
|
||||
"activity_indicator",
|
||||
"agent",
|
||||
|
||||
@@ -1513,7 +1513,7 @@ impl AgentDiff {
|
||||
multibuffer.add_diff(diff_handle.clone(), cx);
|
||||
});
|
||||
|
||||
let new_state = if thread.read(cx).has_pending_edit_tool_uses() {
|
||||
let new_state = if thread.read(cx).is_generating() {
|
||||
EditorState::Generating
|
||||
} else {
|
||||
EditorState::Reviewing
|
||||
|
||||
@@ -21,18 +21,21 @@ impl CodeLldbDebugAdapter {
|
||||
|
||||
fn request_args(
|
||||
&self,
|
||||
delegate: &Arc<dyn DapDelegate>,
|
||||
task_definition: &DebugTaskDefinition,
|
||||
) -> Result<dap::StartDebuggingRequestArguments> {
|
||||
// CodeLLDB uses `name` for a terminal label.
|
||||
let mut configuration = task_definition.config.clone();
|
||||
|
||||
configuration
|
||||
let obj = configuration
|
||||
.as_object_mut()
|
||||
.context("CodeLLDB is not a valid json object")?
|
||||
.insert(
|
||||
"name".into(),
|
||||
Value::String(String::from(task_definition.label.as_ref())),
|
||||
);
|
||||
.context("CodeLLDB is not a valid json object")?;
|
||||
|
||||
obj.entry("name")
|
||||
.or_insert(Value::String(String::from(task_definition.label.as_ref())));
|
||||
|
||||
obj.entry("cwd")
|
||||
.or_insert(delegate.worktree_root_path().to_string_lossy().into());
|
||||
|
||||
let request = self.request_kind(&configuration)?;
|
||||
|
||||
@@ -365,7 +368,7 @@ impl DebugAdapter for CodeLldbDebugAdapter {
|
||||
"--settings".into(),
|
||||
json!({"sourceLanguages": ["cpp", "rust"]}).to_string(),
|
||||
],
|
||||
request_args: self.request_args(&config)?,
|
||||
request_args: self.request_args(delegate, &config)?,
|
||||
envs: HashMap::default(),
|
||||
connection: None,
|
||||
})
|
||||
|
||||
@@ -177,10 +177,12 @@ impl DebugAdapter for GdbDebugAdapter {
|
||||
|
||||
let gdb_path = user_setting_path.unwrap_or(gdb_path?);
|
||||
|
||||
let request_args = StartDebuggingRequestArguments {
|
||||
request: self.request_kind(&config.config)?,
|
||||
configuration: config.config.clone(),
|
||||
};
|
||||
let mut configuration = config.config.clone();
|
||||
if let Some(configuration) = configuration.as_object_mut() {
|
||||
configuration
|
||||
.entry("cwd")
|
||||
.or_insert_with(|| delegate.worktree_root_path().to_string_lossy().into());
|
||||
}
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
command: Some(gdb_path),
|
||||
@@ -188,7 +190,10 @@ impl DebugAdapter for GdbDebugAdapter {
|
||||
envs: HashMap::default(),
|
||||
cwd: Some(delegate.worktree_root_path().to_path_buf()),
|
||||
connection: None,
|
||||
request_args,
|
||||
request_args: StartDebuggingRequestArguments {
|
||||
request: self.request_kind(&config.config)?,
|
||||
configuration,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use anyhow::{Context as _, bail};
|
||||
use dap::{
|
||||
StartDebuggingRequestArguments,
|
||||
adapters::{
|
||||
DebugTaskDefinition, DownloadedFileType, download_adapter_from_github,
|
||||
DebugTaskDefinition, DownloadedFileType, TcpArguments, download_adapter_from_github,
|
||||
latest_github_release,
|
||||
},
|
||||
};
|
||||
@@ -10,6 +10,7 @@ use dap::{
|
||||
use gpui::{AsyncApp, SharedString};
|
||||
use language::LanguageName;
|
||||
use std::{collections::HashMap, env::consts, ffi::OsStr, path::PathBuf, sync::OnceLock};
|
||||
use task::TcpArgumentsTemplate;
|
||||
use util;
|
||||
|
||||
use crate::*;
|
||||
@@ -433,10 +434,6 @@ impl DebugAdapter for GoDebugAdapter {
|
||||
|
||||
adapter_path.join("dlv").to_string_lossy().to_string()
|
||||
};
|
||||
let minidelve_path = self.install_shim(delegate).await?;
|
||||
let tcp_connection = task_definition.tcp_connection.clone().unwrap_or_default();
|
||||
|
||||
let (host, port, _) = crate::configure_tcp_connection(tcp_connection).await?;
|
||||
|
||||
let cwd = task_definition
|
||||
.config
|
||||
@@ -445,31 +442,58 @@ impl DebugAdapter for GoDebugAdapter {
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|| delegate.worktree_root_path().to_path_buf());
|
||||
|
||||
let arguments = if cfg!(windows) {
|
||||
vec![
|
||||
delve_path,
|
||||
"dap".into(),
|
||||
"--listen".into(),
|
||||
format!("{}:{}", host, port),
|
||||
"--headless".into(),
|
||||
]
|
||||
} else {
|
||||
vec![
|
||||
delve_path,
|
||||
"dap".into(),
|
||||
"--listen".into(),
|
||||
format!("{}:{}", host, port),
|
||||
]
|
||||
};
|
||||
let arguments;
|
||||
let command;
|
||||
let connection;
|
||||
|
||||
let mut configuration = task_definition.config.clone();
|
||||
if let Some(configuration) = configuration.as_object_mut() {
|
||||
configuration
|
||||
.entry("cwd")
|
||||
.or_insert_with(|| delegate.worktree_root_path().to_string_lossy().into());
|
||||
}
|
||||
|
||||
if let Some(connection_options) = &task_definition.tcp_connection {
|
||||
command = None;
|
||||
arguments = vec![];
|
||||
let (host, port, timeout) =
|
||||
crate::configure_tcp_connection(connection_options.clone()).await?;
|
||||
connection = Some(TcpArguments {
|
||||
host,
|
||||
port,
|
||||
timeout,
|
||||
});
|
||||
} else {
|
||||
let minidelve_path = self.install_shim(delegate).await?;
|
||||
let (host, port, _) =
|
||||
crate::configure_tcp_connection(TcpArgumentsTemplate::default()).await?;
|
||||
command = Some(minidelve_path.to_string_lossy().into_owned());
|
||||
connection = None;
|
||||
arguments = if cfg!(windows) {
|
||||
vec![
|
||||
delve_path,
|
||||
"dap".into(),
|
||||
"--listen".into(),
|
||||
format!("{}:{}", host, port),
|
||||
"--headless".into(),
|
||||
]
|
||||
} else {
|
||||
vec![
|
||||
delve_path,
|
||||
"dap".into(),
|
||||
"--listen".into(),
|
||||
format!("{}:{}", host, port),
|
||||
]
|
||||
};
|
||||
}
|
||||
Ok(DebugAdapterBinary {
|
||||
command: Some(minidelve_path.to_string_lossy().into_owned()),
|
||||
command,
|
||||
arguments,
|
||||
cwd: Some(cwd),
|
||||
envs: HashMap::default(),
|
||||
connection: None,
|
||||
connection,
|
||||
request_args: StartDebuggingRequestArguments {
|
||||
configuration: task_definition.config.clone(),
|
||||
configuration,
|
||||
request: self.request_kind(&task_definition.config)?,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -2,6 +2,7 @@ use adapters::latest_github_release;
|
||||
use anyhow::Context as _;
|
||||
use dap::{StartDebuggingRequestArguments, adapters::DebugTaskDefinition};
|
||||
use gpui::AsyncApp;
|
||||
use serde_json::Value;
|
||||
use std::{collections::HashMap, path::PathBuf, sync::OnceLock};
|
||||
use task::DebugRequest;
|
||||
use util::ResultExt;
|
||||
@@ -68,6 +69,35 @@ impl JsDebugAdapter {
|
||||
let tcp_connection = task_definition.tcp_connection.clone().unwrap_or_default();
|
||||
let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
|
||||
|
||||
let mut configuration = task_definition.config.clone();
|
||||
if let Some(configuration) = configuration.as_object_mut() {
|
||||
if let Some(program) = configuration
|
||||
.get("program")
|
||||
.cloned()
|
||||
.and_then(|value| value.as_str().map(str::to_owned))
|
||||
{
|
||||
match program.as_str() {
|
||||
"npm" | "pnpm" | "yarn" | "bun"
|
||||
if !configuration.contains_key("runtimeExecutable")
|
||||
&& !configuration.contains_key("runtimeArgs") =>
|
||||
{
|
||||
configuration.remove("program");
|
||||
configuration.insert("runtimeExecutable".to_owned(), program.into());
|
||||
if let Some(args) = configuration.remove("args") {
|
||||
configuration.insert("runtimeArgs".to_owned(), args);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
configuration
|
||||
.entry("cwd")
|
||||
.or_insert(delegate.worktree_root_path().to_string_lossy().into());
|
||||
|
||||
configuration.entry("type").and_modify(normalize_task_type);
|
||||
}
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
command: Some(
|
||||
delegate
|
||||
@@ -93,7 +123,7 @@ impl JsDebugAdapter {
|
||||
timeout,
|
||||
}),
|
||||
request_args: StartDebuggingRequestArguments {
|
||||
configuration: task_definition.config.clone(),
|
||||
configuration,
|
||||
request: self.request_kind(&task_definition.config)?,
|
||||
},
|
||||
})
|
||||
@@ -173,7 +203,7 @@ impl DebugAdapter for JsDebugAdapter {
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["pwa-node", "node", "chrome", "pwa-chrome", "edge", "pwa-edge"],
|
||||
"enum": ["pwa-node", "node", "chrome", "pwa-chrome", "msedge", "pwa-msedge"],
|
||||
"description": "The type of debug session",
|
||||
"default": "pwa-node"
|
||||
},
|
||||
@@ -439,3 +469,19 @@ impl DebugAdapter for JsDebugAdapter {
|
||||
Some(label.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_task_type(task_type: &mut Value) {
|
||||
let Some(task_type_str) = task_type.as_str() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let new_name = match task_type_str {
|
||||
"node" | "pwa-node" => "pwa-node",
|
||||
"chrome" | "pwa-chrome" => "pwa-chrome",
|
||||
"edge" | "msedge" | "pwa-edge" | "pwa-msedge" => "pwa-msedge",
|
||||
_ => task_type_str,
|
||||
}
|
||||
.to_owned();
|
||||
|
||||
*task_type = Value::String(new_name);
|
||||
}
|
||||
|
||||
@@ -71,6 +71,12 @@ impl PhpDebugAdapter {
|
||||
let tcp_connection = task_definition.tcp_connection.clone().unwrap_or_default();
|
||||
let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
|
||||
|
||||
let mut configuration = task_definition.config.clone();
|
||||
if let Some(obj) = configuration.as_object_mut() {
|
||||
obj.entry("cwd")
|
||||
.or_insert_with(|| delegate.worktree_root_path().to_string_lossy().into());
|
||||
}
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
command: Some(
|
||||
delegate
|
||||
@@ -95,7 +101,7 @@ impl PhpDebugAdapter {
|
||||
cwd: Some(delegate.worktree_root_path().to_path_buf()),
|
||||
envs: HashMap::default(),
|
||||
request_args: StartDebuggingRequestArguments {
|
||||
configuration: task_definition.config.clone(),
|
||||
configuration,
|
||||
request: <Self as DebugAdapter>::request_kind(self, &task_definition.config)?,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -83,6 +83,7 @@ impl PythonDebugAdapter {
|
||||
|
||||
fn request_args(
|
||||
&self,
|
||||
delegate: &Arc<dyn DapDelegate>,
|
||||
task_definition: &DebugTaskDefinition,
|
||||
) -> Result<StartDebuggingRequestArguments> {
|
||||
let request = self.request_kind(&task_definition.config)?;
|
||||
@@ -95,6 +96,11 @@ impl PythonDebugAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(obj) = configuration.as_object_mut() {
|
||||
obj.entry("cwd")
|
||||
.or_insert(delegate.worktree_root_path().to_string_lossy().into());
|
||||
}
|
||||
|
||||
Ok(StartDebuggingRequestArguments {
|
||||
configuration,
|
||||
request,
|
||||
@@ -196,7 +202,7 @@ impl PythonDebugAdapter {
|
||||
}),
|
||||
cwd: Some(delegate.worktree_root_path().to_path_buf()),
|
||||
envs: HashMap::default(),
|
||||
request_args: self.request_args(config)?,
|
||||
request_args: self.request_args(delegate, config)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,13 @@ impl DebugAdapter for RubyDebugAdapter {
|
||||
|
||||
arguments.extend(ruby_config.args);
|
||||
|
||||
let mut configuration = definition.config.clone();
|
||||
if let Some(configuration) = configuration.as_object_mut() {
|
||||
configuration
|
||||
.entry("cwd")
|
||||
.or_insert_with(|| delegate.worktree_root_path().to_string_lossy().into());
|
||||
}
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
command: Some(rdbg_path.to_string_lossy().to_string()),
|
||||
arguments,
|
||||
@@ -190,7 +197,7 @@ impl DebugAdapter for RubyDebugAdapter {
|
||||
envs: ruby_config.env.into_iter().collect(),
|
||||
request_args: StartDebuggingRequestArguments {
|
||||
request: self.request_kind(&definition.config)?,
|
||||
configuration: definition.config.clone(),
|
||||
configuration,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -179,6 +179,19 @@ impl DebugPanel {
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let worktree = worktree_id.or_else(|| {
|
||||
active_buffer
|
||||
.as_ref()
|
||||
.and_then(|buffer| buffer.read(cx).file())
|
||||
.map(|f| f.worktree_id(cx))
|
||||
});
|
||||
let Some(worktree) = worktree
|
||||
.and_then(|id| self.project.read(cx).worktree_for_id(id, cx))
|
||||
.or_else(|| self.project.read(cx).visible_worktrees(cx).next())
|
||||
else {
|
||||
log::debug!("Could not find a worktree to spawn the debug session in");
|
||||
return;
|
||||
};
|
||||
self.debug_scenario_scheduled_last = true;
|
||||
if let Some(inventory) = self
|
||||
.project
|
||||
@@ -213,7 +226,7 @@ impl DebugPanel {
|
||||
.await?;
|
||||
dap_store
|
||||
.update(cx, |dap_store, cx| {
|
||||
dap_store.boot_session(session.clone(), definition, cx)
|
||||
dap_store.boot_session(session.clone(), definition, worktree, cx)
|
||||
})?
|
||||
.await
|
||||
}
|
||||
@@ -336,8 +349,26 @@ impl DebugPanel {
|
||||
});
|
||||
(session, task)
|
||||
})?;
|
||||
Self::register_session(this.clone(), session, true, cx).await?;
|
||||
task.await
|
||||
Self::register_session(this.clone(), session.clone(), true, cx).await?;
|
||||
|
||||
if let Err(error) = task.await {
|
||||
session
|
||||
.update(cx, |session, cx| {
|
||||
session
|
||||
.console_output(cx)
|
||||
.unbounded_send(format!(
|
||||
"Session failed to restart with error: {}",
|
||||
error
|
||||
))
|
||||
.ok();
|
||||
session.shutdown(cx)
|
||||
})?
|
||||
.await;
|
||||
|
||||
return Err(error);
|
||||
};
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
@@ -111,7 +111,6 @@ pub fn init(cx: &mut App) {
|
||||
}
|
||||
|
||||
let caps = running_state.capabilities(cx);
|
||||
let supports_restart = caps.supports_restart_request.unwrap_or_default();
|
||||
let supports_step_back = caps.supports_step_back.unwrap_or_default();
|
||||
let supports_detach = running_state.session().read(cx).is_attached();
|
||||
let status = running_state.thread_status(cx);
|
||||
@@ -204,13 +203,13 @@ pub fn init(cx: &mut App) {
|
||||
.ok();
|
||||
})
|
||||
})
|
||||
.when(supports_restart, |div| {
|
||||
.on_action({
|
||||
let active_item = active_item.clone();
|
||||
div.on_action(move |_: &Restart, _, cx| {
|
||||
move |_: &Restart, _, cx| {
|
||||
active_item
|
||||
.update(cx, |item, cx| item.restart_session(cx))
|
||||
.ok();
|
||||
})
|
||||
}
|
||||
})
|
||||
.on_action({
|
||||
let active_item = active_item.clone();
|
||||
|
||||
@@ -477,10 +477,9 @@ impl NewProcessModal {
|
||||
.get_index_of(adapter.0.as_ref())
|
||||
.unwrap_or(usize::MAX)
|
||||
});
|
||||
}
|
||||
|
||||
if self.debugger.is_none() {
|
||||
self.debugger = available_adapters.first().cloned();
|
||||
if self.debugger.is_none() {
|
||||
self.debugger = available_adapters.first().cloned();
|
||||
}
|
||||
}
|
||||
|
||||
let label = self
|
||||
@@ -1169,15 +1168,35 @@ impl DebugDelegate {
|
||||
}
|
||||
|
||||
let dap_registry = cx.global::<DapRegistry>();
|
||||
let hide_vscode = scenarios.iter().any(|(kind, _)| match kind {
|
||||
TaskSourceKind::Worktree {
|
||||
id: _,
|
||||
directory_in_worktree: dir,
|
||||
id_base: _,
|
||||
} => dir.ends_with(".zed"),
|
||||
_ => false,
|
||||
});
|
||||
|
||||
self.candidates = recent
|
||||
.into_iter()
|
||||
.map(|scenario| Self::get_scenario_kind(&languages, &dap_registry, scenario))
|
||||
.chain(scenarios.into_iter().map(|(kind, scenario)| {
|
||||
let (language, scenario) =
|
||||
Self::get_scenario_kind(&languages, &dap_registry, scenario);
|
||||
(language.or(Some(kind)), scenario)
|
||||
}))
|
||||
.chain(
|
||||
scenarios
|
||||
.into_iter()
|
||||
.filter(|(kind, _)| match kind {
|
||||
TaskSourceKind::Worktree {
|
||||
id: _,
|
||||
directory_in_worktree: dir,
|
||||
id_base: _,
|
||||
} => !(hide_vscode && dir.ends_with(".vscode")),
|
||||
_ => true,
|
||||
})
|
||||
.map(|(kind, scenario)| {
|
||||
let (language, scenario) =
|
||||
Self::get_scenario_kind(&languages, &dap_registry, scenario);
|
||||
(language.or(Some(kind)), scenario)
|
||||
}),
|
||||
)
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
@@ -1514,40 +1533,3 @@ pub(crate) fn resolve_path(path: &mut String) {
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl NewProcessModal {
|
||||
// #[cfg(test)]
|
||||
// pub(crate) fn set_configure(
|
||||
// &mut self,
|
||||
// program: impl AsRef<str>,
|
||||
// cwd: impl AsRef<str>,
|
||||
// stop_on_entry: bool,
|
||||
// window: &mut Window,
|
||||
// cx: &mut Context<Self>,
|
||||
// ) {
|
||||
// self.mode = NewProcessMode::Launch;
|
||||
// self.debugger = Some(dap::adapters::DebugAdapterName("fake-adapter".into()));
|
||||
|
||||
// self.launch_mode.update(cx, |configure, cx| {
|
||||
// configure.program.update(cx, |editor, cx| {
|
||||
// editor.clear(window, cx);
|
||||
// editor.set_text(program.as_ref(), window, cx);
|
||||
// });
|
||||
|
||||
// configure.cwd.update(cx, |editor, cx| {
|
||||
// editor.clear(window, cx);
|
||||
// editor.set_text(cwd.as_ref(), window, cx);
|
||||
// });
|
||||
|
||||
// configure.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);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ use core_video::pixel_buffer::CVPixelBuffer;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use futures::FutureExt;
|
||||
use futures::channel::oneshot;
|
||||
use itertools::FoldWhile::{Continue, Done};
|
||||
use itertools::Itertools;
|
||||
use parking_lot::RwLock;
|
||||
use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
|
||||
use refineable::Refineable;
|
||||
@@ -408,7 +410,7 @@ pub(crate) type AnyMouseListener =
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct CursorStyleRequest {
|
||||
pub(crate) hitbox_id: HitboxId,
|
||||
pub(crate) hitbox_id: Option<HitboxId>,
|
||||
pub(crate) style: CursorStyle,
|
||||
}
|
||||
|
||||
@@ -622,7 +624,6 @@ pub(crate) struct Frame {
|
||||
pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
|
||||
pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
|
||||
pub(crate) cursor_styles: Vec<CursorStyleRequest>,
|
||||
window_cursor_style: Option<CursorStyle>,
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
|
||||
#[cfg(any(feature = "inspector", debug_assertions))]
|
||||
@@ -667,7 +668,6 @@ impl Frame {
|
||||
input_handlers: Vec::new(),
|
||||
tooltip_requests: Vec::new(),
|
||||
cursor_styles: Vec::new(),
|
||||
window_cursor_style: None,
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
debug_bounds: FxHashMap::default(),
|
||||
@@ -693,7 +693,6 @@ impl Frame {
|
||||
self.window_control_hitboxes.clear();
|
||||
self.deferred_draws.clear();
|
||||
self.focus = None;
|
||||
self.window_cursor_style = None;
|
||||
|
||||
#[cfg(any(feature = "inspector", debug_assertions))]
|
||||
{
|
||||
@@ -703,14 +702,16 @@ impl Frame {
|
||||
}
|
||||
|
||||
pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
|
||||
self.window_cursor_style.or_else(|| {
|
||||
self.cursor_styles.iter().rev().find_map(|request| {
|
||||
request
|
||||
.hitbox_id
|
||||
.is_hovered(window)
|
||||
.then_some(request.style)
|
||||
self.cursor_styles
|
||||
.iter()
|
||||
.rev()
|
||||
.fold_while(None, |style, request| match request.hitbox_id {
|
||||
None => Done(Some(request.style)),
|
||||
Some(hitbox_id) => Continue(
|
||||
style.or_else(|| hitbox_id.is_hovered(window).then_some(request.style)),
|
||||
),
|
||||
})
|
||||
})
|
||||
.into_inner()
|
||||
}
|
||||
|
||||
pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
|
||||
@@ -2174,7 +2175,7 @@ impl Window {
|
||||
pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
|
||||
self.invalidator.debug_assert_paint();
|
||||
self.next_frame.cursor_styles.push(CursorStyleRequest {
|
||||
hitbox_id: hitbox.id,
|
||||
hitbox_id: Some(hitbox.id),
|
||||
style,
|
||||
});
|
||||
}
|
||||
@@ -2185,7 +2186,10 @@ impl Window {
|
||||
/// phase of element drawing.
|
||||
pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
|
||||
self.invalidator.debug_assert_paint();
|
||||
self.next_frame.window_cursor_style = Some(style);
|
||||
self.next_frame.cursor_styles.push(CursorStyleRequest {
|
||||
hitbox_id: None,
|
||||
style,
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets a tooltip to be rendered for the upcoming frame. This method should only be called
|
||||
|
||||
@@ -841,7 +841,7 @@ impl BreakpointStore {
|
||||
} else {
|
||||
"breakpoint"
|
||||
};
|
||||
log::info!("Deserialized {count} {breakpoint_str} at path: {path}");
|
||||
log::debug!("Deserialized {count} {breakpoint_str} at path: {path}");
|
||||
}
|
||||
|
||||
this.breakpoints = new_breakpoints;
|
||||
|
||||
@@ -180,15 +180,12 @@ impl DapStore {
|
||||
&mut self,
|
||||
definition: DebugTaskDefinition,
|
||||
session_id: SessionId,
|
||||
worktree: &Entity<Worktree>,
|
||||
console: UnboundedSender<String>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<DebugAdapterBinary>> {
|
||||
match &self.mode {
|
||||
DapStoreMode::Local(_) => {
|
||||
let Some(worktree) = self.worktree_store.read(cx).visible_worktrees(cx).next()
|
||||
else {
|
||||
return Task::ready(Err(anyhow!("Failed to find a worktree")));
|
||||
};
|
||||
let Some(adapter) = DapRegistry::global(cx).adapter(&definition.adapter) else {
|
||||
return Task::ready(Err(anyhow!("Failed to find a debug adapter")));
|
||||
};
|
||||
@@ -229,6 +226,7 @@ impl DapStore {
|
||||
let request = ssh.upstream_client.request(proto::GetDebugAdapterBinary {
|
||||
session_id: session_id.to_proto(),
|
||||
project_id: ssh.upstream_project_id,
|
||||
worktree_id: worktree.read(cx).id().to_proto(),
|
||||
definition: Some(definition.to_proto()),
|
||||
});
|
||||
let ssh_client = ssh.ssh_client.clone();
|
||||
@@ -401,12 +399,9 @@ impl DapStore {
|
||||
&self,
|
||||
session: Entity<Session>,
|
||||
definition: DebugTaskDefinition,
|
||||
worktree: Entity<Worktree>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some(worktree) = self.worktree_store.read(cx).visible_worktrees(cx).next() else {
|
||||
return Task::ready(Err(anyhow!("Failed to find a worktree")));
|
||||
};
|
||||
|
||||
let dap_store = cx.weak_entity();
|
||||
let console = session.update(cx, |session, cx| session.console_output(cx));
|
||||
let session_id = session.read(cx).session_id();
|
||||
@@ -416,7 +411,13 @@ impl DapStore {
|
||||
async move |this, cx| {
|
||||
let binary = this
|
||||
.update(cx, |this, cx| {
|
||||
this.get_debug_adapter_binary(definition.clone(), session_id, console, cx)
|
||||
this.get_debug_adapter_binary(
|
||||
definition.clone(),
|
||||
session_id,
|
||||
&worktree,
|
||||
console,
|
||||
cx,
|
||||
)
|
||||
})?
|
||||
.await?;
|
||||
session
|
||||
@@ -780,9 +781,22 @@ impl DapStore {
|
||||
})
|
||||
.detach();
|
||||
|
||||
let worktree = this
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.worktree_store
|
||||
.read(cx)
|
||||
.worktree_for_id(WorktreeId::from_proto(envelope.payload.worktree_id), cx)
|
||||
})?
|
||||
.context("Failed to find worktree with a given ID")?;
|
||||
let binary = this
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.get_debug_adapter_binary(definition, SessionId::from_proto(session_id), tx, cx)
|
||||
this.get_debug_adapter_binary(
|
||||
definition,
|
||||
SessionId::from_proto(session_id),
|
||||
&worktree,
|
||||
tx,
|
||||
cx,
|
||||
)
|
||||
})?
|
||||
.await?;
|
||||
Ok(binary.to_proto())
|
||||
|
||||
@@ -412,8 +412,7 @@ impl Inventory {
|
||||
let fs = self.fs.clone();
|
||||
let worktree = task_contexts.worktree();
|
||||
let location = task_contexts.location();
|
||||
let language = location
|
||||
.and_then(|location| location.buffer.read(cx).language_at(location.range.start));
|
||||
let language = location.and_then(|location| location.buffer.read(cx).language());
|
||||
let task_source_kind = language.as_ref().map(|language| TaskSourceKind::Language {
|
||||
name: language.name().into(),
|
||||
});
|
||||
@@ -720,20 +719,37 @@ impl Inventory {
|
||||
}
|
||||
};
|
||||
|
||||
let new_templates = raw_tasks.into_iter().filter_map(|raw_template| {
|
||||
serde_json::from_value::<DebugScenario>(raw_template).log_err()
|
||||
});
|
||||
let new_templates = raw_tasks
|
||||
.into_iter()
|
||||
.filter_map(|raw_template| {
|
||||
serde_json::from_value::<DebugScenario>(raw_template).log_err()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let parsed_scenarios = &mut self.scenarios_from_settings;
|
||||
let mut new_definitions: HashMap<_, _> = new_templates
|
||||
.iter()
|
||||
.map(|template| (template.label.clone(), template.clone()))
|
||||
.collect();
|
||||
let previously_existing_scenarios;
|
||||
|
||||
match location {
|
||||
TaskSettingsLocation::Global(path) => {
|
||||
previously_existing_scenarios = parsed_scenarios
|
||||
.global_scenarios()
|
||||
.map(|(_, scenario)| scenario.label.clone())
|
||||
.collect::<HashSet<_>>();
|
||||
parsed_scenarios
|
||||
.global
|
||||
.entry(path.to_owned())
|
||||
.insert_entry(new_templates.collect());
|
||||
.insert_entry(new_templates);
|
||||
}
|
||||
TaskSettingsLocation::Worktree(location) => {
|
||||
let new_templates = new_templates.collect::<Vec<_>>();
|
||||
previously_existing_scenarios = parsed_scenarios
|
||||
.worktree_scenarios(location.worktree_id)
|
||||
.map(|(_, scenario)| scenario.label.clone())
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
if new_templates.is_empty() {
|
||||
if let Some(worktree_tasks) =
|
||||
parsed_scenarios.worktree.get_mut(&location.worktree_id)
|
||||
@@ -749,6 +765,17 @@ impl Inventory {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.last_scheduled_scenarios.retain_mut(|scenario| {
|
||||
if !previously_existing_scenarios.contains(&scenario.label) {
|
||||
return true;
|
||||
}
|
||||
if let Some(new_definition) = new_definitions.remove(&scenario.label) {
|
||||
*scenario = new_definition;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1243,6 +1270,99 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_reloading_debug_scenarios(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
let fs = FakeFs::new(cx.executor());
|
||||
let inventory = cx.update(|cx| Inventory::new(fs, cx));
|
||||
inventory.update(cx, |inventory, cx| {
|
||||
inventory
|
||||
.update_file_based_scenarios(
|
||||
TaskSettingsLocation::Global(Path::new("")),
|
||||
Some(
|
||||
r#"
|
||||
[{
|
||||
"label": "test scenario",
|
||||
"adapter": "CodeLLDB",
|
||||
"request": "launch",
|
||||
"program": "wowzer",
|
||||
}]
|
||||
"#,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (_, scenario) = inventory
|
||||
.list_debug_scenarios(&TaskContexts::default(), vec![], vec![], false, cx)
|
||||
.1
|
||||
.first()
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
inventory.scenario_scheduled(scenario.clone());
|
||||
|
||||
assert_eq!(
|
||||
inventory
|
||||
.list_debug_scenarios(&TaskContexts::default(), vec![], vec![], false, cx)
|
||||
.0
|
||||
.first()
|
||||
.unwrap()
|
||||
.clone(),
|
||||
scenario
|
||||
);
|
||||
|
||||
inventory
|
||||
.update_file_based_scenarios(
|
||||
TaskSettingsLocation::Global(Path::new("")),
|
||||
Some(
|
||||
r#"
|
||||
[{
|
||||
"label": "test scenario",
|
||||
"adapter": "Delve",
|
||||
"request": "launch",
|
||||
"program": "wowzer",
|
||||
}]
|
||||
"#,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
inventory
|
||||
.list_debug_scenarios(&TaskContexts::default(), vec![], vec![], false, cx)
|
||||
.0
|
||||
.first()
|
||||
.unwrap()
|
||||
.adapter,
|
||||
"Delve",
|
||||
);
|
||||
|
||||
inventory
|
||||
.update_file_based_scenarios(
|
||||
TaskSettingsLocation::Global(Path::new("")),
|
||||
Some(
|
||||
r#"
|
||||
[{
|
||||
"label": "testing scenario",
|
||||
"adapter": "Delve",
|
||||
"request": "launch",
|
||||
"program": "wowzer",
|
||||
}]
|
||||
"#,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
inventory
|
||||
.list_debug_scenarios(&TaskContexts::default(), vec![], vec![], false, cx)
|
||||
.0
|
||||
.first(),
|
||||
None
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_inventory_static_task_filters(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
@@ -493,6 +493,7 @@ message GetDebugAdapterBinary {
|
||||
uint64 project_id = 1;
|
||||
uint64 session_id = 3;
|
||||
DebugTaskDefinition definition = 2;
|
||||
uint64 worktree_id = 4;
|
||||
}
|
||||
|
||||
message DebugAdapterBinary {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use collections::HashMap;
|
||||
use gpui::SharedString;
|
||||
use serde::Deserialize;
|
||||
use util::ResultExt as _;
|
||||
|
||||
@@ -20,40 +19,32 @@ enum Request {
|
||||
struct VsCodeDebugTaskDefinition {
|
||||
r#type: String,
|
||||
name: String,
|
||||
request: Request,
|
||||
|
||||
#[serde(default)]
|
||||
program: Option<String>,
|
||||
#[serde(default)]
|
||||
args: Vec<String>,
|
||||
#[serde(default)]
|
||||
env: HashMap<String, Option<String>>,
|
||||
// TODO envFile?
|
||||
#[serde(default)]
|
||||
cwd: Option<String>,
|
||||
#[serde(default)]
|
||||
port: Option<u16>,
|
||||
#[serde(default)]
|
||||
stop_on_entry: Option<bool>,
|
||||
#[serde(flatten)]
|
||||
other_attributes: serde_json::Value,
|
||||
}
|
||||
|
||||
impl VsCodeDebugTaskDefinition {
|
||||
fn try_to_zed(self, replacer: &EnvVariableReplacer) -> anyhow::Result<DebugScenario> {
|
||||
let label = replacer.replace(&self.name).into();
|
||||
// TODO based on grep.app results it seems that vscode supports whitespace-splitting this field (ugh)
|
||||
let label = replacer.replace(&self.name);
|
||||
let mut config = replacer.replace_value(self.other_attributes);
|
||||
let adapter = task_type_to_adapter_name(&self.r#type);
|
||||
if let Some(config) = config.as_object_mut() {
|
||||
if adapter == "JavaScript" {
|
||||
config.insert("type".to_owned(), self.r#type.clone().into());
|
||||
}
|
||||
}
|
||||
let definition = DebugScenario {
|
||||
label,
|
||||
label: label.into(),
|
||||
build: None,
|
||||
adapter: task_type_to_adapter_name(&self.r#type),
|
||||
// TODO host?
|
||||
adapter: adapter.into(),
|
||||
tcp_connection: self.port.map(|port| TcpArgumentsTemplate {
|
||||
port: Some(port),
|
||||
host: None,
|
||||
timeout: None,
|
||||
}),
|
||||
config: replacer.replace_value(self.other_attributes),
|
||||
config,
|
||||
};
|
||||
Ok(definition)
|
||||
}
|
||||
@@ -62,7 +53,8 @@ impl VsCodeDebugTaskDefinition {
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct VsCodeDebugTaskFile {
|
||||
version: String,
|
||||
#[serde(default)]
|
||||
version: Option<String>,
|
||||
configurations: Vec<VsCodeDebugTaskDefinition>,
|
||||
}
|
||||
|
||||
@@ -75,7 +67,11 @@ impl TryFrom<VsCodeDebugTaskFile> for DebugTaskFile {
|
||||
"workspaceFolder".to_owned(),
|
||||
VariableName::WorktreeRoot.to_string(),
|
||||
),
|
||||
("file".to_owned(), VariableName::Filename.to_string()), // TODO other interesting variables?
|
||||
(
|
||||
"relativeFile".to_owned(),
|
||||
VariableName::RelativeFile.to_string(),
|
||||
),
|
||||
("file".to_owned(), VariableName::File.to_string()),
|
||||
]));
|
||||
let templates = file
|
||||
.configurations
|
||||
@@ -86,10 +82,10 @@ impl TryFrom<VsCodeDebugTaskFile> for DebugTaskFile {
|
||||
}
|
||||
}
|
||||
|
||||
// todo(debugger) figure out how to make JsDebugAdapter::ADAPTER_NAME et al available here
|
||||
fn task_type_to_adapter_name(task_type: &str) -> SharedString {
|
||||
fn task_type_to_adapter_name(task_type: &str) -> String {
|
||||
match task_type {
|
||||
"node" => "JavaScript",
|
||||
"pwa-node" | "node" | "chrome" | "pwa-chrome" | "edge" | "pwa-edge" | "msedge"
|
||||
| "pwa-msedge" => "JavaScript",
|
||||
"go" => "Delve",
|
||||
"php" => "PHP",
|
||||
"cppdbg" | "lldb" => "CodeLLDB",
|
||||
@@ -98,7 +94,6 @@ fn task_type_to_adapter_name(task_type: &str) -> SharedString {
|
||||
_ => task_type,
|
||||
}
|
||||
.to_owned()
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -141,7 +136,19 @@ mod tests {
|
||||
label: "Debug my JS app".into(),
|
||||
adapter: "JavaScript".into(),
|
||||
config: json!({
|
||||
"request": "launch",
|
||||
"program": "${ZED_WORKTREE_ROOT}/xyz.js",
|
||||
"showDevDebugOutput": false,
|
||||
"stopOnEntry": true,
|
||||
"args": [
|
||||
"--foo",
|
||||
"${ZED_WORKTREE_ROOT}/thing",
|
||||
],
|
||||
"cwd": "${ZED_WORKTREE_ROOT}/${FOO}/sub",
|
||||
"env": {
|
||||
"X": "Y",
|
||||
},
|
||||
"type": "node",
|
||||
}),
|
||||
tcp_connection: Some(TcpArgumentsTemplate {
|
||||
port: Some(17),
|
||||
|
||||
@@ -285,10 +285,12 @@ pub fn task_contexts(
|
||||
.worktree_for_id(*worktree_id, cx)
|
||||
.map_or(false, |worktree| is_visible_directory(&worktree, cx))
|
||||
})
|
||||
.or(workspace
|
||||
.visible_worktrees(cx)
|
||||
.next()
|
||||
.map(|tree| tree.read(cx).id()));
|
||||
.or_else(|| {
|
||||
workspace
|
||||
.visible_worktrees(cx)
|
||||
.next()
|
||||
.map(|tree| tree.read(cx).id())
|
||||
});
|
||||
|
||||
let active_editor = active_item.and_then(|item| item.act_as::<Editor>(cx));
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
description = "The fast, collaborative code editor."
|
||||
edition.workspace = true
|
||||
name = "zed"
|
||||
version = "0.191.0"
|
||||
version = "0.191.1"
|
||||
publish.workspace = true
|
||||
license = "GPL-3.0-or-later"
|
||||
authors = ["Zed Team <hi@zed.dev>"]
|
||||
|
||||
@@ -1 +1 @@
|
||||
dev
|
||||
preview
|
||||
@@ -281,7 +281,7 @@ Given an externally-ran web server (e.g. with `npx serve` or `npx live-server`)
|
||||
#### Go
|
||||
|
||||
Zed uses [delve](https://github.com/go-delve/delve?tab=readme-ov-file) to debug Go applications. Zed will automatically create debug scenarios for `func main` in your main packages, and also
|
||||
for any tests, so you can use the Play button in the gutter to debug these without configuration. We do not yet support attaching to an existing running copy of delve.
|
||||
for any tests, so you can use the Play button in the gutter to debug these without configuration.
|
||||
|
||||
##### Debug Go Packages
|
||||
|
||||
@@ -350,6 +350,27 @@ and the "build" command should build that.
|
||||
}
|
||||
```
|
||||
|
||||
##### Attaching to an existing instance of Delve
|
||||
|
||||
You might find yourself needing to connect to an existing instance of Delve that's not necessarily running on your machine; in such case, you can use `tcp_arguments` to instrument Zed's connection to Delve.
|
||||
|
||||
````
|
||||
{
|
||||
"adapter": "Delve",
|
||||
"label": "Connect to a running Delve instance",
|
||||
"program": "/Users/zed/Projects/language_repositories/golang/hello/hello",
|
||||
"cwd": "/Users/zed/Projects/language_repositories/golang/hello",
|
||||
"args": [],
|
||||
"env": {},
|
||||
"request": "launch",
|
||||
"mode": "exec",
|
||||
"stopOnEntry": false,
|
||||
"tcp_connection": { "host": "123.456.789.012", "port": 53412 }
|
||||
}
|
||||
```
|
||||
|
||||
In such case Zed won't spawn a new instance of Delve, as it opts to use an existing one. The consequence of this is that *there will be no terminal* in Zed; you have to interact with the Delve instance directly, as it handles stdin/stdout of the debuggee.
|
||||
|
||||
### Ruby
|
||||
|
||||
To run a ruby task in the debugger, you will need to configure it in the `.zed/debug.json` file in your project. We don't yet have automatic detection of ruby tasks, nor do we support connecting to an existing process.
|
||||
@@ -371,7 +392,7 @@ The configuration should look like this:
|
||||
// "cwd": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
## Breakpoints
|
||||
|
||||
|
||||
Reference in New Issue
Block a user