Debugger: Add conditional and hit conditional breakpoint functionality (#27760)
This PR adds conditional and hit condition breakpoint functionality cc @osiewicz Co-authored-by: Remco Smits: <djsmits12@gmail.com> Release Notes: - N/A *or* Added/Fixed/Improved ... --------- Co-authored-by: Remco Smits <djsmits12@gmail.com>
This commit is contained in:
parent
dc64ec9cc8
commit
d517a212dc
6 changed files with 368 additions and 50 deletions
|
@ -294,6 +294,60 @@ impl BreakpointStore {
|
|||
})
|
||||
}
|
||||
}
|
||||
BreakpointEditAction::EditHitCondition(hit_condition) => {
|
||||
if !hit_condition.is_empty() {
|
||||
let found_bp =
|
||||
breakpoint_set
|
||||
.breakpoints
|
||||
.iter_mut()
|
||||
.find_map(|(other_pos, other_bp)| {
|
||||
if breakpoint.0 == *other_pos {
|
||||
Some(other_bp)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(found_bp) = found_bp {
|
||||
found_bp.hit_condition = Some(hit_condition.clone());
|
||||
} else {
|
||||
breakpoint.1.hit_condition = Some(hit_condition.clone());
|
||||
// We did not remove any breakpoint, hence let's toggle one.
|
||||
breakpoint_set.breakpoints.push(breakpoint.clone());
|
||||
}
|
||||
} else if breakpoint.1.hit_condition.is_some() {
|
||||
breakpoint_set.breakpoints.retain(|(other_pos, other)| {
|
||||
&breakpoint.0 != other_pos && other.hit_condition.is_none()
|
||||
})
|
||||
}
|
||||
}
|
||||
BreakpointEditAction::EditCondition(condition) => {
|
||||
if !condition.is_empty() {
|
||||
let found_bp =
|
||||
breakpoint_set
|
||||
.breakpoints
|
||||
.iter_mut()
|
||||
.find_map(|(other_pos, other_bp)| {
|
||||
if breakpoint.0 == *other_pos {
|
||||
Some(other_bp)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(found_bp) = found_bp {
|
||||
found_bp.condition = Some(condition.clone());
|
||||
} else {
|
||||
breakpoint.1.condition = Some(condition.clone());
|
||||
// We did not remove any breakpoint, hence let's toggle one.
|
||||
breakpoint_set.breakpoints.push(breakpoint.clone());
|
||||
}
|
||||
} else if breakpoint.1.condition.is_some() {
|
||||
breakpoint_set.breakpoints.retain(|(other_pos, other)| {
|
||||
&breakpoint.0 != other_pos && other.condition.is_none()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if breakpoint_set.breakpoints.is_empty() {
|
||||
|
@ -424,6 +478,8 @@ impl BreakpointStore {
|
|||
path: path.clone(),
|
||||
state: breakpoint.state,
|
||||
message: breakpoint.message.clone(),
|
||||
condition: breakpoint.condition.clone(),
|
||||
hit_condition: breakpoint.hit_condition.clone(),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
@ -447,6 +503,8 @@ impl BreakpointStore {
|
|||
path: path.clone(),
|
||||
message: breakpoint.message.clone(),
|
||||
state: breakpoint.state,
|
||||
hit_condition: breakpoint.hit_condition.clone(),
|
||||
condition: breakpoint.condition.clone(),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
|
@ -500,6 +558,8 @@ impl BreakpointStore {
|
|||
Breakpoint {
|
||||
message: bp.message,
|
||||
state: bp.state,
|
||||
condition: bp.condition,
|
||||
hit_condition: bp.hit_condition,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
@ -537,13 +597,15 @@ pub enum BreakpointStoreEvent {
|
|||
|
||||
impl EventEmitter<BreakpointStoreEvent> for BreakpointStore {}
|
||||
|
||||
type LogMessage = Arc<str>;
|
||||
type BreakpointMessage = Arc<str>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BreakpointEditAction {
|
||||
Toggle,
|
||||
InvertState,
|
||||
EditLogMessage(LogMessage),
|
||||
EditLogMessage(BreakpointMessage),
|
||||
EditCondition(BreakpointMessage),
|
||||
EditHitCondition(BreakpointMessage),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
|
@ -574,7 +636,10 @@ impl BreakpointState {
|
|||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct Breakpoint {
|
||||
pub message: Option<Arc<str>>,
|
||||
pub message: Option<BreakpointMessage>,
|
||||
/// How many times do we hit the breakpoint until we actually stop at it e.g. (2 = 2 times of the breakpoint action)
|
||||
pub hit_condition: Option<BreakpointMessage>,
|
||||
pub condition: Option<BreakpointMessage>,
|
||||
pub state: BreakpointState,
|
||||
}
|
||||
|
||||
|
@ -582,6 +647,17 @@ impl Breakpoint {
|
|||
pub fn new_standard() -> Self {
|
||||
Self {
|
||||
state: BreakpointState::Enabled,
|
||||
hit_condition: None,
|
||||
condition: None,
|
||||
message: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_condition(hit_condition: &str) -> Self {
|
||||
Self {
|
||||
state: BreakpointState::Enabled,
|
||||
condition: None,
|
||||
hit_condition: Some(hit_condition.into()),
|
||||
message: None,
|
||||
}
|
||||
}
|
||||
|
@ -589,6 +665,8 @@ impl Breakpoint {
|
|||
pub fn new_log(log_message: &str) -> Self {
|
||||
Self {
|
||||
state: BreakpointState::Enabled,
|
||||
hit_condition: None,
|
||||
condition: None,
|
||||
message: Some(log_message.into()),
|
||||
}
|
||||
}
|
||||
|
@ -601,6 +679,11 @@ impl Breakpoint {
|
|||
BreakpointState::Disabled => proto::BreakpointState::Disabled.into(),
|
||||
},
|
||||
message: self.message.as_ref().map(|s| String::from(s.as_ref())),
|
||||
condition: self.condition.as_ref().map(|s| String::from(s.as_ref())),
|
||||
hit_condition: self
|
||||
.hit_condition
|
||||
.as_ref()
|
||||
.map(|s| String::from(s.as_ref())),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -610,7 +693,9 @@ impl Breakpoint {
|
|||
Some(proto::BreakpointState::Disabled) => BreakpointState::Disabled,
|
||||
None | Some(proto::BreakpointState::Enabled) => BreakpointState::Enabled,
|
||||
},
|
||||
message: breakpoint.message.map(|message| message.into()),
|
||||
message: breakpoint.message.map(Into::into),
|
||||
condition: breakpoint.condition.map(Into::into),
|
||||
hit_condition: breakpoint.hit_condition.map(Into::into),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -631,6 +716,8 @@ pub struct SourceBreakpoint {
|
|||
pub row: u32,
|
||||
pub path: Arc<Path>,
|
||||
pub message: Option<Arc<str>>,
|
||||
pub condition: Option<Arc<str>>,
|
||||
pub hit_condition: Option<Arc<str>>,
|
||||
pub state: BreakpointState,
|
||||
}
|
||||
|
||||
|
@ -639,8 +726,12 @@ impl From<SourceBreakpoint> for dap::SourceBreakpoint {
|
|||
Self {
|
||||
line: bp.row as u64 + 1,
|
||||
column: None,
|
||||
condition: None,
|
||||
hit_condition: None,
|
||||
condition: bp
|
||||
.condition
|
||||
.map(|condition| String::from(condition.as_ref())),
|
||||
hit_condition: bp
|
||||
.hit_condition
|
||||
.map(|hit_condition| String::from(hit_condition.as_ref())),
|
||||
log_message: bp.message.map(|message| String::from(message.as_ref())),
|
||||
mode: None,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue