debugger: Touchups to log breakpoints (#27675)
This is a slight refactor that flattens Breakpoint struct in anticipation of condition/hit breakpoints. It also adds a slight delay before breakpoints are shown on gutter hover to make breakpoints less attention grabbing. Release Notes: - N/A
This commit is contained in:
parent
8ecf553279
commit
f86977e2a7
8 changed files with 136 additions and 276 deletions
|
@ -11,12 +11,7 @@ use rpc::{
|
|||
proto::{self},
|
||||
AnyProtoClient, TypedEnvelope,
|
||||
};
|
||||
use std::{
|
||||
hash::{Hash, Hasher},
|
||||
ops::Range,
|
||||
path::Path,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{hash::Hash, ops::Range, path::Path, sync::Arc};
|
||||
use text::{Point, PointUtf16};
|
||||
|
||||
use crate::{buffer_store::BufferStore, worktree_store::WorktreeStore, Project, ProjectPath};
|
||||
|
@ -274,8 +269,6 @@ impl BreakpointStore {
|
|||
}
|
||||
BreakpointEditAction::EditLogMessage(log_message) => {
|
||||
if !log_message.is_empty() {
|
||||
breakpoint.1.kind = BreakpointKind::Log(log_message.clone());
|
||||
|
||||
let found_bp =
|
||||
breakpoint_set
|
||||
.breakpoints
|
||||
|
@ -289,18 +282,16 @@ impl BreakpointStore {
|
|||
});
|
||||
|
||||
if let Some(found_bp) = found_bp {
|
||||
found_bp.kind = BreakpointKind::Log(log_message.clone());
|
||||
found_bp.message = Some(log_message.clone());
|
||||
} else {
|
||||
breakpoint.1.message = Some(log_message.clone());
|
||||
// We did not remove any breakpoint, hence let's toggle one.
|
||||
breakpoint_set.breakpoints.push(breakpoint.clone());
|
||||
}
|
||||
} else if matches!(&breakpoint.1.kind, BreakpointKind::Log(_)) {
|
||||
breakpoint_set
|
||||
.breakpoints
|
||||
.retain(|(other_pos, other_kind)| {
|
||||
&breakpoint.0 != other_pos
|
||||
&& matches!(other_kind.kind, BreakpointKind::Standard)
|
||||
});
|
||||
} else if breakpoint.1.message.is_some() {
|
||||
breakpoint_set.breakpoints.retain(|(other_pos, other)| {
|
||||
&breakpoint.0 != other_pos && other.message.is_none()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -419,7 +410,7 @@ impl BreakpointStore {
|
|||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn breakpoints_from_path(&self, path: &Arc<Path>, cx: &App) -> Vec<SerializedBreakpoint> {
|
||||
pub fn breakpoints_from_path(&self, path: &Arc<Path>, cx: &App) -> Vec<SourceBreakpoint> {
|
||||
self.breakpoints
|
||||
.get(path)
|
||||
.map(|bp| {
|
||||
|
@ -428,11 +419,11 @@ impl BreakpointStore {
|
|||
.iter()
|
||||
.map(|(position, breakpoint)| {
|
||||
let position = snapshot.summary_for_anchor::<PointUtf16>(position).row;
|
||||
SerializedBreakpoint {
|
||||
position,
|
||||
SourceBreakpoint {
|
||||
row: position,
|
||||
path: path.clone(),
|
||||
kind: breakpoint.kind.clone(),
|
||||
state: breakpoint.state,
|
||||
message: breakpoint.message.clone(),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
@ -440,7 +431,7 @@ impl BreakpointStore {
|
|||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn all_breakpoints(&self, cx: &App) -> BTreeMap<Arc<Path>, Vec<SerializedBreakpoint>> {
|
||||
pub fn all_breakpoints(&self, cx: &App) -> BTreeMap<Arc<Path>, Vec<SourceBreakpoint>> {
|
||||
self.breakpoints
|
||||
.iter()
|
||||
.map(|(path, bp)| {
|
||||
|
@ -451,10 +442,10 @@ impl BreakpointStore {
|
|||
.iter()
|
||||
.map(|(position, breakpoint)| {
|
||||
let position = snapshot.summary_for_anchor::<PointUtf16>(position).row;
|
||||
SerializedBreakpoint {
|
||||
position,
|
||||
SourceBreakpoint {
|
||||
row: position,
|
||||
path: path.clone(),
|
||||
kind: breakpoint.kind.clone(),
|
||||
message: breakpoint.message.clone(),
|
||||
state: breakpoint.state,
|
||||
}
|
||||
})
|
||||
|
@ -466,7 +457,7 @@ impl BreakpointStore {
|
|||
|
||||
pub fn with_serialized_breakpoints(
|
||||
&self,
|
||||
breakpoints: BTreeMap<Arc<Path>, Vec<SerializedBreakpoint>>,
|
||||
breakpoints: BTreeMap<Arc<Path>, Vec<SourceBreakpoint>>,
|
||||
cx: &mut Context<BreakpointStore>,
|
||||
) -> Task<Result<()>> {
|
||||
if let BreakpointStoreMode::Local(mode) = &self.mode {
|
||||
|
@ -503,11 +494,11 @@ impl BreakpointStore {
|
|||
this.update(cx, |_, cx| BreakpointsInFile::new(buffer, cx))?;
|
||||
|
||||
for bp in bps {
|
||||
let position = snapshot.anchor_after(Point::new(bp.position, 0));
|
||||
let position = snapshot.anchor_after(Point::new(bp.row, 0));
|
||||
breakpoints_for_file.breakpoints.push((
|
||||
position,
|
||||
Breakpoint {
|
||||
kind: bp.kind,
|
||||
message: bp.message,
|
||||
state: bp.state,
|
||||
},
|
||||
))
|
||||
|
@ -555,42 +546,6 @@ pub enum BreakpointEditAction {
|
|||
EditLogMessage(LogMessage),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BreakpointKind {
|
||||
Standard,
|
||||
Log(LogMessage),
|
||||
}
|
||||
|
||||
impl BreakpointKind {
|
||||
pub fn to_int(&self) -> i32 {
|
||||
match self {
|
||||
BreakpointKind::Standard => 0,
|
||||
BreakpointKind::Log(_) => 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log_message(&self) -> Option<LogMessage> {
|
||||
match self {
|
||||
BreakpointKind::Standard => None,
|
||||
BreakpointKind::Log(message) => Some(message.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for BreakpointKind {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
std::mem::discriminant(self) == std::mem::discriminant(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for BreakpointKind {}
|
||||
|
||||
impl Hash for BreakpointKind {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
std::mem::discriminant(self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub enum BreakpointState {
|
||||
Enabled,
|
||||
|
@ -619,22 +574,22 @@ impl BreakpointState {
|
|||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct Breakpoint {
|
||||
pub kind: BreakpointKind,
|
||||
pub message: Option<Arc<str>>,
|
||||
pub state: BreakpointState,
|
||||
}
|
||||
|
||||
impl Breakpoint {
|
||||
pub fn new_standard() -> Self {
|
||||
Self {
|
||||
kind: BreakpointKind::Standard,
|
||||
state: BreakpointState::Enabled,
|
||||
message: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_log(log_message: &str) -> Self {
|
||||
Self {
|
||||
kind: BreakpointKind::Log(log_message.to_owned().into()),
|
||||
state: BreakpointState::Enabled,
|
||||
message: Some(log_message.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -645,30 +600,17 @@ impl Breakpoint {
|
|||
BreakpointState::Enabled => proto::BreakpointState::Enabled.into(),
|
||||
BreakpointState::Disabled => proto::BreakpointState::Disabled.into(),
|
||||
},
|
||||
kind: match self.kind {
|
||||
BreakpointKind::Standard => proto::BreakpointKind::Standard.into(),
|
||||
BreakpointKind::Log(_) => proto::BreakpointKind::Log.into(),
|
||||
},
|
||||
message: if let BreakpointKind::Log(message) = &self.kind {
|
||||
Some(message.to_string())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
message: self.message.as_ref().map(|s| String::from(s.as_ref())),
|
||||
})
|
||||
}
|
||||
|
||||
fn from_proto(breakpoint: client::proto::Breakpoint) -> Option<Self> {
|
||||
Some(Self {
|
||||
kind: match proto::BreakpointKind::from_i32(breakpoint.kind) {
|
||||
Some(proto::BreakpointKind::Log) => {
|
||||
BreakpointKind::Log(breakpoint.message.clone().unwrap_or_default().into())
|
||||
}
|
||||
None | Some(proto::BreakpointKind::Standard) => BreakpointKind::Standard,
|
||||
},
|
||||
state: match proto::BreakpointState::from_i32(breakpoint.state) {
|
||||
Some(proto::BreakpointState::Disabled) => BreakpointState::Disabled,
|
||||
None | Some(proto::BreakpointState::Enabled) => BreakpointState::Enabled,
|
||||
},
|
||||
message: breakpoint.message.map(|message| message.into()),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -683,22 +625,23 @@ impl Breakpoint {
|
|||
}
|
||||
}
|
||||
|
||||
/// Breakpoint for location within source code.
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct SerializedBreakpoint {
|
||||
pub position: u32,
|
||||
pub struct SourceBreakpoint {
|
||||
pub row: u32,
|
||||
pub path: Arc<Path>,
|
||||
pub kind: BreakpointKind,
|
||||
pub message: Option<Arc<str>>,
|
||||
pub state: BreakpointState,
|
||||
}
|
||||
|
||||
impl From<SerializedBreakpoint> for dap::SourceBreakpoint {
|
||||
fn from(bp: SerializedBreakpoint) -> Self {
|
||||
impl From<SourceBreakpoint> for dap::SourceBreakpoint {
|
||||
fn from(bp: SourceBreakpoint) -> Self {
|
||||
Self {
|
||||
line: bp.position as u64 + 1,
|
||||
line: bp.row as u64 + 1,
|
||||
column: None,
|
||||
condition: None,
|
||||
hit_condition: None,
|
||||
log_message: bp.kind.log_message().as_deref().map(Into::into),
|
||||
log_message: bp.message.map(|message| String::from(message.as_ref())),
|
||||
mode: None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,13 +16,10 @@ use dap::{
|
|||
adapters::{DapStatus, DebugAdapterName},
|
||||
client::SessionId,
|
||||
messages::Message,
|
||||
requests::{
|
||||
Completions, Evaluate, Request as _, RunInTerminal, SetExpression, SetVariable,
|
||||
StartDebugging,
|
||||
},
|
||||
requests::{Completions, Evaluate, Request as _, RunInTerminal, StartDebugging},
|
||||
Capabilities, CompletionItem, CompletionsArguments, DapRegistry, ErrorResponse,
|
||||
EvaluateArguments, EvaluateArgumentsContext, EvaluateResponse, RunInTerminalRequestArguments,
|
||||
SetExpressionArguments, SetVariableArguments, Source, StartDebuggingRequestArguments,
|
||||
Source, StartDebuggingRequestArguments,
|
||||
};
|
||||
use fs::Fs;
|
||||
use futures::{
|
||||
|
@ -710,59 +707,6 @@ impl DapStore {
|
|||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn set_variable_value(
|
||||
&self,
|
||||
session_id: &SessionId,
|
||||
stack_frame_id: u64,
|
||||
variables_reference: u64,
|
||||
name: String,
|
||||
value: String,
|
||||
evaluate_name: Option<String>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some(client) = self
|
||||
.session_by_id(session_id)
|
||||
.and_then(|client| client.read(cx).adapter_client())
|
||||
else {
|
||||
return Task::ready(Err(anyhow!("Could not find client: {:?}", session_id)));
|
||||
};
|
||||
|
||||
let supports_set_expression = self
|
||||
.capabilities_by_id(session_id, cx)
|
||||
.and_then(|caps| caps.supports_set_expression)
|
||||
.unwrap_or_default();
|
||||
|
||||
cx.background_executor().spawn(async move {
|
||||
if let Some(evaluate_name) = supports_set_expression.then(|| evaluate_name).flatten() {
|
||||
client
|
||||
.request::<SetExpression>(SetExpressionArguments {
|
||||
expression: evaluate_name,
|
||||
value,
|
||||
frame_id: Some(stack_frame_id),
|
||||
format: None,
|
||||
})
|
||||
.await?;
|
||||
} else {
|
||||
client
|
||||
.request::<SetVariable>(SetVariableArguments {
|
||||
variables_reference,
|
||||
name,
|
||||
value,
|
||||
format: None,
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
// .. get the client and what not
|
||||
// let _ = client.modules(); // This can fire a request to a dap adapter or be a cheap getter.
|
||||
// client.wait_for_request(request::Modules); // This ensures that the request that we've fired off runs to completions
|
||||
// let returned_value = client.modules(); // this is a cheap getter.
|
||||
|
||||
pub fn shutdown_sessions(&mut self, cx: &mut Context<Self>) -> Task<()> {
|
||||
let mut tasks = vec![];
|
||||
for session_id in self.sessions.keys().cloned().collect::<Vec<_>>() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue