Detailed changes
@@ -299,59 +299,76 @@ pub fn init(cx: &mut App) {
else {
return;
};
+
+ let session = active_session
+ .read(cx)
+ .running_state
+ .read(cx)
+ .session()
+ .read(cx);
+
+ if session.is_terminated() {
+ return;
+ }
+
let editor = cx.entity().downgrade();
- window.on_action(TypeId::of::<editor::actions::RunToCursor>(), {
- let editor = editor.clone();
- let active_session = active_session.clone();
- move |_, phase, _, cx| {
- if phase != DispatchPhase::Bubble {
- return;
- }
- maybe!({
- let (buffer, position, _) = editor
- .update(cx, |editor, cx| {
- let cursor_point: language::Point =
- editor.selections.newest(cx).head();
- editor
- .buffer()
- .read(cx)
- .point_to_buffer_point(cursor_point, cx)
- })
- .ok()??;
+ window.on_action_when(
+ session.any_stopped_thread(),
+ TypeId::of::<editor::actions::RunToCursor>(),
+ {
+ let editor = editor.clone();
+ let active_session = active_session.clone();
+ move |_, phase, _, cx| {
+ if phase != DispatchPhase::Bubble {
+ return;
+ }
+ maybe!({
+ let (buffer, position, _) = editor
+ .update(cx, |editor, cx| {
+ let cursor_point: language::Point =
+ editor.selections.newest(cx).head();
+
+ editor
+ .buffer()
+ .read(cx)
+ .point_to_buffer_point(cursor_point, cx)
+ })
+ .ok()??;
- let path =
+ let path =
debugger::breakpoint_store::BreakpointStore::abs_path_from_buffer(
&buffer, cx,
)?;
- let source_breakpoint = SourceBreakpoint {
- row: position.row,
- path,
- message: None,
- condition: None,
- hit_condition: None,
- state: debugger::breakpoint_store::BreakpointState::Enabled,
- };
+ let source_breakpoint = SourceBreakpoint {
+ row: position.row,
+ path,
+ message: None,
+ condition: None,
+ hit_condition: None,
+ state: debugger::breakpoint_store::BreakpointState::Enabled,
+ };
- active_session.update(cx, |session, cx| {
- session.running_state().update(cx, |state, cx| {
- if let Some(thread_id) = state.selected_thread_id() {
- state.session().update(cx, |session, cx| {
- session.run_to_position(
- source_breakpoint,
- thread_id,
- cx,
- );
- })
- }
+ active_session.update(cx, |session, cx| {
+ session.running_state().update(cx, |state, cx| {
+ if let Some(thread_id) = state.selected_thread_id() {
+ state.session().update(cx, |session, cx| {
+ session.run_to_position(
+ source_breakpoint,
+ thread_id,
+ cx,
+ );
+ })
+ }
+ });
});
- });
- Some(())
- });
- }
- });
+ Some(())
+ });
+ }
+ },
+ );
window.on_action(
TypeId::of::<editor::actions::EvaluateSelectedText>(),
@@ -1,8 +1,8 @@
use crate::{
Copy, CopyAndTrim, CopyPermalinkToLine, Cut, DisplayPoint, DisplaySnapshot, Editor,
EvaluateSelectedText, FindAllReferences, GoToDeclaration, GoToDefinition, GoToImplementation,
- GoToTypeDefinition, Paste, Rename, RevealInFileManager, SelectMode, SelectionEffects,
- SelectionExt, ToDisplayPoint, ToggleCodeActions,
+ GoToTypeDefinition, Paste, Rename, RevealInFileManager, RunToCursor, SelectMode,
+ SelectionEffects, SelectionExt, ToDisplayPoint, ToggleCodeActions,
actions::{Format, FormatSelections},
selections_collection::SelectionsCollection,
};
@@ -200,15 +200,21 @@ pub fn deploy_context_menu(
});
let evaluate_selection = window.is_action_available(&EvaluateSelectedText, cx);
+ let run_to_cursor = window.is_action_available(&RunToCursor, cx);
ui::ContextMenu::build(window, cx, |menu, _window, _cx| {
let builder = menu
.on_blur_subscription(Subscription::new(|| {}))
+ .when(run_to_cursor, |builder| {
+ builder.action("Run to Cursor", Box::new(RunToCursor))
+ })
.when(evaluate_selection && has_selections, |builder| {
- builder
- .action("Evaluate Selection", Box::new(EvaluateSelectedText))
- .separator()
+ builder.action("Evaluate Selection", Box::new(EvaluateSelectedText))
})
+ .when(
+ run_to_cursor || (evaluate_selection && has_selections),
+ |builder| builder.separator(),
+ )
.action("Go to Definition", Box::new(GoToDefinition))
.action("Go to Declaration", Box::new(GoToDeclaration))
.action("Go to Type Definition", Box::new(GoToTypeDefinition))
@@ -4248,6 +4248,25 @@ impl Window {
.on_action(action_type, Rc::new(listener));
}
+ /// Register an action listener on the window for the next frame if the condition is true.
+ /// The type of action is determined by the first parameter of the given listener.
+ /// When the next frame is rendered the listener will be cleared.
+ ///
+ /// This is a fairly low-level method, so prefer using action handlers on elements unless you have
+ /// a specific need to register a global listener.
+ pub fn on_action_when(
+ &mut self,
+ condition: bool,
+ action_type: TypeId,
+ listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
+ ) {
+ if condition {
+ self.next_frame
+ .dispatch_tree
+ .on_action(action_type, Rc::new(listener));
+ }
+ }
+
/// Read information about the GPU backing this window.
/// Currently returns None on Mac and Windows.
pub fn gpu_specs(&self) -> Option<GpuSpecs> {