History

Improve Find/Replace shortcuts (#10297)

This PR changes ways the Find/Replace functionality in the Buffer/Project Search is accessible via shortcuts. It makes those panels work the same way as in VS Code and Sublime Text. The details are described in the issue: [Make Find/Replace easier to use](https://github.com/zed-industries/zed/issues/9142) There's a difficulty with the Linux keybindings: VS Code uses on MacOS (this PR replicates it): | Action | Buffer Search | Project Search | | --- | --- | --- | | Find | `cmd-f` | `cmd-shift-f` | | Replace | `cmd-alt-f` | `cmd-shift-h` | VS Code uses on Linux (this PR replicates all but one): | Action | Buffer Search | Project Search | | --- | --- | --- | | Find | `ctrl-f` | `ctrl-shift-f` | | Replace | `ctrl-h` ❗ | `ctrl-shift-h` | The problem is that `ctrl-h` is already taken by the `editor::Backspace` action in Zed on Linux. There's two options here: 1. Change keybinding for `editor::Backspace` on Linux to something else, and use `ctrl-h` for the "replace in buffer" action. 2. Use some other keybinding on Linux in Zed. This PR introduces `ctrl-r` for this purpose, though I'm not sure it's the best choice. What do you think? fixes #9142 Release Notes: - Improved access to "Find/Replace in Buffer" and "Find/Replace in Files" via shortcuts (#9142). Optionally, include screenshots / media showcasing your addition that can be included in the release notes. - N/A

Andrew Lygin committed 2 years ago

Commit 935e0d51 parent cc367d48 files · +103 −28Browse files

Unified · Split

8 files
  1. assets/keymaps/default-linux.json +14 −5
  2. assets/keymaps/default-macos.json +13 −3
  3. crates/quick_action_bar/src/quick_action_bar.rs +2 −2
  4. crates/search/src/buffer_search.rs +32 −5
  5. crates/search/src/project_search.rs +24 −10
  6. crates/search/src/search.rs +1 −0
  7. crates/workspace/src/pane.rs +16 −2
  8. crates/zed/src/zed/app_menus.rs +1 −1
assets/keymaps/default-linux.json+14−5
@@ -28,7 +28,7 @@ · 27 unmodified lines
28 "ctrl-0": "zed::ResetBufferFontSize",28 "ctrl-0": "zed::ResetBufferFontSize",
29 "ctrl-,": "zed::OpenSettings",29 "ctrl-,": "zed::OpenSettings",
30 "ctrl-q": "zed::Quit",30 "ctrl-q": "zed::Quit",
31 "ctrl-h": "zed::Hide",31 "alt-f9": "zed::Hide",
32 "f11": "zed::ToggleFullScreen"32 "f11": "zed::ToggleFullScreen"
33 }33 }
34 },34 },
@@ -38,7 +38,6 @@ · 3 unmodified lines
38 "escape": "editor::Cancel",38 "escape": "editor::Cancel",
39 "backspace": "editor::Backspace",39 "backspace": "editor::Backspace",
40 "shift-backspace": "editor::Backspace",40 "shift-backspace": "editor::Backspace",
41 "ctrl-h": "editor::Backspace",
42 "delete": "editor::Delete",41 "delete": "editor::Delete",
43 "ctrl-d": "editor::Delete",42 "ctrl-d": "editor::Delete",
44 "tab": "editor::Tab",43 "tab": "editor::Tab",
@@ -150,10 +149,11 @@ · 105 unmodified lines
150 "ctrl-shift-enter": "editor::NewlineBelow",149 "ctrl-shift-enter": "editor::NewlineBelow",
151 "ctrl-enter": "editor::NewlineAbove",150 "ctrl-enter": "editor::NewlineAbove",
152 "alt-z": "editor::ToggleSoftWrap",151 "alt-z": "editor::ToggleSoftWrap",
153 "ctrl-f": [152 "ctrl-f": "buffer_search::Deploy",
153 "ctrl-h": [
154 "buffer_search::Deploy",154 "buffer_search::Deploy",
155 {155 {
156 "focus": true156 "replace_enabled": true
157 }157 }
158 ],158 ],
159 // "cmd-e": [159 // "cmd-e": [
@@ -212,7 +212,9 @@ · 52 unmodified lines
212 "enter": "search::SelectNextMatch",212 "enter": "search::SelectNextMatch",
213 "shift-enter": "search::SelectPrevMatch",213 "shift-enter": "search::SelectPrevMatch",
214 "alt-enter": "search::SelectAllMatches",214 "alt-enter": "search::SelectAllMatches",
215 "alt-tab": "search::CycleMode"215 "alt-tab": "search::CycleMode",
216 "ctrl-f": "search::FocusSearch",
217 "ctrl-h": "search::ToggleReplace"
216 }218 }
217 },219 },
218 {220 {
@@ -234,6 +236,7 @@ · 15 unmodified lines
234 "bindings": {236 "bindings": {
235 "escape": "project_search::ToggleFocus",237 "escape": "project_search::ToggleFocus",
236 "alt-tab": "search::CycleMode",238 "alt-tab": "search::CycleMode",
239 "ctrl-shift-f": "search::FocusSearch",
237 "ctrl-shift-h": "search::ToggleReplace",240 "ctrl-shift-h": "search::ToggleReplace",
238 "alt-ctrl-g": "search::ActivateRegexMode",241 "alt-ctrl-g": "search::ActivateRegexMode",
239 "alt-ctrl-x": "search::ActivateTextMode"242 "alt-ctrl-x": "search::ActivateTextMode"
@@ -419,6 +422,12 @@ · 179 unmodified lines
419 "ctrl-j": "workspace::ToggleBottomDock",422 "ctrl-j": "workspace::ToggleBottomDock",
420 "ctrl-alt-y": "workspace::CloseAllDocks",423 "ctrl-alt-y": "workspace::CloseAllDocks",
421 "ctrl-shift-f": "pane::DeploySearch",424 "ctrl-shift-f": "pane::DeploySearch",
425 "ctrl-shift-h": [
426 "pane::DeploySearch",
427 {
428 "replace_enabled": true
429 }
430 ],
422 "ctrl-k ctrl-s": "zed::OpenKeymap",431 "ctrl-k ctrl-s": "zed::OpenKeymap",
423 "ctrl-k ctrl-t": "theme_selector::Toggle",432 "ctrl-k ctrl-t": "theme_selector::Toggle",
424 "ctrl-shift-t": "project_symbols::Toggle",433 "ctrl-shift-t": "project_symbols::Toggle",
assets/keymaps/default-macos.json+13−3
@@ -170,10 +170,11 @@ · 169 unmodified lines
170 "cmd-shift-enter": "editor::NewlineAbove",170 "cmd-shift-enter": "editor::NewlineAbove",
171 "cmd-enter": "editor::NewlineBelow",171 "cmd-enter": "editor::NewlineBelow",
172 "alt-z": "editor::ToggleSoftWrap",172 "alt-z": "editor::ToggleSoftWrap",
173 "cmd-f": [173 "cmd-f": "buffer_search::Deploy",
174 "cmd-alt-f": [
174 "buffer_search::Deploy",175 "buffer_search::Deploy",
175 {176 {
176 "focus": true177 "replace_enabled": true
177 }178 }
178 ],179 ],
179 "cmd-e": [180 "cmd-e": [
@@ -232,7 +233,9 @@ · 52 unmodified lines
232 "enter": "search::SelectNextMatch",233 "enter": "search::SelectNextMatch",
233 "shift-enter": "search::SelectPrevMatch",234 "shift-enter": "search::SelectPrevMatch",
234 "alt-enter": "search::SelectAllMatches",235 "alt-enter": "search::SelectAllMatches",
235 "alt-tab": "search::CycleMode"236 "alt-tab": "search::CycleMode",
237 "cmd-f": "search::FocusSearch",
238 "cmd-alt-f": "search::ToggleReplace"
236 }239 }
237 },240 },
238 {241 {
@@ -254,6 +257,7 @@ · 15 unmodified lines
254 "bindings": {257 "bindings": {
255 "escape": "project_search::ToggleFocus",258 "escape": "project_search::ToggleFocus",
256 "alt-tab": "search::CycleMode",259 "alt-tab": "search::CycleMode",
260 "cmd-shift-f": "search::FocusSearch",
257 "cmd-shift-h": "search::ToggleReplace",261 "cmd-shift-h": "search::ToggleReplace",
258 "alt-cmd-g": "search::ActivateRegexMode",262 "alt-cmd-g": "search::ActivateRegexMode",
259 "alt-cmd-x": "search::ActivateTextMode"263 "alt-cmd-x": "search::ActivateTextMode"
@@ -436,6 +440,12 @@ · 176 unmodified lines
436 "cmd-j": "workspace::ToggleBottomDock",440 "cmd-j": "workspace::ToggleBottomDock",
437 "alt-cmd-y": "workspace::CloseAllDocks",441 "alt-cmd-y": "workspace::CloseAllDocks",
438 "cmd-shift-f": "pane::DeploySearch",442 "cmd-shift-f": "pane::DeploySearch",
443 "cmd-shift-h": [
444 "pane::DeploySearch",
445 {
446 "replace_enabled": true
447 }
448 ],
439 "cmd-k cmd-s": "zed::OpenKeymap",449 "cmd-k cmd-s": "zed::OpenKeymap",
440 "cmd-k cmd-t": "theme_selector::Toggle",450 "cmd-k cmd-t": "theme_selector::Toggle",
441 "cmd-t": "project_symbols::Toggle",451 "cmd-t": "project_symbols::Toggle",
crates/quick_action_bar/src/quick_action_bar.rs+2−2
@@ -91,13 +91,13 @@ impl Render for QuickActionBar { · 90 unmodified lines
91 "toggle buffer search",91 "toggle buffer search",
92 IconName::MagnifyingGlass,92 IconName::MagnifyingGlass,
93 !self.buffer_search_bar.read(cx).is_dismissed(),93 !self.buffer_search_bar.read(cx).is_dismissed(),
94 Box::new(buffer_search::Deploy { focus: false }),94 Box::new(buffer_search::Deploy::find()),
95 "Buffer Search",95 "Buffer Search",
96 {96 {
97 let buffer_search_bar = self.buffer_search_bar.clone();97 let buffer_search_bar = self.buffer_search_bar.clone();
98 move |_, cx| {98 move |_, cx| {
99 buffer_search_bar.update(cx, |search_bar, cx| {99 buffer_search_bar.update(cx, |search_bar, cx| {
100 search_bar.toggle(&buffer_search::Deploy { focus: true }, cx)100 search_bar.toggle(&buffer_search::Deploy::find(), cx)
101 });101 });
102 }102 }
103 },103 },
crates/search/src/buffer_search.rs+32−5
@@ -3,9 +3,9 @@ mod registrar; · 2 unmodified lines
3use crate::{3use crate::{
4 mode::{next_mode, SearchMode},4 mode::{next_mode, SearchMode},
5 search_bar::render_nav_button,5 search_bar::render_nav_button,
6 ActivateRegexMode, ActivateTextMode, CycleMode, NextHistoryQuery, PreviousHistoryQuery,6 ActivateRegexMode, ActivateTextMode, CycleMode, FocusSearch, NextHistoryQuery,
7 ReplaceAll, ReplaceNext, SearchOptions, SelectAllMatches, SelectNextMatch, SelectPrevMatch,7 PreviousHistoryQuery, ReplaceAll, ReplaceNext, SearchOptions, SelectAllMatches,
8 ToggleCaseSensitive, ToggleReplace, ToggleWholeWord,8 SelectNextMatch, SelectPrevMatch, ToggleCaseSensitive, ToggleReplace, ToggleWholeWord,
9};9};
10use any_vec::AnyVec;10use any_vec::AnyVec;
11use collections::HashMap;11use collections::HashMap;
@@ -44,15 +44,31 @@ const MIN_INPUT_WIDTH_REMS: f32 = 15.; · 32 unmodified lines
44const MAX_INPUT_WIDTH_REMS: f32 = 30.;44const MAX_INPUT_WIDTH_REMS: f32 = 30.;
45const MAX_BUFFER_SEARCH_HISTORY_SIZE: usize = 50;45const MAX_BUFFER_SEARCH_HISTORY_SIZE: usize = 50;
46 46
47const fn true_value() -> bool {
48 true
49}
50
47#[derive(PartialEq, Clone, Deserialize)]51#[derive(PartialEq, Clone, Deserialize)]
48pub struct Deploy {52pub struct Deploy {
53 #[serde(default = "true_value")]
49 pub focus: bool,54 pub focus: bool,
55 #[serde(default)]
56 pub replace_enabled: bool,
50}57}
51 58
52impl_actions!(buffer_search, [Deploy]);59impl_actions!(buffer_search, [Deploy]);
53 60
54actions!(buffer_search, [Dismiss, FocusEditor]);61actions!(buffer_search, [Dismiss, FocusEditor]);
55 62
63impl Deploy {
64 pub fn find() -> Self {
65 Self {
66 focus: true,
67 replace_enabled: false,
68 }
69 }
70}
71
56pub enum Event {72pub enum Event {
57 UpdateLocation,73 UpdateLocation,
58}74}
@@ -470,6 +486,9 @@ impl ToolbarItemView for BufferSearchBar { · 411 unmodified lines
470 486
471impl BufferSearchBar {487impl BufferSearchBar {
472 pub fn register(registrar: &mut impl SearchActionsRegistrar) {488 pub fn register(registrar: &mut impl SearchActionsRegistrar) {
489 registrar.register_handler(ForDeployed(|this, _: &FocusSearch, cx| {
490 this.query_editor.focus_handle(cx).focus(cx);
491 }));
473 registrar.register_handler(ForDeployed(|this, action: &ToggleCaseSensitive, cx| {492 registrar.register_handler(ForDeployed(|this, action: &ToggleCaseSensitive, cx| {
474 if this.supported_options().case {493 if this.supported_options().case {
475 this.toggle_case_sensitive(action, cx);494 this.toggle_case_sensitive(action, cx);
@@ -583,9 +602,17 @@ impl BufferSearchBar { · 107 unmodified lines
583 pub fn deploy(&mut self, deploy: &Deploy, cx: &mut ViewContext<Self>) -> bool {602 pub fn deploy(&mut self, deploy: &Deploy, cx: &mut ViewContext<Self>) -> bool {
584 if self.show(cx) {603 if self.show(cx) {
585 self.search_suggested(cx);604 self.search_suggested(cx);
605 self.replace_enabled = deploy.replace_enabled;
586 if deploy.focus {606 if deploy.focus {
587 self.select_query(cx);607 let mut handle = self.query_editor.focus_handle(cx).clone();
588 let handle = self.query_editor.focus_handle(cx);608 let mut select_query = true;
609 if deploy.replace_enabled && handle.is_focused(cx) {
610 handle = self.replacement_editor.focus_handle(cx).clone();
611 select_query = false;
612 };
613 if select_query {
614 self.select_query(cx);
615 }
589 cx.focus(&handle);616 cx.focus(&handle);
590 }617 }
591 return true;618 return true;
crates/search/src/project_search.rs+24−10
@@ -1,7 +1,8 @@
1use crate::{1use crate::{
2 mode::SearchMode, ActivateRegexMode, ActivateTextMode, CycleMode, NextHistoryQuery,2 mode::SearchMode, ActivateRegexMode, ActivateTextMode, CycleMode, FocusSearch,
3 PreviousHistoryQuery, ReplaceAll, ReplaceNext, SearchOptions, SelectNextMatch, SelectPrevMatch,3 NextHistoryQuery, PreviousHistoryQuery, ReplaceAll, ReplaceNext, SearchOptions,
4 ToggleCaseSensitive, ToggleIncludeIgnored, ToggleReplace, ToggleWholeWord,4 SelectNextMatch, SelectPrevMatch, ToggleCaseSensitive, ToggleIncludeIgnored, ToggleReplace,
5 ToggleWholeWord,
5};6};
6use anyhow::Context as _;7use anyhow::Context as _;
7use collections::{HashMap, HashSet};8use collections::{HashMap, HashSet};
@@ -60,6 +61,9 @@ const SEARCH_CONTEXT: u32 = 2; · 52 unmodified lines
60pub fn init(cx: &mut AppContext) {61pub fn init(cx: &mut AppContext) {
61 cx.set_global(ActiveSettings::default());62 cx.set_global(ActiveSettings::default());
62 cx.observe_new_views(|workspace: &mut Workspace, _cx| {63 cx.observe_new_views(|workspace: &mut Workspace, _cx| {
64 register_workspace_action(workspace, move |search_bar, _: &FocusSearch, cx| {
65 search_bar.focus_search(cx);
66 });
63 register_workspace_action(workspace, move |search_bar, _: &ToggleFilters, cx| {67 register_workspace_action(workspace, move |search_bar, _: &ToggleFilters, cx| {
64 search_bar.toggle_filters(cx);68 search_bar.toggle_filters(cx);
65 });69 });
@@ -797,7 +801,7 @@ impl ProjectSearchView { · 731 unmodified lines
797 // If no search exists in the workspace, create a new one.801 // If no search exists in the workspace, create a new one.
798 fn deploy_search(802 fn deploy_search(
799 workspace: &mut Workspace,803 workspace: &mut Workspace,
800 _: &workspace::DeploySearch,804 action: &workspace::DeploySearch,
801 cx: &mut ViewContext<Workspace>,805 cx: &mut ViewContext<Workspace>,
802 ) {806 ) {
803 let existing = workspace807 let existing = workspace
@@ -806,7 +810,7 @@ impl ProjectSearchView { · 2 unmodified lines
806 .items()810 .items()
807 .find_map(|item| item.downcast::<ProjectSearchView>());811 .find_map(|item| item.downcast::<ProjectSearchView>());
808 812
809 Self::existing_or_new_search(workspace, existing, cx)813 Self::existing_or_new_search(workspace, existing, action, cx);
810 }814 }
811 815
812 fn search_in_new(workspace: &mut Workspace, _: &SearchInNew, cx: &mut ViewContext<Workspace>) {816 fn search_in_new(workspace: &mut Workspace, _: &SearchInNew, cx: &mut ViewContext<Workspace>) {
@@ -846,12 +850,13 @@ impl ProjectSearchView { · 33 unmodified lines
846 _: &workspace::NewSearch,850 _: &workspace::NewSearch,
847 cx: &mut ViewContext<Workspace>,851 cx: &mut ViewContext<Workspace>,
848 ) {852 ) {
849 Self::existing_or_new_search(workspace, None, cx)853 Self::existing_or_new_search(workspace, None, &DeploySearch::find(), cx)
850 }854 }
851 855
852 fn existing_or_new_search(856 fn existing_or_new_search(
853 workspace: &mut Workspace,857 workspace: &mut Workspace,
854 existing: Option<View<ProjectSearchView>>,858 existing: Option<View<ProjectSearchView>>,
859 action: &workspace::DeploySearch,
855 cx: &mut ViewContext<Workspace>,860 cx: &mut ViewContext<Workspace>,
856 ) {861 ) {
857 let query = workspace.active_item(cx).and_then(|item| {862 let query = workspace.active_item(cx).and_then(|item| {
@@ -887,6 +892,7 @@ impl ProjectSearchView { · 29 unmodified lines
887 };892 };
888 893
889 search.update(cx, |search, cx| {894 search.update(cx, |search, cx| {
895 search.replace_enabled = action.replace_enabled;
890 if let Some(query) = query {896 if let Some(query) = query {
891 search.set_query(&query, cx);897 search.set_query(&query, cx);
892 }898 }
@@ -1172,6 +1178,14 @@ impl ProjectSearchBar { · 279 unmodified lines
1172 self.cycle_field(Direction::Prev, cx);1178 self.cycle_field(Direction::Prev, cx);
1173 }1179 }
1174 1180
1181 fn focus_search(&mut self, cx: &mut ViewContext<Self>) {
1182 if let Some(search_view) = self.active_project_search.as_ref() {
1183 search_view.update(cx, |search_view, cx| {
1184 search_view.query_editor.focus_handle(cx).focus(cx);
1185 });
1186 }
1187 }
1188
1175 fn cycle_field(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {1189 fn cycle_field(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
1176 let active_project_search = match &self.active_project_search {1190 let active_project_search = match &self.active_project_search {
1177 Some(active_project_search) => active_project_search,1191 Some(active_project_search) => active_project_search,
@@ -2011,7 +2025,7 @@ pub mod tests { · 833 unmodified lines
2011 .update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))2025 .update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))
2012 });2026 });
2013 2027
2014 ProjectSearchView::deploy_search(workspace, &workspace::DeploySearch, cx)2028 ProjectSearchView::deploy_search(workspace, &workspace::DeploySearch::find(), cx)
2015 })2029 })
2016 .unwrap();2030 .unwrap();
2017 2031
@@ -2160,7 +2174,7 @@ pub mod tests { · 142 unmodified lines
2160 2174
2161 workspace2175 workspace
2162 .update(cx, |workspace, cx| {2176 .update(cx, |workspace, cx| {
2163 ProjectSearchView::deploy_search(workspace, &workspace::DeploySearch, cx)2177 ProjectSearchView::deploy_search(workspace, &workspace::DeploySearch::find(), cx)
2164 })2178 })
2165 .unwrap();2179 .unwrap();
2166 window.update(cx, |_, cx| {2180 window.update(cx, |_, cx| {
@@ -3259,7 +3273,7 @@ pub mod tests { · 1092 unmodified lines
3259 .unwrap();3273 .unwrap();
3260 3274
3261 // Deploy a new search3275 // Deploy a new search
3262 cx.dispatch_action(window.into(), DeploySearch);3276 cx.dispatch_action(window.into(), DeploySearch::find());
3263 3277
3264 // Both panes should now have a project search in them3278 // Both panes should now have a project search in them
3265 window3279 window
@@ -3284,7 +3298,7 @@ pub mod tests { · 18 unmodified lines
3284 .unwrap();3298 .unwrap();
3285 3299
3286 // Deploy a new search3300 // Deploy a new search
3287 cx.dispatch_action(window.into(), DeploySearch);3301 cx.dispatch_action(window.into(), DeploySearch::find());
3288 3302
3289 // The project search view should now be focused in the second pane3303 // The project search view should now be focused in the second pane
3290 // And the number of items should be unchanged.3304 // And the number of items should be unchanged.
crates/search/src/search.rs+1−0
@@ -22,6 +22,7 @@ actions!( · 21 unmodified lines
22 search,22 search,
23 [23 [
24 CycleMode,24 CycleMode,
25 FocusSearch,
25 ToggleWholeWord,26 ToggleWholeWord,
26 ToggleCaseSensitive,27 ToggleCaseSensitive,
27 ToggleIncludeIgnored,28 ToggleIncludeIgnored,
crates/workspace/src/pane.rs+16−2
@@ -86,6 +86,12 @@ pub struct RevealInProjectPanel { · 85 unmodified lines
86 pub entry_id: Option<u64>,86 pub entry_id: Option<u64>,
87}87}
88 88
89#[derive(PartialEq, Clone, Deserialize)]
90pub struct DeploySearch {
91 #[serde(default)]
92 pub replace_enabled: bool,
93}
94
89impl_actions!(95impl_actions!(
90 pane,96 pane,
91 [97 [
@@ -93,7 +99,8 @@ impl_actions!( · 1 unmodified line
93 CloseActiveItem,99 CloseActiveItem,
94 CloseInactiveItems,100 CloseInactiveItems,
95 ActivateItem,101 ActivateItem,
96 RevealInProjectPanel102 RevealInProjectPanel,
103 DeploySearch,
97 ]104 ]
98);105);
99 106
@@ -107,7 +114,6 @@ actions!( · 7 unmodified lines
107 CloseItemsToTheLeft,114 CloseItemsToTheLeft,
108 CloseItemsToTheRight,115 CloseItemsToTheRight,
109 GoBack,116 GoBack,
110 DeploySearch,
111 GoForward,117 GoForward,
112 ReopenClosedItem,118 ReopenClosedItem,
113 SplitLeft,119 SplitLeft,
@@ -117,6 +123,14 @@ actions!( · 3 unmodified lines
117 ]123 ]
118);124);
119 125
126impl DeploySearch {
127 pub fn find() -> Self {
128 Self {
129 replace_enabled: false,
130 }
131 }
132}
133
120const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;134const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
121 135
122pub enum Event {136pub enum Event {
crates/zed/src/zed/app_menus.rs+1−1
@@ -67,7 +67,7 @@ pub fn app_menus() -> Vec<Menu<'static>> { · 66 unmodified lines
67 MenuItem::os_action("Copy", editor::actions::Copy, OsAction::Copy),67 MenuItem::os_action("Copy", editor::actions::Copy, OsAction::Copy),
68 MenuItem::os_action("Paste", editor::actions::Paste, OsAction::Paste),68 MenuItem::os_action("Paste", editor::actions::Paste, OsAction::Paste),
69 MenuItem::separator(),69 MenuItem::separator(),
70 MenuItem::action("Find", search::buffer_search::Deploy { focus: true }),70 MenuItem::action("Find", search::buffer_search::Deploy::find()),
71 MenuItem::action("Find In Project", workspace::NewSearch),71 MenuItem::action("Find In Project", workspace::NewSearch),
72 MenuItem::separator(),72 MenuItem::separator(),
73 MenuItem::action(73 MenuItem::action(

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t