diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 7a2511fa6d..78cbbd9101 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -36,8 +36,8 @@ pub use element::{ use futures::FutureExt; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ - div, px, AnyElement, AppContext, BackgroundExecutor, Context, Div, Element, Entity, - EventEmitter, FocusHandle, FontStyle, FontWeight, Hsla, Model, Pixels, Render, Styled, + div, px, AnyElement, AppContext, BackgroundExecutor, Context, DispatchContext, Div, Element, + Entity, EventEmitter, FocusHandle, FontStyle, FontWeight, Hsla, Model, Pixels, Render, Styled, Subscription, Task, TextStyle, View, ViewContext, VisualContext, WeakView, WindowContext, }; use highlight_matching_bracket::refresh_matching_bracket_highlights; @@ -54,6 +54,7 @@ use language::{ }; use link_go_to_definition::{GoToDefinitionLink, InlayHighlight, LinkGoToDefinitionState}; use lsp::{DiagnosticSeverity, Documentation, LanguageServerId}; +use movement::TextLayoutDetails; pub use multi_buffer::{ Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint, @@ -397,6 +398,18 @@ pub struct GoToTypeDefinition; pub struct GoToDefinitionSplit; pub struct GoToTypeDefinitionSplit; +#[derive(PartialEq, Clone, Default, Deserialize)] +pub struct MoveLeft; + +#[derive(PartialEq, Clone, Default, Deserialize)] +pub struct MoveRight; + +#[derive(PartialEq, Clone, Default, Deserialize)] +pub struct MoveDown; + +#[derive(PartialEq, Clone, Default, Deserialize)] +pub struct MoveUp; + enum DocumentHighlightRead {} enum DocumentHighlightWrite {} enum InputComposition {} @@ -413,130 +426,130 @@ pub fn init_settings(cx: &mut AppContext) { pub fn init(cx: &mut AppContext) { init_settings(cx); - // cx.add_action(Editor::new_file); - // cx.add_action(Editor::new_file_in_direction); - // cx.add_action(Editor::cancel); - // cx.add_action(Editor::newline); - // cx.add_action(Editor::newline_above); - // cx.add_action(Editor::newline_below); - // cx.add_action(Editor::backspace); - // cx.add_action(Editor::delete); - // cx.add_action(Editor::tab); - // cx.add_action(Editor::tab_prev); - // cx.add_action(Editor::indent); - // cx.add_action(Editor::outdent); - // cx.add_action(Editor::delete_line); - // cx.add_action(Editor::join_lines); - // cx.add_action(Editor::sort_lines_case_sensitive); - // cx.add_action(Editor::sort_lines_case_insensitive); - // cx.add_action(Editor::reverse_lines); - // cx.add_action(Editor::shuffle_lines); - // cx.add_action(Editor::convert_to_upper_case); - // cx.add_action(Editor::convert_to_lower_case); - // cx.add_action(Editor::convert_to_title_case); - // cx.add_action(Editor::convert_to_snake_case); - // cx.add_action(Editor::convert_to_kebab_case); - // cx.add_action(Editor::convert_to_upper_camel_case); - // cx.add_action(Editor::convert_to_lower_camel_case); - // cx.add_action(Editor::delete_to_previous_word_start); - // cx.add_action(Editor::delete_to_previous_subword_start); - // cx.add_action(Editor::delete_to_next_word_end); - // cx.add_action(Editor::delete_to_next_subword_end); - // cx.add_action(Editor::delete_to_beginning_of_line); - // cx.add_action(Editor::delete_to_end_of_line); - // cx.add_action(Editor::cut_to_end_of_line); - // cx.add_action(Editor::duplicate_line); - // cx.add_action(Editor::move_line_up); - // cx.add_action(Editor::move_line_down); - // cx.add_action(Editor::transpose); - // cx.add_action(Editor::cut); - // cx.add_action(Editor::copy); - // cx.add_action(Editor::paste); - // cx.add_action(Editor::undo); - // cx.add_action(Editor::redo); - // cx.add_action(Editor::move_up); - // cx.add_action(Editor::move_page_up); - // cx.add_action(Editor::move_down); - // cx.add_action(Editor::move_page_down); - // cx.add_action(Editor::next_screen); - // cx.add_action(Editor::move_left); - // cx.add_action(Editor::move_right); - // cx.add_action(Editor::move_to_previous_word_start); - // cx.add_action(Editor::move_to_previous_subword_start); - // cx.add_action(Editor::move_to_next_word_end); - // cx.add_action(Editor::move_to_next_subword_end); - // cx.add_action(Editor::move_to_beginning_of_line); - // cx.add_action(Editor::move_to_end_of_line); - // cx.add_action(Editor::move_to_start_of_paragraph); - // cx.add_action(Editor::move_to_end_of_paragraph); - // cx.add_action(Editor::move_to_beginning); - // cx.add_action(Editor::move_to_end); - // cx.add_action(Editor::select_up); - // cx.add_action(Editor::select_down); - // cx.add_action(Editor::select_left); - // cx.add_action(Editor::select_right); - // cx.add_action(Editor::select_to_previous_word_start); - // cx.add_action(Editor::select_to_previous_subword_start); - // cx.add_action(Editor::select_to_next_word_end); - // cx.add_action(Editor::select_to_next_subword_end); - // cx.add_action(Editor::select_to_beginning_of_line); - // cx.add_action(Editor::select_to_end_of_line); - // cx.add_action(Editor::select_to_start_of_paragraph); - // cx.add_action(Editor::select_to_end_of_paragraph); - // cx.add_action(Editor::select_to_beginning); - // cx.add_action(Editor::select_to_end); - // cx.add_action(Editor::select_all); - // cx.add_action(Editor::select_all_matches); - // cx.add_action(Editor::select_line); - // cx.add_action(Editor::split_selection_into_lines); - // cx.add_action(Editor::add_selection_above); - // cx.add_action(Editor::add_selection_below); - // cx.add_action(Editor::select_next); - // cx.add_action(Editor::select_previous); - // cx.add_action(Editor::toggle_comments); - // cx.add_action(Editor::select_larger_syntax_node); - // cx.add_action(Editor::select_smaller_syntax_node); - // cx.add_action(Editor::move_to_enclosing_bracket); - // cx.add_action(Editor::undo_selection); - // cx.add_action(Editor::redo_selection); - // cx.add_action(Editor::go_to_diagnostic); - // cx.add_action(Editor::go_to_prev_diagnostic); - // cx.add_action(Editor::go_to_hunk); - // cx.add_action(Editor::go_to_prev_hunk); - // cx.add_action(Editor::go_to_definition); - // cx.add_action(Editor::go_to_definition_split); - // cx.add_action(Editor::go_to_type_definition); - // cx.add_action(Editor::go_to_type_definition_split); - // cx.add_action(Editor::fold); - // cx.add_action(Editor::fold_at); - // cx.add_action(Editor::unfold_lines); - // cx.add_action(Editor::unfold_at); - // cx.add_action(Editor::gutter_hover); - // cx.add_action(Editor::fold_selected_ranges); - // cx.add_action(Editor::show_completions); - // cx.add_action(Editor::toggle_code_actions); - // cx.add_action(Editor::open_excerpts); - // cx.add_action(Editor::toggle_soft_wrap); - // cx.add_action(Editor::toggle_inlay_hints); - // cx.add_action(Editor::reveal_in_finder); - // cx.add_action(Editor::copy_path); - // cx.add_action(Editor::copy_relative_path); - // cx.add_action(Editor::copy_highlight_json); + // cx.register_action_type(Editor::new_file); + // cx.register_action_type(Editor::new_file_in_direction); + // cx.register_action_type(Editor::cancel); + // cx.register_action_type(Editor::newline); + // cx.register_action_type(Editor::newline_above); + // cx.register_action_type(Editor::newline_below); + // cx.register_action_type(Editor::backspace); + // cx.register_action_type(Editor::delete); + // cx.register_action_type(Editor::tab); + // cx.register_action_type(Editor::tab_prev); + // cx.register_action_type(Editor::indent); + // cx.register_action_type(Editor::outdent); + // cx.register_action_type(Editor::delete_line); + // cx.register_action_type(Editor::join_lines); + // cx.register_action_type(Editor::sort_lines_case_sensitive); + // cx.register_action_type(Editor::sort_lines_case_insensitive); + // cx.register_action_type(Editor::reverse_lines); + // cx.register_action_type(Editor::shuffle_lines); + // cx.register_action_type(Editor::convert_to_upper_case); + // cx.register_action_type(Editor::convert_to_lower_case); + // cx.register_action_type(Editor::convert_to_title_case); + // cx.register_action_type(Editor::convert_to_snake_case); + // cx.register_action_type(Editor::convert_to_kebab_case); + // cx.register_action_type(Editor::convert_to_upper_camel_case); + // cx.register_action_type(Editor::convert_to_lower_camel_case); + // cx.register_action_type(Editor::delete_to_previous_word_start); + // cx.register_action_type(Editor::delete_to_previous_subword_start); + // cx.register_action_type(Editor::delete_to_next_word_end); + // cx.register_action_type(Editor::delete_to_next_subword_end); + // cx.register_action_type(Editor::delete_to_beginning_of_line); + // cx.register_action_type(Editor::delete_to_end_of_line); + // cx.register_action_type(Editor::cut_to_end_of_line); + // cx.register_action_type(Editor::duplicate_line); + // cx.register_action_type(Editor::move_line_up); + // cx.register_action_type(Editor::move_line_down); + // cx.register_action_type(Editor::transpose); + // cx.register_action_type(Editor::cut); + // cx.register_action_type(Editor::copy); + // cx.register_action_type(Editor::paste); + // cx.register_action_type(Editor::undo); + // cx.register_action_type(Editor::redo); + cx.register_action_type::(); + // cx.register_action_type(Editor::move_page_up); + cx.register_action_type::(); + // cx.register_action_type(Editor::move_page_down); + // cx.register_action_type(Editor::next_screen); + cx.register_action_type::(); + cx.register_action_type::(); + // cx.register_action_type(Editor::move_to_previous_word_start); + // cx.register_action_type(Editor::move_to_previous_subword_start); + // cx.register_action_type(Editor::move_to_next_word_end); + // cx.register_action_type(Editor::move_to_next_subword_end); + // cx.register_action_type(Editor::move_to_beginning_of_line); + // cx.register_action_type(Editor::move_to_end_of_line); + // cx.register_action_type(Editor::move_to_start_of_paragraph); + // cx.register_action_type(Editor::move_to_end_of_paragraph); + // cx.register_action_type(Editor::move_to_beginning); + // cx.register_action_type(Editor::move_to_end); + // cx.register_action_type(Editor::select_up); + // cx.register_action_type(Editor::select_down); + // cx.register_action_type(Editor::select_left); + // cx.register_action_type(Editor::select_right); + // cx.register_action_type(Editor::select_to_previous_word_start); + // cx.register_action_type(Editor::select_to_previous_subword_start); + // cx.register_action_type(Editor::select_to_next_word_end); + // cx.register_action_type(Editor::select_to_next_subword_end); + // cx.register_action_type(Editor::select_to_beginning_of_line); + // cx.register_action_type(Editor::select_to_end_of_line); + // cx.register_action_type(Editor::select_to_start_of_paragraph); + // cx.register_action_type(Editor::select_to_end_of_paragraph); + // cx.register_action_type(Editor::select_to_beginning); + // cx.register_action_type(Editor::select_to_end); + // cx.register_action_type(Editor::select_all); + // cx.register_action_type(Editor::select_all_matches); + // cx.register_action_type(Editor::select_line); + // cx.register_action_type(Editor::split_selection_into_lines); + // cx.register_action_type(Editor::add_selection_above); + // cx.register_action_type(Editor::add_selection_below); + // cx.register_action_type(Editor::select_next); + // cx.register_action_type(Editor::select_previous); + // cx.register_action_type(Editor::toggle_comments); + // cx.register_action_type(Editor::select_larger_syntax_node); + // cx.register_action_type(Editor::select_smaller_syntax_node); + // cx.register_action_type(Editor::move_to_enclosing_bracket); + // cx.register_action_type(Editor::undo_selection); + // cx.register_action_type(Editor::redo_selection); + // cx.register_action_type(Editor::go_to_diagnostic); + // cx.register_action_type(Editor::go_to_prev_diagnostic); + // cx.register_action_type(Editor::go_to_hunk); + // cx.register_action_type(Editor::go_to_prev_hunk); + // cx.register_action_type(Editor::go_to_definition); + // cx.register_action_type(Editor::go_to_definition_split); + // cx.register_action_type(Editor::go_to_type_definition); + // cx.register_action_type(Editor::go_to_type_definition_split); + // cx.register_action_type(Editor::fold); + // cx.register_action_type(Editor::fold_at); + // cx.register_action_type(Editor::unfold_lines); + // cx.register_action_type(Editor::unfold_at); + // cx.register_action_type(Editor::gutter_hover); + // cx.register_action_type(Editor::fold_selected_ranges); + // cx.register_action_type(Editor::show_completions); + // cx.register_action_type(Editor::toggle_code_actions); + // cx.register_action_type(Editor::open_excerpts); + // cx.register_action_type(Editor::toggle_soft_wrap); + // cx.register_action_type(Editor::toggle_inlay_hints); + // cx.register_action_type(Editor::reveal_in_finder); + // cx.register_action_type(Editor::copy_path); + // cx.register_action_type(Editor::copy_relative_path); + // cx.register_action_type(Editor::copy_highlight_json); // cx.add_async_action(Editor::format); - // cx.add_action(Editor::restart_language_server); - // cx.add_action(Editor::show_character_palette); + // cx.register_action_type(Editor::restart_language_server); + // cx.register_action_type(Editor::show_character_palette); // cx.add_async_action(Editor::confirm_completion); // cx.add_async_action(Editor::confirm_code_action); // cx.add_async_action(Editor::rename); // cx.add_async_action(Editor::confirm_rename); // cx.add_async_action(Editor::find_all_references); - // cx.add_action(Editor::next_copilot_suggestion); - // cx.add_action(Editor::previous_copilot_suggestion); - // cx.add_action(Editor::copilot_suggest); - // cx.add_action(Editor::context_menu_first); - // cx.add_action(Editor::context_menu_prev); - // cx.add_action(Editor::context_menu_next); - // cx.add_action(Editor::context_menu_last); + // cx.register_action_type(Editor::next_copilot_suggestion); + // cx.register_action_type(Editor::previous_copilot_suggestion); + // cx.register_action_type(Editor::copilot_suggest); + // cx.register_action_type(Editor::context_menu_first); + // cx.register_action_type(Editor::context_menu_prev); + // cx.register_action_type(Editor::context_menu_next); + // cx.register_action_type(Editor::context_menu_last); hover_popover::init(cx); scroll::actions::init(cx); @@ -657,7 +670,7 @@ pub struct Editor { collapse_matches: bool, autoindent_mode: Option, workspace: Option<(WeakView, i64)>, - // keymap_context_layers: BTreeMap, + keymap_context_layers: BTreeMap, input_enabled: bool, read_only: bool, leader_peer_id: Option, @@ -670,6 +683,7 @@ pub struct Editor { next_inlay_id: usize, _subscriptions: Vec, pixel_position_of_newest_cursor: Option>, + style: Option, } pub struct EditorSnapshot { @@ -1965,7 +1979,7 @@ impl Editor { autoindent_mode: Some(AutoindentMode::EachLine), collapse_matches: false, workspace: None, - // keymap_context_layers: Default::default(), + keymap_context_layers: Default::default(), input_enabled: true, read_only: false, leader_peer_id: None, @@ -1976,6 +1990,7 @@ impl Editor { inlay_hint_cache: InlayHintCache::new(inlay_hint_settings), gutter_hovered: false, pixel_position_of_newest_cursor: None, + style: None, _subscriptions: vec![ cx.observe(&buffer, Self::on_buffer_changed), cx.subscribe(&buffer, Self::on_buffer_event), @@ -2014,6 +2029,48 @@ impl Editor { this } + fn dispatch_context(&self, cx: &AppContext) -> DispatchContext { + let mut dispatch_context = DispatchContext::default(); + dispatch_context.insert("Editor"); + let mode = match self.mode { + EditorMode::SingleLine => "single_line", + EditorMode::AutoHeight { .. } => "auto_height", + EditorMode::Full => "full", + }; + dispatch_context.set("mode", mode); + if self.pending_rename.is_some() { + dispatch_context.insert("renaming"); + } + if self.context_menu_visible() { + match self.context_menu.read().as_ref() { + Some(ContextMenu::Completions(_)) => { + dispatch_context.insert("menu"); + dispatch_context.insert("showing_completions") + } + Some(ContextMenu::CodeActions(_)) => { + dispatch_context.insert("menu"); + dispatch_context.insert("showing_code_actions") + } + None => {} + } + } + + for layer in self.keymap_context_layers.values() { + dispatch_context.extend(layer); + } + + if let Some(extension) = self + .buffer + .read(cx) + .as_singleton() + .and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str()) + { + dispatch_context.set("extension", extension.to_string()); + } + + dispatch_context + } + // pub fn new_file( // workspace: &mut Workspace, // _: &workspace::NewFile, @@ -2021,7 +2078,7 @@ impl Editor { // ) { // let project = workspace.project().clone(); // if project.read(cx).is_remote() { - // cx.propagate_action(); + // cx.propagate(); // } else if let Some(buffer) = project // .update(cx, |project, cx| project.create_buffer("", None, cx)) // .log_err() @@ -2040,7 +2097,7 @@ impl Editor { // ) { // let project = workspace.project().clone(); // if project.read(cx).is_remote() { - // cx.propagate_action(); + // cx.propagate(); // } else if let Some(buffer) = project // .update(cx, |project, cx| project.create_buffer("", None, cx)) // .log_err() @@ -2731,7 +2788,7 @@ impl Editor { // } // } - // cx.propagate_action(); + // cx.propagate(); // } // pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext) { @@ -3482,13 +3539,12 @@ impl Editor { .collect() } - // pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails { - // TextLayoutDetails { - // font_cache: cx.font_cache().clone(), - // text_layout_cache: cx.text_layout_cache().clone(), - // editor_style: self.style(cx), - // } - // } + pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails { + TextLayoutDetails { + text_system: cx.text_system().clone(), + editor_style: self.style.clone().unwrap(), + } + } fn splice_inlay_hints( &self, @@ -4207,7 +4263,7 @@ impl Editor { let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none(); if is_copilot_disabled { todo!(); - // cx.propagate_action(); + // cx.propagate(); } } } @@ -4429,12 +4485,14 @@ impl Editor { // .collect() // } - // pub fn context_menu_visible(&self) -> bool { - // self.context_menu - // .read() - // .as_ref() - // .map_or(false, |menu| menu.visible()) - // } + pub fn context_menu_visible(&self) -> bool { + false + // todo!("context menu") + // self.context_menu + // .read() + // .as_ref() + // .map_or(false, |menu| menu.visible()) + } // pub fn render_context_menu( // &self, @@ -5681,19 +5739,19 @@ impl Editor { // .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx)); // } - // pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext) { - // self.change_selections(Some(Autoscroll::fit()), cx, |s| { - // let line_mode = s.line_mode; - // s.move_with(|map, selection| { - // let cursor = if selection.is_empty() && !line_mode { - // movement::left(map, selection.start) - // } else { - // selection.start - // }; - // selection.collapse_to(cursor, SelectionGoal::None); - // }); - // }) - // } + pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext) { + self.change_selections(Some(Autoscroll::fit()), cx, |s| { + let line_mode = s.line_mode; + s.move_with(|map, selection| { + let cursor = if selection.is_empty() && !line_mode { + movement::left(map, selection.start) + } else { + selection.start + }; + selection.collapse_to(cursor, SelectionGoal::None); + }); + }) + } // pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext) { // self.change_selections(Some(Autoscroll::fit()), cx, |s| { @@ -5701,19 +5759,19 @@ impl Editor { // }) // } - // pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext) { - // self.change_selections(Some(Autoscroll::fit()), cx, |s| { - // let line_mode = s.line_mode; - // s.move_with(|map, selection| { - // let cursor = if selection.is_empty() && !line_mode { - // movement::right(map, selection.end) - // } else { - // selection.end - // }; - // selection.collapse_to(cursor, SelectionGoal::None) - // }); - // }) - // } + pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext) { + self.change_selections(Some(Autoscroll::fit()), cx, |s| { + let line_mode = s.line_mode; + s.move_with(|map, selection| { + let cursor = if selection.is_empty() && !line_mode { + movement::right(map, selection.end) + } else { + selection.end + }; + selection.collapse_to(cursor, SelectionGoal::None) + }); + }) + } // pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext) { // self.change_selections(Some(Autoscroll::fit()), cx, |s| { @@ -5721,35 +5779,35 @@ impl Editor { // }) // } - // pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext) { - // if self.take_rename(true, cx).is_some() { - // return; - // } + pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext) { + if self.take_rename(true, cx).is_some() { + return; + } - // if matches!(self.mode, EditorMode::SingleLine) { - // cx.propagate_action(); - // return; - // } + if matches!(self.mode, EditorMode::SingleLine) { + cx.propagate(); + return; + } - // let text_layout_details = &self.text_layout_details(cx); + let text_layout_details = &self.text_layout_details(cx); - // self.change_selections(Some(Autoscroll::fit()), cx, |s| { - // let line_mode = s.line_mode; - // s.move_with(|map, selection| { - // if !selection.is_empty() && !line_mode { - // selection.goal = SelectionGoal::None; - // } - // let (cursor, goal) = movement::up( - // map, - // selection.start, - // selection.goal, - // false, - // &text_layout_details, - // ); - // selection.collapse_to(cursor, goal); - // }); - // }) - // } + self.change_selections(Some(Autoscroll::fit()), cx, |s| { + let line_mode = s.line_mode; + s.move_with(|map, selection| { + if !selection.is_empty() && !line_mode { + selection.goal = SelectionGoal::None; + } + let (cursor, goal) = movement::up( + map, + selection.start, + selection.goal, + false, + &text_layout_details, + ); + selection.collapse_to(cursor, goal); + }); + }) + } // pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext) { // if self.take_rename(true, cx).is_some() { @@ -5757,7 +5815,7 @@ impl Editor { // } // if matches!(self.mode, EditorMode::SingleLine) { - // cx.propagate_action(); + // cx.propagate(); // return; // } @@ -5803,32 +5861,33 @@ impl Editor { // }) // } - // pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext) { - // self.take_rename(true, cx); + pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext) { + dbg!("move_down"); + self.take_rename(true, cx); - // if self.mode == EditorMode::SingleLine { - // cx.propagate_action(); - // return; - // } + if self.mode == EditorMode::SingleLine { + cx.propagate(); + return; + } - // let text_layout_details = &self.text_layout_details(cx); - // self.change_selections(Some(Autoscroll::fit()), cx, |s| { - // let line_mode = s.line_mode; - // s.move_with(|map, selection| { - // if !selection.is_empty() && !line_mode { - // selection.goal = SelectionGoal::None; - // } - // let (cursor, goal) = movement::down( - // map, - // selection.end, - // selection.goal, - // false, - // &text_layout_details, - // ); - // selection.collapse_to(cursor, goal); - // }); - // }); - // } + let text_layout_details = &self.text_layout_details(cx); + self.change_selections(Some(Autoscroll::fit()), cx, |s| { + let line_mode = s.line_mode; + s.move_with(|map, selection| { + if !selection.is_empty() && !line_mode { + selection.goal = SelectionGoal::None; + } + let (cursor, goal) = movement::down( + map, + selection.end, + selection.goal, + false, + &text_layout_details, + ); + selection.collapse_to(cursor, goal); + }); + }); + } // pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext) { // if self.take_rename(true, cx).is_some() { @@ -5846,7 +5905,7 @@ impl Editor { // } // if matches!(self.mode, EditorMode::SingleLine) { - // cx.propagate_action(); + // cx.propagate(); // return; // } @@ -6193,7 +6252,7 @@ impl Editor { // cx: &mut ViewContext, // ) { // if matches!(self.mode, EditorMode::SingleLine) { - // cx.propagate_action(); + // cx.propagate(); // return; // } @@ -6213,7 +6272,7 @@ impl Editor { // cx: &mut ViewContext, // ) { // if matches!(self.mode, EditorMode::SingleLine) { - // cx.propagate_action(); + // cx.propagate(); // return; // } @@ -6233,7 +6292,7 @@ impl Editor { // cx: &mut ViewContext, // ) { // if matches!(self.mode, EditorMode::SingleLine) { - // cx.propagate_action(); + // cx.propagate(); // return; // } @@ -6253,7 +6312,7 @@ impl Editor { // cx: &mut ViewContext, // ) { // if matches!(self.mode, EditorMode::SingleLine) { - // cx.propagate_action(); + // cx.propagate(); // return; // } @@ -6269,7 +6328,7 @@ impl Editor { // pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext) { // if matches!(self.mode, EditorMode::SingleLine) { - // cx.propagate_action(); + // cx.propagate(); // return; // } @@ -6289,7 +6348,7 @@ impl Editor { // pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext) { // if matches!(self.mode, EditorMode::SingleLine) { - // cx.propagate_action(); + // cx.propagate(); // return; // } @@ -8807,14 +8866,14 @@ impl Editor { // { // editor // } else { - // cx.propagate_action(); + // cx.propagate(); // return; // }; // let editor = editor_handle.read(cx); // let buffer = editor.buffer.read(cx); // if buffer.is_singleton() { - // cx.propagate_action(); + // cx.propagate(); // return; // } @@ -9443,46 +9502,7 @@ impl Render for Editor { // false // } - -// fn update_keymap_context(&self, keymap: &mut KeymapContext, cx: &AppContext) { -// Self::reset_to_default_keymap_context(keymap); -// let mode = match self.mode { -// EditorMode::SingleLine => "single_line", -// EditorMode::AutoHeight { .. } => "auto_height", -// EditorMode::Full => "full", -// }; -// keymap.add_key("mode", mode); -// if self.pending_rename.is_some() { -// keymap.add_identifier("renaming"); -// } -// if self.context_menu_visible() { -// match self.context_menu.read().as_ref() { -// Some(ContextMenu::Completions(_)) => { -// keymap.add_identifier("menu"); -// keymap.add_identifier("showing_completions") -// } -// Some(ContextMenu::CodeActions(_)) => { -// keymap.add_identifier("menu"); -// keymap.add_identifier("showing_code_actions") -// } -// None => {} -// } -// } - -// for layer in self.keymap_context_layers.values() { -// keymap.extend(layer); -// } - -// if let Some(extension) = self -// .buffer -// .read(cx) -// .as_singleton() -// .and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str()) -// { -// keymap.add_key("extension", extension.to_string()); -// } -// } - +// // fn text_for_range(&self, range_utf16: Range, cx: &AppContext) -> Option { // Some( // self.buffer diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index 4d8cd57abc..918cfce43f 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -3,15 +3,15 @@ use crate::{ editor_settings::ShowScrollbar, git::{diff_hunk_to_display, DisplayDiffHunk}, CursorShape, DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, - Point, Selection, SoftWrap, ToPoint, MAX_LINE_LEN, + MoveDown, Point, Selection, SoftWrap, ToPoint, MAX_LINE_LEN, }; use anyhow::Result; use collections::{BTreeMap, HashMap}; use gpui::{ - black, hsla, point, px, relative, size, transparent_black, AnyElement, BorrowWindow, Bounds, - ContentMask, Corners, DispatchPhase, Edges, Element, ElementId, Hsla, Line, Pixels, - ScrollWheelEvent, ShapedGlyph, Size, StatefulInteraction, Style, TextRun, TextStyle, - TextSystem, ViewContext, WindowContext, + black, hsla, point, px, relative, size, transparent_black, Action, AnyElement, BorrowWindow, + Bounds, ContentMask, Corners, DispatchContext, DispatchPhase, Edges, Element, ElementId, + Entity, Hsla, KeyDownEvent, KeyListener, KeyMatch, Line, Pixels, ScrollWheelEvent, ShapedGlyph, + Size, StatefulInteraction, Style, TextRun, TextStyle, TextSystem, ViewContext, WindowContext, }; use itertools::Itertools; use language::language_settings::ShowWhitespaceSetting; @@ -20,6 +20,7 @@ use project::project_settings::{GitGutterSetting, ProjectSettings}; use settings::Settings; use smallvec::SmallVec; use std::{ + any::TypeId, borrow::Cow, cmp::{self, Ordering}, fmt::Write, @@ -94,14 +95,12 @@ impl SelectionLayout { } pub struct EditorElement { - style: Arc, + style: EditorStyle, } impl EditorElement { pub fn new(style: EditorStyle) -> Self { - Self { - style: Arc::new(style), - } + Self { style } } // fn attach_mouse_handlers( @@ -2554,7 +2553,38 @@ impl Element for EditorElement { element_state: Option, cx: &mut gpui::ViewContext, ) -> Self::ElementState { - () + editor.style = Some(self.style.clone()); // Long-term, we'd like to eliminate this. + + let dispatch_context = editor.dispatch_context(cx); + cx.with_element_id(cx.view().entity_id(), |global_id, cx| { + cx.with_key_dispatch_context(dispatch_context, |cx| { + cx.with_key_listeners( + [ + build_key_listener( + move |editor, key_down: &KeyDownEvent, dispatch_context, phase, cx| { + if phase == DispatchPhase::Bubble { + if let KeyMatch::Some(action) = cx.match_keystroke( + &global_id, + &key_down.keystroke, + dispatch_context, + ) { + dbg!(action.as_any()); + return Some(action); + } + } + + None + }, + ), + build_action_listener(Editor::move_left), + build_action_listener(Editor::move_right), + build_action_listener(Editor::move_down), + build_action_listener(Editor::move_up), + ], + |cx| cx.with_focus(editor.focus_handle.clone(), |_| {}), + ); + }) + }); } fn layout( @@ -4080,3 +4110,33 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: f32) -> f32 { // .collect() // } // } + +fn build_key_listener( + listener: impl Fn( + &mut Editor, + &T, + &[&DispatchContext], + DispatchPhase, + &mut ViewContext, + ) -> Option> + + 'static, +) -> (TypeId, KeyListener) { + ( + TypeId::of::(), + Box::new(move |editor, event, dispatch_context, phase, cx| { + let key_event = event.downcast_ref::()?; + listener(editor, key_event, dispatch_context, phase, cx) + }), + ) +} + +fn build_action_listener( + listener: impl Fn(&mut Editor, &T, &mut ViewContext) + 'static, +) -> (TypeId, KeyListener) { + build_key_listener(move |editor, action: &T, dispatch_context, phase, cx| { + if phase == DispatchPhase::Bubble { + listener(editor, action, cx); + } + None + }) +} diff --git a/crates/editor2/src/movement.rs b/crates/editor2/src/movement.rs index 962f4f60e6..b15c484a03 100644 --- a/crates/editor2/src/movement.rs +++ b/crates/editor2/src/movement.rs @@ -3,7 +3,7 @@ use crate::{char_kind, CharKind, EditorStyle, ToOffset, ToPoint}; use gpui::{px, TextSystem}; use language::Point; use serde::de::IntoDeserializer; -use std::ops::Range; +use std::{ops::Range, sync::Arc}; #[derive(Debug, PartialEq)] pub enum FindRange { @@ -14,7 +14,7 @@ pub enum FindRange { /// TextLayoutDetails encompasses everything we need to move vertically /// taking into account variable width characters. pub struct TextLayoutDetails { - pub text_system: TextSystem, + pub text_system: Arc, pub editor_style: EditorStyle, } diff --git a/crates/gpui2/src/action.rs b/crates/gpui2/src/action.rs index 84843c9876..2139fdedcb 100644 --- a/crates/gpui2/src/action.rs +++ b/crates/gpui2/src/action.rs @@ -22,7 +22,8 @@ where A: for<'a> Deserialize<'a> + PartialEq + Clone + Default + 'static, { fn qualified_name() -> SharedString { - type_name::().into() + // todo!() remove this + type_name::().replace("2::", "::").into() } fn build(params: Option) -> Result> diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 801047de5f..63d2143a67 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -779,11 +779,21 @@ impl AppContext { (build)(params) } - /// Halt propagation of a mouse event, keyboard event, or action. This prevents listeners - /// that have not yet been invoked from receiving the event. + /// Event handlers propagate events by default. Call this method to stop dispatching to + /// event handlers with a lower z-index (mouse) or higher in the tree (keyboard). This is + /// the opposite of [propagate]. It's also possible to cancel a call to [propagate] by + /// calling this method before effects are flushed. pub fn stop_propagation(&mut self) { self.propagate_event = false; } + + /// Action handlers stop propagation by default during the bubble phase of action dispatch + /// dispatching to action handlers higher in the element tree. This is the opposite of + /// [stop_propagation]. It's also possible to cancel a call to [stop_propagate] by calling + /// this method before effects are flushed. + pub fn propagate(&mut self) { + self.propagate_event = true; + } } impl Context for AppContext { diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 9cab40082b..0b3bcd1d76 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1314,6 +1314,7 @@ impl<'a> WindowContext<'a> { } = stack_frame { if action_type == *event_type { + self.app.propagate_event = false; listener(action.as_any(), &[], DispatchPhase::Bubble, self); if !self.app.propagate_event { break; @@ -1328,6 +1329,7 @@ impl<'a> WindowContext<'a> { self.app.global_action_listeners.remove(&action_type) { for listener in global_listeners.iter().rev() { + self.app.propagate_event = false; listener(action.as_ref(), DispatchPhase::Bubble, self); if !self.app.propagate_event { break; diff --git a/crates/settings2/src/settings_file.rs b/crates/settings2/src/settings_file.rs index c623ae9caf..6f2c8d374f 100644 --- a/crates/settings2/src/settings_file.rs +++ b/crates/settings2/src/settings_file.rs @@ -1,4 +1,4 @@ -use crate::{settings_store::SettingsStore, Settings}; +use crate::{settings_store::SettingsStore, KeymapFile, Settings}; use anyhow::Result; use fs::Fs; use futures::{channel::mpsc, StreamExt}; @@ -117,3 +117,50 @@ pub fn update_settings_file( }) .detach_and_log_err(cx); } + +pub fn load_default_keymap(cx: &mut AppContext) { + for path in ["keymaps/default.json", "keymaps/vim.json"] { + KeymapFile::load_asset(path, cx).unwrap(); + } + + // todo!() + // if let Some(asset_path) = settings::get::(cx).asset_path() { + // KeymapFile::load_asset(asset_path, cx).unwrap(); + // } +} + +pub fn handle_keymap_file_changes( + mut user_keymap_file_rx: mpsc::UnboundedReceiver, + cx: &mut AppContext, +) { + cx.spawn(move |cx| async move { + // let mut settings_subscription = None; + while let Some(user_keymap_content) = user_keymap_file_rx.next().await { + if let Some(keymap_content) = KeymapFile::parse(&user_keymap_content).log_err() { + cx.update(|cx| reload_keymaps(cx, &keymap_content)).ok(); + + // todo!() + // let mut old_base_keymap = cx.read(|cx| *settings::get::(cx)); + // drop(settings_subscription); + // settings_subscription = Some(cx.update(|cx| { + // cx.observe_global::(move |cx| { + // let new_base_keymap = *settings::get::(cx); + // if new_base_keymap != old_base_keymap { + // old_base_keymap = new_base_keymap.clone(); + // reload_keymaps(cx, &keymap_content); + // } + // }) + // })); + } + } + }) + .detach(); +} + +fn reload_keymaps(cx: &mut AppContext, keymap_content: &KeymapFile) { + // todo!() + // cx.clear_bindings(); + load_default_keymap(cx); + keymap_content.clone().add_to_cx(cx).log_err(); + // cx.set_menus(menus::menus()); +} diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index 580afd2653..8dad94847e 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -20,7 +20,8 @@ use node_runtime::RealNodeRuntime; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; use settings::{ - default_settings, handle_settings_file_changes, watch_config_file, Settings, SettingsStore, + default_settings, handle_keymap_file_changes, handle_settings_file_changes, watch_config_file, + Settings, SettingsStore, }; use simplelog::ConfigBuilder; use smol::process::Command; @@ -76,7 +77,7 @@ fn main() { fs.clone(), paths::SETTINGS.clone(), ); - let _user_keymap_file_rx = watch_config_file( + let user_keymap_file_rx = watch_config_file( &app.background_executor(), fs.clone(), paths::KEYMAP.clone(), @@ -116,7 +117,7 @@ fn main() { .unwrap(); cx.set_global(store); handle_settings_file_changes(user_settings_file_rx, cx); - // handle_keymap_file_changes(user_keymap_file_rx, cx); + handle_keymap_file_changes(user_keymap_file_rx, cx); let client = client::Client::new(http.clone(), cx); let mut languages = LanguageRegistry::new(login_shell_env_loaded);