@@ -11,15 +11,18 @@ use helix_core::{
1111
1212use helix_view::{
1313 document::{IndentStyle, Mode},
14+ input::{KeyCode, KeyEvent},
1415 view::{View, PADDING},
1516 Document, DocumentId, Editor, ViewId,
1617};
1718
19+use anyhow::anyhow;
1820use helix_lsp::{
1921 lsp,
2022 util::{lsp_pos_to_pos, lsp_range_to_range, pos_to_lsp_pos, range_to_lsp_range},
2123 OffsetEncoding,
2224};
25+use insert::*;
2326use movement::Movement;
2427
2528use crate::{
@@ -29,15 +32,15 @@ use crate::{
2932
3033use crate::application::{LspCallbackWrapper, LspCallbacks};
3134use futures_util::FutureExt;
32−use std::future::Future;
35+use std::{fmt, future::Future, path::Display, str::FromStr};
3336
3437use std::{
3538 borrow::Cow,
3639 path::{Path, PathBuf},
3740};
3841
39−use crossterm::event::{KeyCode, KeyEvent};
4042use once_cell::sync::Lazy;
43+use serde::de::{self, Deserialize, Deserializer};
4144
4245pub struct Context<'a> {
4346 pub selected_register: helix_view::RegisterSelection,
@@ -50,27 +53,6 @@ pub struct Context<'a> {
5053}
5154
5255impl<'a> Context<'a> {
53− #[inline]
54− pub fn view(&mut self) -> &mut View {
55− self.editor.view_mut()
56− }
57−
58− #[inline]
59− pub fn doc(&mut self) -> &mut Document {
60− let id = self.editor.view().doc;
61− &mut self.editor.documents[id]
62− }
63−
64− #[inline]
65− pub fn current(&mut self) -> (&mut View, &mut Document) {
66− self.editor.current()
67− }
68−
69− #[inline]
70− pub fn current_with_registers(&mut self) -> (&mut View, &mut Document, &mut Registers) {
71− self.editor.current_with_registers()
72− }
73−
7456 /// Push a new component onto the compositor.
7557 pub fn push_layer(&mut self, mut component: Box<dyn Component>) {
7658 self.callback = Some(Box::new(|compositor: &mut Compositor| {
@@ -107,6 +89,7 @@ impl<'a> Context<'a> {
10789 self.callbacks.push(callback);
10890 }
10991
92+ /// Returns 1 if no explicit count was provided
11093 #[inline]
11194 pub fn count(&self) -> usize {
11295 self.count.map_or(1, |v| v.get())
@@ -132,13 +115,189 @@ fn align_view(doc: &Document, view: &mut View, align: Align) {
132115 view.first_line = line.saturating_sub(relative);
133116}
134117
135−/// A command is a function that takes the current state and a count, and does a side-effect on the
136−/// state (usually by creating and applying a transaction).
137−pub type Command = fn(cx: &mut Context);
118+/// A command is composed of a static name, and a function that takes the current state plus a count,
119+/// and does a side-effect on the state (usually by creating and applying a transaction).
120+#[derive(Copy, Clone)]
121+pub struct Command(&'static str, fn(cx: &mut Context));
122+
123+macro_rules! commands {
124+ ( $($name:ident),* ) => {
125+ $(
126+ #[allow(non_upper_case_globals)]
127+ pub const $name: Self = Self(stringify!($name), $name);
128+ )*
129+
130+ pub const COMMAND_LIST: &'static [Self] = &[
131+ $( Self::$name, )*
132+ ];
133+ }
134+}
135+
136+impl Command {
137+ pub fn execute(&self, cx: &mut Context) {
138+ (self.1)(cx);
139+ }
140+
141+ pub fn name(&self) -> &'static str {
142+ self.0
143+ }
144+
145+ commands!(
146+ move_char_left,
147+ move_char_right,
148+ move_line_up,
149+ move_line_down,
150+ move_line_end,
151+ move_line_start,
152+ move_first_nonwhitespace,
153+ move_next_word_start,
154+ move_prev_word_start,
155+ move_next_word_end,
156+ move_file_start,
157+ move_file_end,
158+ extend_next_word_start,
159+ extend_prev_word_start,
160+ extend_next_word_end,
161+ find_till_char,
162+ find_next_char,
163+ extend_till_char,
164+ extend_next_char,
165+ till_prev_char,
166+ find_prev_char,
167+ extend_till_prev_char,
168+ extend_prev_char,
169+ extend_first_nonwhitespace,
170+ replace,
171+ page_up,
172+ page_down,
173+ half_page_up,
174+ half_page_down,
175+ extend_char_left,
176+ extend_char_right,
177+ extend_line_up,
178+ extend_line_down,
179+ extend_line_end,
180+ extend_line_start,
181+ select_all,
182+ select_regex,
183+ split_selection,
184+ split_selection_on_newline,
185+ search,
186+ search_next,
187+ extend_search_next,
188+ search_selection,
189+ select_line,
190+ extend_line,
191+ delete_selection,
192+ change_selection,
193+ collapse_selection,
194+ flip_selections,
195+ insert_mode,
196+ append_mode,
197+ command_mode,
198+ file_picker,
199+ buffer_picker,
200+ symbol_picker,
201+ prepend_to_line,
202+ append_to_line,
203+ open_below,
204+ open_above,
205+ normal_mode,
206+ goto_mode,
207+ select_mode,
208+ exit_select_mode,
209+ goto_definition,
210+ goto_type_definition,
211+ goto_implementation,
212+ goto_reference,
213+ goto_first_diag,
214+ goto_last_diag,
215+ goto_next_diag,
216+ goto_prev_diag,
217+ signature_help,
218+ insert_tab,
219+ insert_newline,
220+ delete_char_backward,
221+ delete_char_forward,
222+ delete_word_backward,
223+ undo,
224+ redo,
225+ yank,
226+ replace_with_yanked,
227+ paste_after,
228+ paste_before,
229+ indent,
230+ unindent,
231+ format_selections,
232+ join_selections,
233+ keep_selections,
234+ keep_primary_selection,
235+ save,
236+ completion,
237+ hover,
238+ toggle_comments,
239+ expand_selection,
240+ match_brackets,
241+ jump_forward,
242+ jump_backward,
243+ window_mode,
244+ rotate_view,
245+ hsplit,
246+ vsplit,
247+ wclose,
248+ select_register,
249+ space_mode,
250+ view_mode,
251+ left_bracket_mode,
252+ right_bracket_mode
253+ );
254+}
255+
256+impl fmt::Debug for Command {
257+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258+ let Command(name, _) = self;
259+ f.debug_tuple("Command").field(name).finish()
260+ }
261+}
262+
263+impl fmt::Display for Command {
264+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265+ let Command(name, _) = self;
266+ f.write_str(name)
267+ }
268+}
269+
270+impl std::str::FromStr for Command {
271+ type Err = anyhow::Error;
272+
273+ fn from_str(s: &str) -> Result<Self, Self::Err> {
274+ Command::COMMAND_LIST
275+ .iter()
276+ .copied()
277+ .find(|cmd| cmd.0 == s)
278+ .ok_or_else(|| anyhow!("No command named '{}'", s))
279+ }
280+}
138281
139−pub fn move_char_left(cx: &mut Context) {
282+impl<'de> Deserialize<'de> for Command {
283+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
284+ where
285+ D: Deserializer<'de>,
286+ {
287+ let s = String::deserialize(deserializer)?;
288+ s.parse().map_err(de::Error::custom)
289+ }
290+}
291+
292+impl PartialEq for Command {
293+ fn eq(&self, other: &Self) -> bool {
294+ self.name() == other.name()
295+ }
296+}
297+
298+fn move_char_left(cx: &mut Context) {
140299 let count = cx.count();
141− let (view, doc) = cx.current();
300+ let (view, doc) = current!(cx.editor);
142301 let text = doc.text().slice(..);
143302 let selection = doc.selection(view.id).transform(|range| {
144303 movement::move_horizontally(text, range, Direction::Backward, count, Movement::Move)
@@ -146,9 +305,9 @@ pub fn move_char_left(cx: &mut Context) {
146305 doc.set_selection(view.id, selection);
147306}
148307
149−pub fn move_char_right(cx: &mut Context) {
308+fn move_char_right(cx: &mut Context) {
150309 let count = cx.count();
151− let (view, doc) = cx.current();
310+ let (view, doc) = current!(cx.editor);
152311 let text = doc.text().slice(..);
153312 let selection = doc.selection(view.id).transform(|range| {
154313 movement::move_horizontally(text, range, Direction::Forward, count, Movement::Move)
@@ -156,9 +315,9 @@ pub fn move_char_right(cx: &mut Context) {
156315 doc.set_selection(view.id, selection);
157316}
158317
159−pub fn move_line_up(cx: &mut Context) {
318+fn move_line_up(cx: &mut Context) {
160319 let count = cx.count();
161− let (view, doc) = cx.current();
320+ let (view, doc) = current!(cx.editor);
162321 let text = doc.text().slice(..);
163322 let selection = doc.selection(view.id).transform(|range| {
164323 movement::move_vertically(text, range, Direction::Backward, count, Movement::Move)
@@ -166,9 +325,9 @@ pub fn move_line_up(cx: &mut Context) {
166325 doc.set_selection(view.id, selection);
167326}
168327
169−pub fn move_line_down(cx: &mut Context) {
328+fn move_line_down(cx: &mut Context) {
170329 let count = cx.count();
171− let (view, doc) = cx.current();
330+ let (view, doc) = current!(cx.editor);
172331 let text = doc.text().slice(..);
173332 let selection = doc.selection(view.id).transform(|range| {
174333 movement::move_vertically(text, range, Direction::Forward, count, Movement::Move)
@@ -176,8 +335,8 @@ pub fn move_line_down(cx: &mut Context) {
176335 doc.set_selection(view.id, selection);
177336}
178337
179−pub fn move_line_end(cx: &mut Context) {
180− let (view, doc) = cx.current();
338+fn move_line_end(cx: &mut Context) {
339+ let (view, doc) = current!(cx.editor);
181340
182341 let selection = doc.selection(view.id).transform(|range| {
183342 let text = doc.text();
@@ -195,8 +354,8 @@ pub fn move_line_end(cx: &mut Context) {
195354 doc.set_selection(view.id, selection);
196355}
197356
198−pub fn move_line_start(cx: &mut Context) {
199− let (view, doc) = cx.current();
357+fn move_line_start(cx: &mut Context) {
358+ let (view, doc) = current!(cx.editor);
200359
201360 let selection = doc.selection(view.id).transform(|range| {
202361 let text = doc.text();
@@ -210,8 +369,8 @@ pub fn move_line_start(cx: &mut Context) {
210369 doc.set_selection(view.id, selection);
211370}
212371
213−pub fn move_first_nonwhitespace(cx: &mut Context) {
214− let (view, doc) = cx.current();
372+fn move_first_nonwhitespace(cx: &mut Context) {
373+ let (view, doc) = current!(cx.editor);
215374
216375 let selection = doc.selection(view.id).transform(|range| {
217376 let text = doc.text();
@@ -232,9 +391,9 @@ pub fn move_first_nonwhitespace(cx: &mut Context) {
232391// Range::new(if Move { pos } if Extend { range.anchor }, pos)
233392// since these all really do the same thing
234393
235−pub fn move_next_word_start(cx: &mut Context) {
394+fn move_next_word_start(cx: &mut Context) {
236395 let count = cx.count();
237− let (view, doc) = cx.current();
396+ let (view, doc) = current!(cx.editor);
238397 let text = doc.text().slice(..);
239398
240399 let selection = doc
@@ -244,9 +403,9 @@ pub fn move_next_word_start(cx: &mut Context) {
244403 doc.set_selection(view.id, selection);
245404}
246405
247−pub fn move_prev_word_start(cx: &mut Context) {
406+fn move_prev_word_start(cx: &mut Context) {
248407 let count = cx.count();
249− let (view, doc) = cx.current();
408+ let (view, doc) = current!(cx.editor);
250409 let text = doc.text().slice(..);
251410
252411 let selection = doc
@@ -256,9 +415,9 @@ pub fn move_prev_word_start(cx: &mut Context) {
256415 doc.set_selection(view.id, selection);
257416}
258417
259−pub fn move_next_word_end(cx: &mut Context) {
418+fn move_next_word_end(cx: &mut Context) {
260419 let count = cx.count();
261− let (view, doc) = cx.current();
420+ let (view, doc) = current!(cx.editor);
262421 let text = doc.text().slice(..);
263422
264423 let selection = doc
@@ -268,23 +427,23 @@ pub fn move_next_word_end(cx: &mut Context) {
268427 doc.set_selection(view.id, selection);
269428}
270429
271−pub fn move_file_start(cx: &mut Context) {
430+fn move_file_start(cx: &mut Context) {
272431 push_jump(cx.editor);
273− let (view, doc) = cx.current();
432+ let (view, doc) = current!(cx.editor);
274433 doc.set_selection(view.id, Selection::point(0));
275434}
276435
277−pub fn move_file_end(cx: &mut Context) {
436+fn move_file_end(cx: &mut Context) {
278437 push_jump(cx.editor);
279− let (view, doc) = cx.current();
438+ let (view, doc) = current!(cx.editor);
280439 let text = doc.text();
281440 let last_line = text.line_to_char(text.len_lines().saturating_sub(2));
282441 doc.set_selection(view.id, Selection::point(last_line));
283442}
284443
285−pub fn extend_next_word_start(cx: &mut Context) {
444+fn extend_next_word_start(cx: &mut Context) {
286445 let count = cx.count();
287− let (view, doc) = cx.current();
446+ let (view, doc) = current!(cx.editor);
288447 let text = doc.text().slice(..);
289448
290449 let selection = doc.selection(view.id).transform(|mut range| {
@@ -296,9 +455,9 @@ pub fn extend_next_word_start(cx: &mut Context) {
296455 doc.set_selection(view.id, selection);
297456}
298457
299−pub fn extend_prev_word_start(cx: &mut Context) {
458+fn extend_prev_word_start(cx: &mut Context) {
300459 let count = cx.count();
301− let (view, doc) = cx.current();
460+ let (view, doc) = current!(cx.editor);
302461 let text = doc.text().slice(..);
303462
304463 let selection = doc.selection(view.id).transform(|mut range| {
@@ -309,9 +468,9 @@ pub fn extend_prev_word_start(cx: &mut Context) {
309468 doc.set_selection(view.id, selection);
310469}
311470
312−pub fn extend_next_word_end(cx: &mut Context) {
471+fn extend_next_word_end(cx: &mut Context) {
313472 let count = cx.count();
314− let (view, doc) = cx.current();
473+ let (view, doc) = current!(cx.editor);
315474 let text = doc.text().slice(..);
316475
317476 let selection = doc.selection(view.id).transform(|mut range| {
@@ -348,7 +507,7 @@ where
348507 _ => return,
349508 };
350509
351− let (view, doc) = cx.current();
510+ let (view, doc) = current!(cx.editor);
352511 let text = doc.text().slice(..);
353512
354513 let selection = doc.selection(view.id).transform(|mut range| {
@@ -367,7 +526,7 @@ where
367526 })
368527}
369528
370−pub fn find_till_char(cx: &mut Context) {
529+fn find_till_char(cx: &mut Context) {
371530 find_char_impl(
372531 cx,
373532 search::find_nth_next,
@@ -376,7 +535,7 @@ pub fn find_till_char(cx: &mut Context) {
376535 )
377536}
378537
379−pub fn find_next_char(cx: &mut Context) {
538+fn find_next_char(cx: &mut Context) {
380539 find_char_impl(
381540 cx,
382541 search::find_nth_next,
@@ -385,7 +544,7 @@ pub fn find_next_char(cx: &mut Context) {
385544 )
386545}
387546
388−pub fn extend_till_char(cx: &mut Context) {
547+fn extend_till_char(cx: &mut Context) {
389548 find_char_impl(
390549 cx,
391550 search::find_nth_next,
@@ -394,7 +553,7 @@ pub fn extend_till_char(cx: &mut Context) {
394553 )
395554}
396555
397−pub fn extend_next_char(cx: &mut Context) {
556+fn extend_next_char(cx: &mut Context) {
398557 find_char_impl(
399558 cx,
400559 search::find_nth_next,
@@ -403,7 +562,7 @@ pub fn extend_next_char(cx: &mut Context) {
403562 )
404563}
405564
406−pub fn till_prev_char(cx: &mut Context) {
565+fn till_prev_char(cx: &mut Context) {
407566 find_char_impl(
408567 cx,
409568 search::find_nth_prev,
@@ -412,7 +571,7 @@ pub fn till_prev_char(cx: &mut Context) {
412571 )
413572}
414573
415−pub fn find_prev_char(cx: &mut Context) {
574+fn find_prev_char(cx: &mut Context) {
416575 find_char_impl(
417576 cx,
418577 search::find_nth_prev,
@@ -421,7 +580,7 @@ pub fn find_prev_char(cx: &mut Context) {
421580 )
422581}
423582
424−pub fn extend_till_prev_char(cx: &mut Context) {
583+fn extend_till_prev_char(cx: &mut Context) {
425584 find_char_impl(
426585 cx,
427586 search::find_nth_prev,
@@ -430,7 +589,7 @@ pub fn extend_till_prev_char(cx: &mut Context) {
430589 )
431590}
432591
433−pub fn extend_prev_char(cx: &mut Context) {
592+fn extend_prev_char(cx: &mut Context) {
434593 find_char_impl(
435594 cx,
436595 search::find_nth_prev,
@@ -439,8 +598,8 @@ pub fn extend_prev_char(cx: &mut Context) {
439598 )
440599}
441600
442−pub fn extend_first_nonwhitespace(cx: &mut Context) {
443− let (view, doc) = cx.current();
601+fn extend_first_nonwhitespace(cx: &mut Context) {
602+ let (view, doc) = current!(cx.editor);
444603
445604 let selection = doc.selection(view.id).transform(|range| {
446605 let text = doc.text();
@@ -457,7 +616,7 @@ pub fn extend_first_nonwhitespace(cx: &mut Context) {
457616 doc.set_selection(view.id, selection);
458617}
459618
460−pub fn replace(cx: &mut Context) {
619+fn replace(cx: &mut Context) {
461620 // need to wait for next key
462621 cx.on_next_key(move |cx, event| {
463622 let ch = match event {
@@ -473,7 +632,7 @@ pub fn replace(cx: &mut Context) {
473632 };
474633
475634 if let Some(ch) = ch {
476− let (view, doc) = cx.current();
635+ let (view, doc) = current!(cx.editor);
477636
478637 let transaction =
479638 Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
@@ -497,7 +656,7 @@ pub fn replace(cx: &mut Context) {
497656
498657fn scroll(cx: &mut Context, offset: usize, direction: Direction) {
499658 use Direction::*;
500− let (view, doc) = cx.current();
659+ let (view, doc) = current!(cx.editor);
501660 let cursor = coords_at_pos(doc.text().slice(..), doc.selection(view.id).cursor());
502661 let doc_last_line = doc.text().len_lines() - 1;
503662
@@ -537,33 +696,33 @@ fn scroll(cx: &mut Context, offset: usize, direction: Direction) {
537696 doc.set_selection(view.id, Selection::point(pos));
538697}
539698
540−pub fn page_up(cx: &mut Context) {
541− let view = cx.view();
699+fn page_up(cx: &mut Context) {
700+ let view = view!(cx.editor);
542701 let offset = view.area.height as usize;
543702 scroll(cx, offset, Direction::Backward);
544703}
545704
546−pub fn page_down(cx: &mut Context) {
547− let view = cx.view();
705+fn page_down(cx: &mut Context) {
706+ let view = view!(cx.editor);
548707 let offset = view.area.height as usize;
549708 scroll(cx, offset, Direction::Forward);
550709}
551710
552−pub fn half_page_up(cx: &mut Context) {
553− let view = cx.view();
711+fn half_page_up(cx: &mut Context) {
712+ let view = view!(cx.editor);
554713 let offset = view.area.height as usize / 2;
555714 scroll(cx, offset, Direction::Backward);
556715}
557716
558−pub fn half_page_down(cx: &mut Context) {
559− let view = cx.view();
717+fn half_page_down(cx: &mut Context) {
718+ let view = view!(cx.editor);
560719 let offset = view.area.height as usize / 2;
561720 scroll(cx, offset, Direction::Forward);
562721}
563722
564−pub fn extend_char_left(cx: &mut Context) {
723+fn extend_char_left(cx: &mut Context) {
565724 let count = cx.count();
566− let (view, doc) = cx.current();
725+ let (view, doc) = current!(cx.editor);
567726 let text = doc.text().slice(..);
568727 let selection = doc.selection(view.id).transform(|range| {
569728 movement::move_horizontally(text, range, Direction::Backward, count, Movement::Extend)
@@ -571,9 +730,9 @@ pub fn extend_char_left(cx: &mut Context) {
571730 doc.set_selection(view.id, selection);
572731}
573732
574−pub fn extend_char_right(cx: &mut Context) {
733+fn extend_char_right(cx: &mut Context) {
575734 let count = cx.count();
576− let (view, doc) = cx.current();
735+ let (view, doc) = current!(cx.editor);
577736 let text = doc.text().slice(..);
578737 let selection = doc.selection(view.id).transform(|range| {
579738 movement::move_horizontally(text, range, Direction::Forward, count, Movement::Extend)
@@ -581,9 +740,9 @@ pub fn extend_char_right(cx: &mut Context) {
581740 doc.set_selection(view.id, selection);
582741}
583742
584−pub fn extend_line_up(cx: &mut Context) {
743+fn extend_line_up(cx: &mut Context) {
585744 let count = cx.count();
586− let (view, doc) = cx.current();
745+ let (view, doc) = current!(cx.editor);
587746 let text = doc.text().slice(..);
588747 let selection = doc.selection(view.id).transform(|range| {
589748 movement::move_vertically(text, range, Direction::Backward, count, Movement::Extend)
@@ -591,9 +750,9 @@ pub fn extend_line_up(cx: &mut Context) {
591750 doc.set_selection(view.id, selection);
592751}
593752
594−pub fn extend_line_down(cx: &mut Context) {
753+fn extend_line_down(cx: &mut Context) {
595754 let count = cx.count();
596− let (view, doc) = cx.current();
755+ let (view, doc) = current!(cx.editor);
597756 let text = doc.text().slice(..);
598757 let selection = doc.selection(view.id).transform(|range| {
599758 movement::move_vertically(text, range, Direction::Forward, count, Movement::Extend)
@@ -601,8 +760,8 @@ pub fn extend_line_down(cx: &mut Context) {
601760 doc.set_selection(view.id, selection);
602761}
603762
604−pub fn extend_line_end(cx: &mut Context) {
605− let (view, doc) = cx.current();
763+fn extend_line_end(cx: &mut Context) {
764+ let (view, doc) = current!(cx.editor);
606765
607766 let selection = doc.selection(view.id).transform(|range| {
608767 let text = doc.text();
@@ -620,8 +779,8 @@ pub fn extend_line_end(cx: &mut Context) {
620779 doc.set_selection(view.id, selection);
621780}
622781
623−pub fn extend_line_start(cx: &mut Context) {
624− let (view, doc) = cx.current();
782+fn extend_line_start(cx: &mut Context) {
783+ let (view, doc) = current!(cx.editor);
625784
626785 let selection = doc.selection(view.id).transform(|range| {
627786 let text = doc.text();
@@ -635,14 +794,14 @@ pub fn extend_line_start(cx: &mut Context) {
635794 doc.set_selection(view.id, selection);
636795}
637796
638−pub fn select_all(cx: &mut Context) {
639− let (view, doc) = cx.current();
797+fn select_all(cx: &mut Context) {
798+ let (view, doc) = current!(cx.editor);
640799
641800 let end = doc.text().len_chars().saturating_sub(1);
642801 doc.set_selection(view.id, Selection::single(0, end))
643802}
644803
645−pub fn select_regex(cx: &mut Context) {
804+fn select_regex(cx: &mut Context) {
646805 let prompt = ui::regex_prompt(cx, "select:".to_string(), move |view, doc, _, regex| {
647806 let text = doc.text().slice(..);
648807 if let Some(selection) = selection::select_on_matches(text, doc.selection(view.id), ®ex)
@@ -654,7 +813,7 @@ pub fn select_regex(cx: &mut Context) {
654813 cx.push_layer(Box::new(prompt));
655814}
656815
657−pub fn split_selection(cx: &mut Context) {
816+fn split_selection(cx: &mut Context) {
658817 let prompt = ui::regex_prompt(cx, "split:".to_string(), move |view, doc, _, regex| {
659818 let text = doc.text().slice(..);
660819 let selection = selection::split_on_matches(text, doc.selection(view.id), ®ex);
@@ -664,8 +823,8 @@ pub fn split_selection(cx: &mut Context) {
664823 cx.push_layer(Box::new(prompt));
665824}
666825
667−pub fn split_selection_on_newline(cx: &mut Context) {
668− let (view, doc) = cx.current();
826+fn split_selection_on_newline(cx: &mut Context) {
827+ let (view, doc) = current!(cx.editor);
669828 let text = doc.text().slice(..);
670829 // only compile the regex once
671830 #[allow(clippy::trivial_regex)]
@@ -716,8 +875,8 @@ fn search_impl(doc: &mut Document, view: &mut View, contents: &str, regex: &Rege
716875}
717876
718877// TODO: use one function for search vs extend
719−pub fn search(cx: &mut Context) {
720− let (view, doc) = cx.current();
878+fn search(cx: &mut Context) {
879+ let (view, doc) = current!(cx.editor);
721880
722881 // TODO: could probably share with select_on_matches?
723882
@@ -738,10 +897,10 @@ pub fn search(cx: &mut Context) {
738897
739898 cx.push_layer(Box::new(prompt));
740899}
741−// can't search next for ""compose"" for some reason
742900
743−pub fn search_next_impl(cx: &mut Context, extend: bool) {
744− let (view, doc, registers) = cx.current_with_registers();
901+fn search_next_impl(cx: &mut Context, extend: bool) {
902+ let (view, doc) = current!(cx.editor);
903+ let registers = &mut cx.editor.registers;
745904 if let Some(query) = registers.read('\\') {
746905 let query = query.first().unwrap();
747906 let contents = doc.text().slice(..).to_string();
@@ -750,16 +909,16 @@ pub fn search_next_impl(cx: &mut Context, extend: bool) {
750909 }
751910}
752911
753−pub fn search_next(cx: &mut Context) {
912+fn search_next(cx: &mut Context) {
754913 search_next_impl(cx, false);
755914}
756915
757−pub fn extend_search_next(cx: &mut Context) {
916+fn extend_search_next(cx: &mut Context) {
758917 search_next_impl(cx, true);
759918}
760919
761−pub fn search_selection(cx: &mut Context) {
762− let (view, doc) = cx.current();
920+fn search_selection(cx: &mut Context) {
921+ let (view, doc) = current!(cx.editor);
763922 let contents = doc.text().slice(..);
764923 let query = doc.selection(view.id).primary().fragment(contents);
765924 let regex = regex::escape(&query);
@@ -773,9 +932,9 @@ pub fn search_selection(cx: &mut Context) {
773932
774933//
775934
776−pub fn select_line(cx: &mut Context) {
935+fn select_line(cx: &mut Context) {
777936 let count = cx.count();
778− let (view, doc) = cx.current();
937+ let (view, doc) = current!(cx.editor);
779938
780939 let pos = doc.selection(view.id).primary();
781940 let text = doc.text();
@@ -788,9 +947,9 @@ pub fn select_line(cx: &mut Context) {
788947
789948 doc.set_selection(view.id, Selection::single(start, end));
790949}
791−pub fn extend_line(cx: &mut Context) {
950+fn extend_line(cx: &mut Context) {
792951 let count = cx.count();
793− let (view, doc) = cx.current();
952+ let (view, doc) = current!(cx.editor);
794953
795954 let pos = doc.selection(view.id).primary();
796955 let text = doc.text();
@@ -830,9 +989,10 @@ fn delete_selection_impl(reg: &mut Register, doc: &mut Document, view_id: ViewId
830989 doc.apply(&transaction, view_id);
831990}
832991
833−pub fn delete_selection(cx: &mut Context) {
992+fn delete_selection(cx: &mut Context) {
834993 let reg_name = cx.selected_register.name();
835− let (view, doc, registers) = cx.current_with_registers();
994+ let (view, doc) = current!(cx.editor);
995+ let registers = &mut cx.editor.registers;
836996 let reg = registers.get_or_insert(reg_name);
837997 delete_selection_impl(reg, doc, view.id);
838998
@@ -842,16 +1002,17 @@ pub fn delete_selection(cx: &mut Context) {
8421002 exit_select_mode(cx);
8431003}
8441004
845−pub fn change_selection(cx: &mut Context) {
1005+fn change_selection(cx: &mut Context) {
8461006 let reg_name = cx.selected_register.name();
847− let (view, doc, registers) = cx.current_with_registers();
1007+ let (view, doc) = current!(cx.editor);
1008+ let registers = &mut cx.editor.registers;
8481009 let reg = registers.get_or_insert(reg_name);
8491010 delete_selection_impl(reg, doc, view.id);
8501011 enter_insert_mode(doc);
8511012}
8521013
853−pub fn collapse_selection(cx: &mut Context) {
854− let (view, doc) = cx.current();
1014+fn collapse_selection(cx: &mut Context) {
1015+ let (view, doc) = current!(cx.editor);
8551016 let selection = doc
8561017 .selection(view.id)
8571018 .transform(|range| Range::new(range.head, range.head));
@@ -859,8 +1020,8 @@ pub fn collapse_selection(cx: &mut Context) {
8591020 doc.set_selection(view.id, selection);
8601021}
8611022
862−pub fn flip_selections(cx: &mut Context) {
863− let (view, doc) = cx.current();
1023+fn flip_selections(cx: &mut Context) {
1024+ let (view, doc) = current!(cx.editor);
8641025 let selection = doc
8651026 .selection(view.id)
8661027 .transform(|range| Range::new(range.head, range.anchor));
@@ -873,8 +1034,8 @@ fn enter_insert_mode(doc: &mut Document) {
8731034}
8741035
8751036// inserts at the start of each selection
876−pub fn insert_mode(cx: &mut Context) {
877− let (view, doc) = cx.current();
1037+fn insert_mode(cx: &mut Context) {
1038+ let (view, doc) = current!(cx.editor);
8781039 enter_insert_mode(doc);
8791040
8801041 let selection = doc
@@ -884,8 +1045,8 @@ pub fn insert_mode(cx: &mut Context) {
8841045}
8851046
8861047// inserts at the end of each selection
887−pub fn append_mode(cx: &mut Context) {
888− let (view, doc) = cx.current();
1048+fn append_mode(cx: &mut Context) {
1049+ let (view, doc) = current!(cx.editor);
8891050 enter_insert_mode(doc);
8901051 doc.restore_cursor = true;
8911052
@@ -918,7 +1079,7 @@ mod cmd {
9181079 use ui::completers::{self, Completer};
9191080
9201081 #[derive(Clone)]
921− pub struct Command {
1082+ pub struct TypableCommand {
9221083 pub name: &'static str,
9231084 pub alias: Option<&'static str>,
9241085 pub doc: &'static str,
@@ -932,11 +1093,11 @@ mod cmd {
9321093 if editor.tree.views().count() == 1 && buffers_remaining_impl(editor) {
9331094 return;
9341095 }
935− editor.close(editor.view().id, /* close_buffer */ false);
1096+ editor.close(view!(editor).id, /* close_buffer */ false);
9361097 }
9371098
9381099 fn force_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
939− editor.close(editor.view().id, /* close_buffer */ false);
1100+ editor.close(view!(editor).id, /* close_buffer */ false);
9401101 }
9411102
9421103 fn open(editor: &mut Editor, args: &[&str], event: PromptEvent) {
@@ -978,7 +1139,7 @@ mod cmd {
9781139 }
9791140
9801141 fn write(editor: &mut Editor, args: &[&str], event: PromptEvent) {
981− let (view, doc) = editor.current();
1142+ let (view, doc) = current!(editor);
9821143 if let Err(e) = write_impl(view, doc, args.first()) {
9831144 editor.set_error(e.to_string());
9841145 };
@@ -989,7 +1150,7 @@ mod cmd {
9891150 }
9901151
9911152 fn format(editor: &mut Editor, args: &[&str], event: PromptEvent) {
992− let (view, doc) = editor.current();
1153+ let (view, doc) = current!(editor);
9931154
9941155 doc.format(view.id)
9951156 }
@@ -999,7 +1160,7 @@ mod cmd {
9991160
10001161 // If no argument, report current indent style.
10011162 if args.is_empty() {
1002− let style = editor.current().1.indent_style;
1163+ let style = current!(editor).1.indent_style;
10031164 editor.set_status(match style {
10041165 Tabs => "tabs".into(),
10051166 Spaces(1) => "1 space".into(),
@@ -1022,7 +1183,7 @@ mod cmd {
10221183 };
10231184
10241185 if let Some(s) = style {
1025− let (_, doc) = editor.current();
1186+ let doc = doc_mut!(editor);
10261187 doc.indent_style = s;
10271188 } else {
10281189 // Invalid argument.
@@ -1038,7 +1199,7 @@ mod cmd {
10381199 return;
10391200 }
10401201 };
1041− let (view, doc) = editor.current();
1202+ let (view, doc) = current!(editor);
10421203 doc.earlier(view.id, uk)
10431204 }
10441205
@@ -1050,12 +1211,12 @@ mod cmd {
10501211 return;
10511212 }
10521213 };
1053− let (view, doc) = editor.current();
1214+ let (view, doc) = current!(editor);
10541215 doc.later(view.id, uk)
10551216 }
10561217
10571218 fn write_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1058− let (view, doc) = editor.current();
1219+ let (view, doc) = current!(editor);
10591220 if let Err(e) = write_impl(view, doc, args.first()) {
10601221 editor.set_error(e.to_string());
10611222 return;
@@ -1076,8 +1237,8 @@ mod cmd {
10761237 .filter(|doc| doc.is_modified())
10771238 .map(|doc| {
10781239 doc.relative_path()
1079− .and_then(|path| path.to_str())
1080− .unwrap_or("[scratch]")
1240+ .map(|path| path.to_string_lossy().to_string())
1241+ .unwrap_or_else(|| "[scratch]".into())
10811242 })
10821243 .collect();
10831244 if !modified.is_empty() {
@@ -1157,113 +1318,113 @@ mod cmd {
11571318 quit_all_impl(editor, args, event, true)
11581319 }
11591320
1160− pub const COMMAND_LIST: &[Command] = &[
1161− Command {
1321+ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
1322+ TypableCommand {
11621323 name: "quit",
11631324 alias: Some("q"),
11641325 doc: "Close the current view.",
11651326 fun: quit,
11661327 completer: None,
11671328 },
1168− Command {
1329+ TypableCommand {
11691330 name: "quit!",
11701331 alias: Some("q!"),
11711332 doc: "Close the current view.",
11721333 fun: force_quit,
11731334 completer: None,
11741335 },
1175− Command {
1336+ TypableCommand {
11761337 name: "open",
11771338 alias: Some("o"),
11781339 doc: "Open a file from disk into the current view.",
11791340 fun: open,
11801341 completer: Some(completers::filename),
11811342 },
1182− Command {
1343+ TypableCommand {
11831344 name: "write",
11841345 alias: Some("w"),
11851346 doc: "Write changes to disk. Accepts an optional path (:write some/path.txt)",
11861347 fun: write,
11871348 completer: Some(completers::filename),
11881349 },
1189− Command {
1350+ TypableCommand {
11901351 name: "new",
11911352 alias: Some("n"),
11921353 doc: "Create a new scratch buffer.",
11931354 fun: new_file,
11941355 completer: Some(completers::filename),
11951356 },
1196− Command {
1357+ TypableCommand {
11971358 name: "format",
11981359 alias: Some("fmt"),
11991360 doc: "Format the file using a formatter.",
12001361 fun: format,
12011362 completer: None,
12021363 },
1203− Command {
1364+ TypableCommand {
12041365 name: "indent-style",
12051366 alias: None,
12061367 doc: "Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.)",
12071368 fun: set_indent_style,
12081369 completer: None,
12091370 },
1210− Command {
1371+ TypableCommand {
12111372 name: "earlier",
12121373 alias: Some("ear"),
12131374 doc: "Jump back to an earlier point in edit history. Accepts a number of steps or a time span.",
12141375 fun: earlier,
12151376 completer: None,
12161377 },
1217− Command {
1378+ TypableCommand {
12181379 name: "later",
12191380 alias: Some("lat"),
12201381 doc: "Jump to a later point in edit history. Accepts a number of steps or a time span.",
12211382 fun: later,
12221383 completer: None,
12231384 },
1224− Command {
1385+ TypableCommand {
12251386 name: "write-quit",
12261387 alias: Some("wq"),
12271388 doc: "Writes changes to disk and closes the current view. Accepts an optional path (:wq some/path.txt)",
12281389 fun: write_quit,
12291390 completer: Some(completers::filename),
12301391 },
1231− Command {
1392+ TypableCommand {
12321393 name: "write-quit!",
12331394 alias: Some("wq!"),
12341395 doc: "Writes changes to disk and closes the current view forcefully. Accepts an optional path (:wq! some/path.txt)",
12351396 fun: force_write_quit,
12361397 completer: Some(completers::filename),
12371398 },
1238− Command {
1399+ TypableCommand {
12391400 name: "write-all",
12401401 alias: Some("wa"),
12411402 doc: "Writes changes from all views to disk.",
12421403 fun: write_all,
12431404 completer: None,
12441405 },
1245− Command {
1406+ TypableCommand {
12461407 name: "write-quit-all",
12471408 alias: Some("wqa"),
12481409 doc: "Writes changes from all views to disk and close all views.",
12491410 fun: write_all_quit,
12501411 completer: None,
12511412 },
1252− Command {
1413+ TypableCommand {
12531414 name: "write-quit-all!",
12541415 alias: Some("wqa!"),
12551416 doc: "Writes changes from all views to disk and close all views forcefully (ignoring unsaved changes).",
12561417 fun: force_write_all_quit,
12571418 completer: None,
12581419 },
1259− Command {
1420+ TypableCommand {
12601421 name: "quit-all",
12611422 alias: Some("qa"),
12621423 doc: "Close all views.",
12631424 fun: quit_all,
12641425 completer: None,
12651426 },
1266− Command {
1427+ TypableCommand {
12671428 name: "quit-all!",
12681429 alias: Some("qa!"),
12691430 doc: "Close all views forcefully (ignoring unsaved changes).",
@@ -1273,10 +1434,10 @@ mod cmd {
12731434
12741435 ];
12751436
1276− pub static COMMANDS: Lazy<HashMap<&'static str, &'static Command>> = Lazy::new(|| {
1437+ pub static COMMANDS: Lazy<HashMap<&'static str, &'static TypableCommand>> = Lazy::new(|| {
12771438 let mut map = HashMap::new();
12781439
1279− for cmd in COMMAND_LIST {
1440+ for cmd in TYPABLE_COMMAND_LIST {
12801441 map.insert(cmd.name, cmd);
12811442 if let Some(alias) = cmd.alias {
12821443 map.insert(alias, cmd);
@@ -1287,7 +1448,7 @@ mod cmd {
12871448 });
12881449}
12891450
1290−pub fn command_mode(cx: &mut Context) {
1451+fn command_mode(cx: &mut Context) {
12911452 // TODO: completion items should have a info section that would get displayed in
12921453 // a popup above the prompt when items are tabbed over
12931454
@@ -1302,7 +1463,7 @@ pub fn command_mode(cx: &mut Context) {
13021463 if parts.len() <= 1 {
13031464 use std::{borrow::Cow, ops::Range};
13041465 let end = 0..;
1305− cmd::COMMAND_LIST
1466+ cmd::TYPABLE_COMMAND_LIST
13061467 .iter()
13071468 .filter(|command| command.name.contains(input))
13081469 .map(|command| (end.clone(), Cow::Borrowed(command.name)))
@@ -1310,7 +1471,7 @@ pub fn command_mode(cx: &mut Context) {
13101471 } else {
13111472 let part = parts.last().unwrap();
13121473
1313− if let Some(cmd::Command {
1474+ if let Some(cmd::TypableCommand {
13141475 completer: Some(completer),
13151476 ..
13161477 }) = cmd::COMMANDS.get(parts[0])
@@ -1351,7 +1512,7 @@ pub fn command_mode(cx: &mut Context) {
13511512 prompt.doc_fn = Box::new(|input: &str| {
13521513 let part = input.split(' ').next().unwrap_or_default();
13531514
1354− if let Some(cmd::Command { doc, .. }) = cmd::COMMANDS.get(part) {
1515+ if let Some(cmd::TypableCommand { doc, .. }) = cmd::COMMANDS.get(part) {
13551516 return Some(doc);
13561517 }
13571518
@@ -1361,21 +1522,21 @@ pub fn command_mode(cx: &mut Context) {
13611522 cx.push_layer(Box::new(prompt));
13621523}
13631524
1364−pub fn file_picker(cx: &mut Context) {
1525+fn file_picker(cx: &mut Context) {
13651526 let root = find_root(None).unwrap_or_else(|| PathBuf::from("./"));
13661527 let picker = ui::file_picker(root);
13671528 cx.push_layer(Box::new(picker));
13681529}
13691530
1370−pub fn buffer_picker(cx: &mut Context) {
1531+fn buffer_picker(cx: &mut Context) {
13711532 use std::path::{Path, PathBuf};
1372− let current = cx.editor.view().doc;
1533+ let current = view!(cx.editor).doc;
13731534
13741535 let picker = Picker::new(
13751536 cx.editor
13761537 .documents
13771538 .iter()
1378− .map(|(id, doc)| (id, doc.relative_path().map(Path::to_path_buf)))
1539+ .map(|(id, doc)| (id, doc.relative_path()))
13791540 .collect(),
13801541 move |(id, path): &(DocumentId, Option<PathBuf>)| {
13811542 // format_fn
@@ -1398,7 +1559,7 @@ pub fn buffer_picker(cx: &mut Context) {
13981559 cx.push_layer(Box::new(picker));
13991560}
14001561
1401−pub fn symbol_picker(cx: &mut Context) {
1562+fn symbol_picker(cx: &mut Context) {
14021563 fn nested_to_flat(
14031564 list: &mut Vec<lsp::SymbolInformation>,
14041565 file: &lsp::TextDocumentIdentifier,
@@ -1417,7 +1578,7 @@ pub fn symbol_picker(cx: &mut Context) {
14171578 nested_to_flat(list, file, child);
14181579 }
14191580 }
1420− let (view, doc) = cx.current();
1581+ let (view, doc) = current!(cx.editor);
14211582
14221583 let language_server = match doc.language_server() {
14231584 Some(language_server) => language_server,
@@ -1438,7 +1599,7 @@ pub fn symbol_picker(cx: &mut Context) {
14381599 let symbols = match symbols {
14391600 lsp::DocumentSymbolResponse::Flat(symbols) => symbols,
14401601 lsp::DocumentSymbolResponse::Nested(symbols) => {
1441− let (_view, doc) = editor.current();
1602+ let (_view, doc) = current!(editor);
14421603 let mut flat_symbols = Vec::new();
14431604 for symbol in symbols {
14441605 nested_to_flat(&mut flat_symbols, &doc.identifier(), symbol)
@@ -1452,7 +1613,7 @@ pub fn symbol_picker(cx: &mut Context) {
14521613 |symbol| (&symbol.name).into(),
14531614 move |editor: &mut Editor, symbol, _action| {
14541615 push_jump(editor);
1455− let (view, doc) = editor.current();
1616+ let (view, doc) = current!(editor);
14561617
14571618 if let Some(range) =
14581619 lsp_range_to_range(doc.text(), symbol.location.range, offset_encoding)
@@ -1469,15 +1630,15 @@ pub fn symbol_picker(cx: &mut Context) {
14691630}
14701631
14711632// I inserts at the first nonwhitespace character of each line with a selection
1472−pub fn prepend_to_line(cx: &mut Context) {
1633+fn prepend_to_line(cx: &mut Context) {
14731634 move_first_nonwhitespace(cx);
1474− let doc = cx.doc();
1635+ let doc = doc_mut!(cx.editor);
14751636 enter_insert_mode(doc);
14761637}
14771638
14781639// A inserts at the end of each line with a selection
1479−pub fn append_to_line(cx: &mut Context) {
1480− let (view, doc) = cx.current();
1640+fn append_to_line(cx: &mut Context) {
1641+ let (view, doc) = current!(cx.editor);
14811642 enter_insert_mode(doc);
14821643
14831644 let selection = doc.selection(view.id).transform(|range| {
@@ -1497,73 +1658,79 @@ enum Open {
14971658
14981659fn open(cx: &mut Context, open: Open) {
14991660 let count = cx.count();
1500− let (view, doc) = cx.current();
1661+ let (view, doc) = current!(cx.editor);
15011662 enter_insert_mode(doc);
15021663
15031664 let text = doc.text().slice(..);
1665+ let contents = doc.text();
15041666 let selection = doc.selection(view.id);
15051667
15061668 let mut ranges = SmallVec::with_capacity(selection.len());
1669+ let mut offs = 0;
15071670
1508− let changes: Vec<Change> = selection
1509− .iter()
1510− .map(|range| {
1511− let line = text.char_to_line(range.head);
1512−
1513− let line = match open {
1514− // adjust position to the end of the line (next line - 1)
1515− Open::Below => line + 1,
1516− // adjust position to the end of the previous line (current line - 1)
1517− Open::Above => line,
1518− };
1519−
1520− let index = doc.text().line_to_char(line).saturating_sub(1);
1671+ let line = match open {
1672+ // adjust position to the end of the line (next line - 1)
1673+ Open::Below => line + 1,
1674+ // adjust position to the end of the previous line (current line - 1)
1675+ Open::Above => line,
1676+ };
15211677
1522− // TODO: share logic with insert_newline for indentation
1523− let indent_level = indent::suggested_indent_for_pos(
1524− doc.language_config(),
1525− doc.syntax(),
1526− text,
1527− index,
1528− true,
1529− );
1530− let indent = doc.indent_unit().repeat(indent_level);
1531− let mut text = String::with_capacity(1 + indent.len());
1532− text.push_str(doc.line_ending().as_str());
1533− text.push_str(&indent);
1534− let text = text.repeat(count);
1678+ let mut transaction = Transaction::change_by_selection(contents, selection, |range| {
1679+ let line = text.char_to_line(range.head);
15351680
1536− // calculate new selection range
1537− let pos = index + text.chars().count();
1538− ranges.push(Range::new(pos, pos));
1681+ // insert newlines after this index for both Above and Below variants
1682+ let linend_index = doc.text().line_to_char(line).saturating_sub(1);
15391683
1540− (index, index, Some(text.into()))
1541− })
1542− .collect();
1684+ // TODO: share logic with insert_newline for indentation
1685+ let indent_level = indent::suggested_indent_for_pos(
1686+ doc.language_config(),
1687+ doc.syntax(),
1688+ text,
1689+ linend_index,
1690+ true,
1691+ );
1692+ let indent = doc.indent_unit().repeat(indent_level);
1693+ let indent_len = indent.len();
1694+ let mut text = String::with_capacity(1 + indent_len);
1695+ text.push('\n');
1696+ text.push_str(&indent);
1697+ let text = text.repeat(count);
1698+
1699+ // calculate new selection ranges
1700+ let pos = if line == 0 {
1701+ 0 // Required since text will have a min len of 1 (\n)
1702+ } else {
1703+ offs + linend_index + 1
1704+ };
1705+ for i in 0..count {
1706+ // pos -> beginning of reference line,
1707+ // + (i * (1+indent_len)) -> beginning of i'th line from pos
1708+ // + indent_len -> -> indent for i'th line
1709+ ranges.push(Range::point(pos + (i * (1 + indent_len)) + indent_len));
1710+ }
15431711
1544− // TODO: count actually inserts "n" new lines and starts editing on all of them.
1545− // TODO: append "count" newlines and modify cursors to those lines
1712+ offs += text.chars().count();
15461713
1547− let selection = Selection::new(ranges, 0);
1714+ (linend_index, linend_index, Some(text.into()))
1715+ });
15481716
1549− let transaction =
1550− Transaction::change(doc.text(), changes.into_iter()).with_selection(selection);
1717+ transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index()));
15511718
15521719 doc.apply(&transaction, view.id);
15531720}
15541721
15551722// o inserts a new line after each line with a selection
1556−pub fn open_below(cx: &mut Context) {
1723+fn open_below(cx: &mut Context) {
15571724 open(cx, Open::Below)
15581725}
15591726
15601727// O inserts a new line before each line with a selection
1561−pub fn open_above(cx: &mut Context) {
1728+fn open_above(cx: &mut Context) {
15621729 open(cx, Open::Above)
15631730}
15641731
1565−pub fn normal_mode(cx: &mut Context) {
1566− let (view, doc) = cx.current();
1732+fn normal_mode(cx: &mut Context) {
1733+ let (view, doc) = current!(cx.editor);
15671734
15681735 doc.mode = Mode::Normal;
15691736
@@ -1586,13 +1753,13 @@ pub fn normal_mode(cx: &mut Context) {
15861753
15871754// Store a jump on the jumplist.
15881755fn push_jump(editor: &mut Editor) {
1589− let (view, doc) = editor.current();
1756+ let (view, doc) = current!(editor);
15901757 let jump = (doc.id(), doc.selection(view.id).clone());
15911758 view.jumps.push(jump);
15921759}
15931760
15941761fn switch_to_last_accessed_file(cx: &mut Context) {
1595− let alternate_file = cx.view().last_accessed_doc;
1762+ let alternate_file = view!(cx.editor).last_accessed_doc;
15961763 if let Some(alt) = alternate_file {
15971764 cx.editor.switch(alt, Action::Replace);
15981765 } else {
@@ -1600,11 +1767,11 @@ fn switch_to_last_accessed_file(cx: &mut Context) {
16001767 }
16011768}
16021769
1603−pub fn goto_mode(cx: &mut Context) {
1770+fn goto_mode(cx: &mut Context) {
16041771 if let Some(count) = cx.count {
16051772 push_jump(cx.editor);
16061773
1607− let (view, doc) = cx.current();
1774+ let (view, doc) = current!(cx.editor);
16081775 let line_idx = std::cmp::min(count.get() - 1, doc.text().len_lines().saturating_sub(2));
16091776 let pos = doc.text().line_to_char(line_idx);
16101777 doc.set_selection(view.id, Selection::point(pos));
@@ -1618,7 +1785,8 @@ pub fn goto_mode(cx: &mut Context) {
16181785 } = event
16191786 {
16201787 // TODO: temporarily show GOTO in the mode list
1621− match (cx.doc().mode, ch) {
1788+ let doc = doc_mut!(cx.editor);
1789+ match (doc.mode, ch) {
16221790 (_, 'g') => move_file_start(cx),
16231791 (_, 'e') => move_file_end(cx),
16241792 (_, 'a') => switch_to_last_accessed_file(cx),
@@ -1634,7 +1802,7 @@ pub fn goto_mode(cx: &mut Context) {
16341802 (Mode::Select, 's') => extend_first_nonwhitespace(cx),
16351803
16361804 (_, 't') | (_, 'm') | (_, 'b') => {
1637− let (view, doc) = cx.current();
1805+ let (view, doc) = current!(cx.editor);
16381806
16391807 let pos = doc.selection(view.id).cursor();
16401808 let line = doc.text().char_to_line(pos);
@@ -1661,12 +1829,12 @@ pub fn goto_mode(cx: &mut Context) {
16611829 })
16621830}
16631831
1664−pub fn select_mode(cx: &mut Context) {
1665− cx.doc().mode = Mode::Select;
1832+fn select_mode(cx: &mut Context) {
1833+ doc_mut!(cx.editor).mode = Mode::Select;
16661834}
16671835
1668−pub fn exit_select_mode(cx: &mut Context) {
1669− cx.doc().mode = Mode::Normal;
1836+fn exit_select_mode(cx: &mut Context) {
1837+ doc_mut!(cx.editor).mode = Mode::Normal;
16701838}
16711839
16721840fn goto_impl(
@@ -1688,7 +1856,7 @@ fn goto_impl(
16881856 let id = editor
16891857 .open(PathBuf::from(location.uri.path()), action)
16901858 .expect("editor.open failed");
1691− let (view, doc) = editor.current();
1859+ let (view, doc) = current!(editor);
16921860 let definition_pos = location.range.start;
16931861 // TODO: convert inside server
16941862 let new_pos =
@@ -1725,8 +1893,8 @@ fn goto_impl(
17251893 }
17261894}
17271895
1728−pub fn goto_definition(cx: &mut Context) {
1729− let (view, doc) = cx.current();
1896+fn goto_definition(cx: &mut Context) {
1897+ let (view, doc) = current!(cx.editor);
17301898 let language_server = match doc.language_server() {
17311899 Some(language_server) => language_server,
17321900 None => return,
@@ -1737,7 +1905,7 @@ pub fn goto_definition(cx: &mut Context) {
17371905 let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
17381906
17391907 // TODO: handle fails
1740− let future = language_server.goto_definition(doc.identifier(), pos);
1908+ let future = language_server.goto_definition(doc.identifier(), pos, None);
17411909
17421910 cx.callback(
17431911 future,
@@ -1762,8 +1930,8 @@ pub fn goto_definition(cx: &mut Context) {
17621930 );
17631931}
17641932
1765−pub fn goto_type_definition(cx: &mut Context) {
1766− let (view, doc) = cx.current();
1933+fn goto_type_definition(cx: &mut Context) {
1934+ let (view, doc) = current!(cx.editor);
17671935 let language_server = match doc.language_server() {
17681936 Some(language_server) => language_server,
17691937 None => return,
@@ -1774,7 +1942,7 @@ pub fn goto_type_definition(cx: &mut Context) {
17741942 let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
17751943
17761944 // TODO: handle fails
1777− let future = language_server.goto_type_definition(doc.identifier(), pos);
1945+ let future = language_server.goto_type_definition(doc.identifier(), pos, None);
17781946
17791947 cx.callback(
17801948 future,
@@ -1799,8 +1967,8 @@ pub fn goto_type_definition(cx: &mut Context) {
17991967 );
18001968}
18011969
1802−pub fn goto_implementation(cx: &mut Context) {
1803− let (view, doc) = cx.current();
1970+fn goto_implementation(cx: &mut Context) {
1971+ let (view, doc) = current!(cx.editor);
18041972 let language_server = match doc.language_server() {
18051973 Some(language_server) => language_server,
18061974 None => return,
@@ -1811,7 +1979,7 @@ pub fn goto_implementation(cx: &mut Context) {
18111979 let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
18121980
18131981 // TODO: handle fails
1814− let future = language_server.goto_implementation(doc.identifier(), pos);
1982+ let future = language_server.goto_implementation(doc.identifier(), pos, None);
18151983
18161984 cx.callback(
18171985 future,
@@ -1836,8 +2004,8 @@ pub fn goto_implementation(cx: &mut Context) {
18362004 );
18372005}
18382006
1839−pub fn goto_reference(cx: &mut Context) {
1840− let (view, doc) = cx.current();
2007+fn goto_reference(cx: &mut Context) {
2008+ let (view, doc) = current!(cx.editor);
18412009 let language_server = match doc.language_server() {
18422010 Some(language_server) => language_server,
18432011 None => return,
@@ -1848,7 +2016,7 @@ pub fn goto_reference(cx: &mut Context) {
18482016 let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
18492017
18502018 // TODO: handle fails
1851− let future = language_server.goto_reference(doc.identifier(), pos);
2019+ let future = language_server.goto_reference(doc.identifier(), pos, None);
18522020
18532021 cx.callback(
18542022 future,
@@ -1868,15 +2036,15 @@ pub fn goto_reference(cx: &mut Context) {
18682036fn goto_pos(editor: &mut Editor, pos: usize) {
18692037 push_jump(editor);
18702038
1871− let (view, doc) = editor.current();
2039+ let (view, doc) = current!(editor);
18722040
18732041 doc.set_selection(view.id, Selection::point(pos));
18742042 align_view(doc, view, Align::Center);
18752043}
18762044
1877−pub fn goto_first_diag(cx: &mut Context) {
2045+fn goto_first_diag(cx: &mut Context) {
18782046 let editor = &mut cx.editor;
1879− let (view, doc) = editor.current();
2047+ let (view, doc) = current!(editor);
18802048
18812049 let cursor_pos = doc.selection(view.id).cursor();
18822050 let diag = if let Some(diag) = doc.diagnostics().first() {
@@ -1888,9 +2056,9 @@ pub fn goto_first_diag(cx: &mut Context) {
18882056 goto_pos(editor, diag);
18892057}
18902058
1891−pub fn goto_last_diag(cx: &mut Context) {
2059+fn goto_last_diag(cx: &mut Context) {
18922060 let editor = &mut cx.editor;
1893− let (view, doc) = editor.current();
2061+ let (view, doc) = current!(editor);
18942062
18952063 let cursor_pos = doc.selection(view.id).cursor();
18962064 let diag = if let Some(diag) = doc.diagnostics().last() {
@@ -1902,9 +2070,9 @@ pub fn goto_last_diag(cx: &mut Context) {
19022070 goto_pos(editor, diag);
19032071}
19042072
1905−pub fn goto_next_diag(cx: &mut Context) {
2073+fn goto_next_diag(cx: &mut Context) {
19062074 let editor = &mut cx.editor;
1907− let (view, doc) = editor.current();
2075+ let (view, doc) = current!(editor);
19082076
19092077 let cursor_pos = doc.selection(view.id).cursor();
19102078 let diag = if let Some(diag) = doc
@@ -1923,9 +2091,9 @@ pub fn goto_next_diag(cx: &mut Context) {
19232091 goto_pos(editor, diag);
19242092}
19252093
1926−pub fn goto_prev_diag(cx: &mut Context) {
2094+fn goto_prev_diag(cx: &mut Context) {
19272095 let editor = &mut cx.editor;
1928− let (view, doc) = editor.current();
2096+ let (view, doc) = current!(editor);
19292097
19302098 let cursor_pos = doc.selection(view.id).cursor();
19312099 let diag = if let Some(diag) = doc
@@ -1945,8 +2113,8 @@ pub fn goto_prev_diag(cx: &mut Context) {
19452113 goto_pos(editor, diag);
19462114}
19472115
1948−pub fn signature_help(cx: &mut Context) {
1949− let (view, doc) = cx.current();
2116+fn signature_help(cx: &mut Context) {
2117+ let (view, doc) = current!(cx.editor);
19502118
19512119 let language_server = match doc.language_server() {
19522120 Some(language_server) => language_server,
@@ -1960,7 +2128,7 @@ pub fn signature_help(cx: &mut Context) {
19602128 );
19612129
19622130 // TODO: handle fails
1963− let future = language_server.text_document_signature_help(doc.identifier(), pos);
2131+ let future = language_server.text_document_signature_help(doc.identifier(), pos, None);
19642132
19652133 cx.callback(
19662134 future,
@@ -1992,7 +2160,7 @@ pub mod insert {
19922160
19932161 fn completion(cx: &mut Context, ch: char) {
19942162 // if ch matches completion char, trigger completion
1995− let doc = cx.doc();
2163+ let doc = doc_mut!(cx.editor);
19962164 let language_server = match doc.language_server() {
19972165 Some(language_server) => language_server,
19982166 None => return,
@@ -2020,7 +2188,7 @@ pub mod insert {
20202188
20212189 fn signature_help(cx: &mut Context, ch: char) {
20222190 // if ch matches signature_help char, trigger
2023− let doc = cx.doc();
2191+ let doc = doc_mut!(cx.editor);
20242192 let language_server = match doc.language_server() {
20252193 Some(language_server) => language_server,
20262194 None => return,
@@ -2075,7 +2243,7 @@ pub mod insert {
20752243 const POST_HOOKS: &[PostHook] = &[completion, signature_help];
20762244
20772245 pub fn insert_char(cx: &mut Context, c: char) {
2078− let (view, doc) = cx.current();
2246+ let (view, doc) = current!(cx.editor);
20792247
20802248 let text = doc.text();
20812249 let selection = doc.selection(view.id);
@@ -2097,7 +2265,7 @@ pub mod insert {
20972265 }
20982266
20992267 pub fn insert_tab(cx: &mut Context) {
2100− let (view, doc) = cx.current();
2268+ let (view, doc) = current!(cx.editor);
21012269 // TODO: round out to nearest indentation level (for example a line with 3 spaces should
21022270 // indent by one to reach 4 spaces).
21032271
@@ -2107,7 +2275,7 @@ pub mod insert {
21072275 }
21082276
21092277 pub fn insert_newline(cx: &mut Context) {
2110− let (view, doc) = cx.current();
2278+ let (view, doc) = current!(cx.editor);
21112279 let text = doc.text().slice(..);
21122280
21132281 let contents = doc.text();
@@ -2176,7 +2344,7 @@ pub mod insert {
21762344 // TODO: handle indent-aware delete
21772345 pub fn delete_char_backward(cx: &mut Context) {
21782346 let count = cx.count();
2179− let (view, doc) = cx.current();
2347+ let (view, doc) = current!(cx.editor);
21802348 let text = doc.text().slice(..);
21812349 let transaction =
21822350 Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
@@ -2191,7 +2359,7 @@ pub mod insert {
21912359
21922360 pub fn delete_char_forward(cx: &mut Context) {
21932361 let count = cx.count();
2194− let (view, doc) = cx.current();
2362+ let (view, doc) = current!(cx.editor);
21952363 let text = doc.text().slice(..);
21962364 let transaction =
21972365 Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
@@ -2206,7 +2374,7 @@ pub mod insert {
22062374
22072375 pub fn delete_word_backward(cx: &mut Context) {
22082376 let count = cx.count();
2209− let (view, doc) = cx.current();
2377+ let (view, doc) = current!(cx.editor);
22102378 let text = doc.text().slice(..);
22112379 let selection = doc
22122380 .selection(view.id)
@@ -2221,21 +2389,23 @@ pub mod insert {
22212389// TODO: each command could simply return a Option<transaction>, then the higher level handles
22222390// storing it?
22232391
2224−pub fn undo(cx: &mut Context) {
2225− let view_id = cx.view().id;
2226− cx.doc().undo(view_id);
2392+fn undo(cx: &mut Context) {
2393+ let (view, doc) = current!(cx.editor);
2394+ let view_id = view.id;
2395+ doc.undo(view_id);
22272396}
22282397
2229−pub fn redo(cx: &mut Context) {
2230− let view_id = cx.view().id;
2231− cx.doc().redo(view_id);
2398+fn redo(cx: &mut Context) {
2399+ let (view, doc) = current!(cx.editor);
2400+ let view_id = view.id;
2401+ doc.redo(view_id);
22322402}
22332403
22342404// Yank / Paste
22352405
2236−pub fn yank(cx: &mut Context) {
2406+fn yank(cx: &mut Context) {
22372407 // TODO: should selections be made end inclusive?
2238− let (view, doc) = cx.current();
2408+ let (view, doc) = current!(cx.editor);
22392409 let values: Vec<String> = doc
22402410 .selection(view.id)
22412411 .fragments(doc.text().slice(..))
@@ -2300,9 +2470,10 @@ fn paste_impl(
23002470 Some(transaction)
23012471}
23022472
2303−pub fn replace_with_yanked(cx: &mut Context) {
2473+fn replace_with_yanked(cx: &mut Context) {
23042474 let reg_name = cx.selected_register.name();
2305− let (view, doc, registers) = cx.current_with_registers();
2475+ let (view, doc) = current!(cx.editor);
2476+ let registers = &mut cx.editor.registers;
23062477
23072478 if let Some(values) = registers.read(reg_name) {
23082479 if let Some(yank) = values.first() {
@@ -2329,9 +2500,10 @@ pub fn replace_with_yanked(cx: &mut Context) {
23292500// replace => replace
23302501// default insert
23312502
2332−pub fn paste_after(cx: &mut Context) {
2503+fn paste_after(cx: &mut Context) {
23332504 let reg_name = cx.selected_register.name();
2334− let (view, doc, registers) = cx.current_with_registers();
2505+ let (view, doc) = current!(cx.editor);
2506+ let registers = &mut cx.editor.registers;
23352507
23362508 if let Some(transaction) = registers
23372509 .read(reg_name)
@@ -2342,9 +2514,10 @@ pub fn paste_after(cx: &mut Context) {
23422514 }
23432515}
23442516
2345−pub fn paste_before(cx: &mut Context) {
2517+fn paste_before(cx: &mut Context) {
23462518 let reg_name = cx.selected_register.name();
2347− let (view, doc, registers) = cx.current_with_registers();
2519+ let (view, doc) = current!(cx.editor);
2520+ let registers = &mut cx.editor.registers;
23482521
23492522 if let Some(transaction) = registers
23502523 .read(reg_name)
@@ -2372,9 +2545,9 @@ fn get_lines(doc: &Document, view_id: ViewId) -> Vec<usize> {
23722545 lines
23732546}
23742547
2375−pub fn indent(cx: &mut Context) {
2548+fn indent(cx: &mut Context) {
23762549 let count = cx.count();
2377− let (view, doc) = cx.current();
2550+ let (view, doc) = current!(cx.editor);
23782551 let lines = get_lines(doc, view.id);
23792552
23802553 // Indent by one level
@@ -2391,9 +2564,9 @@ pub fn indent(cx: &mut Context) {
23912564 doc.append_changes_to_history(view.id);
23922565}
23932566
2394−pub fn unindent(cx: &mut Context) {
2567+fn unindent(cx: &mut Context) {
23952568 let count = cx.count();
2396− let (view, doc) = cx.current();
2569+ let (view, doc) = current!(cx.editor);
23972570 let lines = get_lines(doc, view.id);
23982571 let mut changes = Vec::with_capacity(lines.len());
23992572 let tab_width = doc.tab_width();
@@ -2431,8 +2604,8 @@ pub fn unindent(cx: &mut Context) {
24312604 doc.append_changes_to_history(view.id);
24322605}
24332606
2434−pub fn format_selections(cx: &mut Context) {
2435− let (view, doc) = cx.current();
2607+fn format_selections(cx: &mut Context) {
2608+ let (view, doc) = current!(cx.editor);
24362609
24372610 // via lsp if available
24382611 // else via tree-sitter indentation calculations
@@ -2477,9 +2650,9 @@ pub fn format_selections(cx: &mut Context) {
24772650 doc.append_changes_to_history(view.id);
24782651}
24792652
2480−pub fn join_selections(cx: &mut Context) {
2653+fn join_selections(cx: &mut Context) {
24812654 use movement::skip_while;
2482− let (view, doc) = cx.current();
2655+ let (view, doc) = current!(cx.editor);
24832656 let text = doc.text();
24842657 let slice = doc.text().slice(..);
24852658
@@ -2521,7 +2694,7 @@ pub fn join_selections(cx: &mut Context) {
25212694 doc.append_changes_to_history(view.id);
25222695}
25232696
2524−pub fn keep_selections(cx: &mut Context) {
2697+fn keep_selections(cx: &mut Context) {
25252698 // keep selections matching regex
25262699 let prompt = ui::regex_prompt(cx, "keep:".to_string(), move |view, doc, _, regex| {
25272700 let text = doc.text().slice(..);
@@ -2534,8 +2707,8 @@ pub fn keep_selections(cx: &mut Context) {
25342707 cx.push_layer(Box::new(prompt));
25352708}
25362709
2537−pub fn keep_primary_selection(cx: &mut Context) {
2538− let (view, doc) = cx.current();
2710+fn keep_primary_selection(cx: &mut Context) {
2711+ let (view, doc) = current!(cx.editor);
25392712
25402713 let range = doc.selection(view.id).primary();
25412714 let selection = Selection::single(range.anchor, range.head);
@@ -2544,14 +2717,14 @@ pub fn keep_primary_selection(cx: &mut Context) {
25442717
25452718//
25462719
2547−pub fn save(cx: &mut Context) {
2720+fn save(cx: &mut Context) {
25482721 // Spawns an async task to actually do the saving. This way we prevent blocking.
25492722
25502723 // TODO: handle save errors somehow?
2551− tokio::spawn(cx.doc().save());
2724+ tokio::spawn(doc_mut!(cx.editor).save());
25522725}
25532726
2554−pub fn completion(cx: &mut Context) {
2727+fn completion(cx: &mut Context) {
25552728 // trigger on trigger char, or if user calls it
25562729 // (or on word char typing??)
25572730 // after it's triggered, if response marked is_incomplete, update on every subsequent keypress
@@ -2588,7 +2761,7 @@ pub fn completion(cx: &mut Context) {
25882761 // The prefix still has to satisfy `company-minimum-prefix-length' before that
25892762 // happens. The value of nil means no idle completion."
25902763
2591− let (view, doc) = cx.current();
2764+ let (view, doc) = current!(cx.editor);
25922765
25932766 let language_server = match doc.language_server() {
25942767 Some(language_server) => language_server,
@@ -2600,7 +2773,7 @@ pub fn completion(cx: &mut Context) {
26002773 let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
26012774
26022775 // TODO: handle fails
2603− let future = language_server.completion(doc.identifier(), pos);
2776+ let future = language_server.completion(doc.identifier(), pos, None);
26042777
26052778 let trigger_offset = doc.selection(view.id).cursor();
26062779
@@ -2641,8 +2814,8 @@ pub fn completion(cx: &mut Context) {
26412814 //}
26422815}
26432816
2644−pub fn hover(cx: &mut Context) {
2645− let (view, doc) = cx.current();
2817+fn hover(cx: &mut Context) {
2818+ let (view, doc) = current!(cx.editor);
26462819
26472820 let language_server = match doc.language_server() {
26482821 Some(language_server) => language_server,
@@ -2658,7 +2831,7 @@ pub fn hover(cx: &mut Context) {
26582831 );
26592832
26602833 // TODO: handle fails
2661− let future = language_server.text_document_hover(doc.identifier(), pos);
2834+ let future = language_server.text_document_hover(doc.identifier(), pos, None);
26622835
26632836 cx.callback(
26642837 future,
@@ -2691,8 +2864,8 @@ pub fn hover(cx: &mut Context) {
26912864}
26922865
26932866// comments
2694−pub fn toggle_comments(cx: &mut Context) {
2695− let (view, doc) = cx.current();
2867+fn toggle_comments(cx: &mut Context) {
2868+ let (view, doc) = current!(cx.editor);
26962869 let transaction = comment::toggle_line_comments(doc.text(), doc.selection(view.id));
26972870
26982871 doc.apply(&transaction, view.id);
@@ -2701,8 +2874,8 @@ pub fn toggle_comments(cx: &mut Context) {
27012874
27022875// tree sitter node selection
27032876
2704−pub fn expand_selection(cx: &mut Context) {
2705− let (view, doc) = cx.current();
2877+fn expand_selection(cx: &mut Context) {
2878+ let (view, doc) = current!(cx.editor);
27062879
27072880 if let Some(syntax) = doc.syntax() {
27082881 let text = doc.text().slice(..);
@@ -2711,8 +2884,8 @@ pub fn expand_selection(cx: &mut Context) {
27112884 }
27122885}
27132886
2714−pub fn match_brackets(cx: &mut Context) {
2715− let (view, doc) = cx.current();
2887+fn match_brackets(cx: &mut Context) {
2888+ let (view, doc) = current!(cx.editor);
27162889
27172890 if let Some(syntax) = doc.syntax() {
27182891 let pos = doc.selection(view.id).cursor();
@@ -2725,23 +2898,23 @@ pub fn match_brackets(cx: &mut Context) {
27252898
27262899//
27272900
2728−pub fn jump_forward(cx: &mut Context) {
2901+fn jump_forward(cx: &mut Context) {
27292902 let count = cx.count();
2730− let (view, doc) = cx.current();
2903+ let (view, doc) = current!(cx.editor);
27312904
27322905 if let Some((id, selection)) = view.jumps.forward(count) {
27332906 view.doc = *id;
27342907 let selection = selection.clone();
2735− let (view, doc) = cx.current(); // refetch doc
2908+ let (view, doc) = current!(cx.editor); // refetch doc
27362909 doc.set_selection(view.id, selection);
27372910
27382911 align_view(doc, view, Align::Center);
27392912 };
27402913}
27412914
2742−pub fn jump_backward(cx: &mut Context) {
2915+fn jump_backward(cx: &mut Context) {
27432916 let count = cx.count();
2744− let (view, doc) = cx.current();
2917+ let (view, doc) = current!(cx.editor);
27452918
27462919 if let Some((id, selection)) = view.jumps.backward(view.id, doc, count) {
27472920 // manually set the alternate_file as we cannot use the Editor::switch function here.
@@ -2750,14 +2923,14 @@ pub fn jump_backward(cx: &mut Context) {
27502923 }
27512924 view.doc = *id;
27522925 let selection = selection.clone();
2753− let (view, doc) = cx.current(); // refetch doc
2926+ let (view, doc) = current!(cx.editor); // refetch doc
27542927 doc.set_selection(view.id, selection);
27552928
27562929 align_view(doc, view, Align::Center);
27572930 };
27582931}
27592932
2760−pub fn window_mode(cx: &mut Context) {
2933+fn window_mode(cx: &mut Context) {
27612934 cx.on_next_key(move |cx, event| {
27622935 if let KeyEvent {
27632936 code: KeyCode::Char(ch),
@@ -2775,15 +2948,17 @@ pub fn window_mode(cx: &mut Context) {
27752948 })
27762949}
27772950
2778−pub fn rotate_view(cx: &mut Context) {
2951+fn rotate_view(cx: &mut Context) {
27792952 cx.editor.focus_next()
27802953}
27812954
27822955// split helper, clear it later
27832956use helix_view::editor::Action;
2957+
2958+use self::cmd::TypableCommand;
27842959fn split(cx: &mut Context, action: Action) {
27852960 use helix_view::editor::Action;
2786− let (view, doc) = cx.current();
2961+ let (view, doc) = current!(cx.editor);
27872962 let id = doc.id();
27882963 let selection = doc.selection(view.id).clone();
27892964 let first_line = view.first_line;
@@ -2791,26 +2966,26 @@ fn split(cx: &mut Context, action: Action) {
27912966 cx.editor.switch(id, action);
27922967
27932968 // match the selection in the previous view
2794− let (view, doc) = cx.current();
2969+ let (view, doc) = current!(cx.editor);
27952970 view.first_line = first_line;
27962971 doc.set_selection(view.id, selection);
27972972}
27982973
2799−pub fn hsplit(cx: &mut Context) {
2974+fn hsplit(cx: &mut Context) {
28002975 split(cx, Action::HorizontalSplit);
28012976}
28022977
2803−pub fn vsplit(cx: &mut Context) {
2978+fn vsplit(cx: &mut Context) {
28042979 split(cx, Action::VerticalSplit);
28052980}
28062981
2807−pub fn wclose(cx: &mut Context) {
2808− let view_id = cx.view().id;
2982+fn wclose(cx: &mut Context) {
2983+ let view_id = view!(cx.editor).id;
28092984 // close current split
28102985 cx.editor.close(view_id, /* close_buffer */ false);
28112986}
28122987
2813−pub fn select_register(cx: &mut Context) {
2988+fn select_register(cx: &mut Context) {
28142989 cx.on_next_key(move |cx, event| {
28152990 if let KeyEvent {
28162991 code: KeyCode::Char(ch),
@@ -2822,7 +2997,7 @@ pub fn select_register(cx: &mut Context) {
28222997 })
28232998}
28242999
2825−pub fn space_mode(cx: &mut Context) {
3000+fn space_mode(cx: &mut Context) {
28263001 cx.on_next_key(move |cx, event| {
28273002 if let KeyEvent {
28283003 code: KeyCode::Char(ch),
@@ -2844,7 +3019,7 @@ pub fn space_mode(cx: &mut Context) {
28443019 })
28453020}
28463021
2847−pub fn view_mode(cx: &mut Context) {
3022+fn view_mode(cx: &mut Context) {
28483023 cx.on_next_key(move |cx, event| {
28493024 if let KeyEvent {
28503025 code: KeyCode::Char(ch),
@@ -2860,7 +3035,7 @@ pub fn view_mode(cx: &mut Context) {
28603035 | 't'
28613036 // bottom
28623037 | 'b' => {
2863− let (view, doc) = cx.current();
3038+ let (view, doc) = current!(cx.editor);
28643039
28653040 align_view(doc, view, match ch {
28663041 'z' | 'c' => Align::Center,
@@ -2870,7 +3045,7 @@ pub fn view_mode(cx: &mut Context) {
28703045 });
28713046 }
28723047 'm' => {
2873− let (view, doc) = cx.current();
3048+ let (view, doc) = current!(cx.editor);
28743049 let pos = doc.selection(view.id).cursor();
28753050 let pos = coords_at_pos(doc.text().slice(..), pos);
28763051
@@ -2887,7 +3062,7 @@ pub fn view_mode(cx: &mut Context) {
28873062 })
28883063}
28893064
2890−pub fn left_bracket_mode(cx: &mut Context) {
3065+fn left_bracket_mode(cx: &mut Context) {
28913066 cx.on_next_key(move |cx, event| {
28923067 if let KeyEvent {
28933068 code: KeyCode::Char(ch),
@@ -2903,7 +3078,7 @@ pub fn left_bracket_mode(cx: &mut Context) {
29033078 })
29043079}
29053080
2906−pub fn right_bracket_mode(cx: &mut Context) {
3081+fn right_bracket_mode(cx: &mut Context) {
29073082 cx.on_next_key(move |cx, event| {
29083083 if let KeyEvent {
29093084 code: KeyCode::Char(ch),