on master help sign in
Introduce a command context that carries the executor and other fields.
commit8f0bcfe286d97dfff67bd924e11ca2b6ae1a63dc authorBlaž Hrastnik <blaz@mxxn.io> dateFri 30 Oct 2020, 14:09 (6 years ago) parentae8a9e5
2 files changed+264−219
helix-term/src/application.rs+25−4 helix-view/src/commands.rs+239−215
helix-term/src/application.rs+25−4
@@ -476,13 +476,24 @@ impl<'a> Application<'a> {
476476 match view.doc.mode() {
477477 Mode::Insert => {
478478 if let Some(command) = self.keymap[&Mode::Insert].get(&keys) {
479− command(view, 1);
479+ let mut cx = helix_view::commands::Context {
480+ view,
481+ executor: self.executor,
482+ count: 1,
483+ };
484+
485+ command(&mut cx);
480486 } else if let KeyEvent {
481487 code: KeyCode::Char(c),
482488 ..
483489 } = event
484490 {
485− commands::insert::insert_char(view, c);
491+ let mut cx = helix_view::commands::Context {
492+ view,
493+ executor: self.executor,
494+ count: 1,
495+ };
496+ commands::insert::insert_char(&mut cx, c);
486497 }
487498 view.ensure_cursor_in_view();
488499 }
@@ -544,7 +555,12 @@ impl<'a> Application<'a> {
544555
545556 // HAXX: special casing for command mode
546557 } else if let Some(command) = self.keymap[&Mode::Normal].get(&keys) {
547− command(view, 1);
558+ let mut cx = helix_view::commands::Context {
559+ view,
560+ executor: self.executor,
561+ count: 1,
562+ };
563+ command(&mut cx);
548564
549565 // TODO: simplistic ensure cursor in view for now
550566 view.ensure_cursor_in_view();
@@ -552,7 +568,12 @@ impl<'a> Application<'a> {
552568 }
553569 mode => {
554570 if let Some(command) = self.keymap[&mode].get(&keys) {
555− command(view, 1);
571+ let mut cx = helix_view::commands::Context {
572+ view,
573+ executor: self.executor,
574+ count: 1,
575+ };
576+ command(&mut cx);
556577
557578 // TODO: simplistic ensure cursor in view for now
558579 view.ensure_cursor_in_view();
helix-view/src/commands.rs+239−215
@@ -14,44 +14,54 @@ use crate::{
1414 view::{View, PADDING},
1515};
1616
17+pub struct Context<'a, 'b> {
18+ pub count: usize,
19+ pub view: &'a mut View,
20+ pub executor: &'a smol::Executor<'b>,
21+}
22+
1723/// A command is a function that takes the current state and a count, and does a side-effect on the
1824/// state (usually by creating and applying a transaction).
19−pub type Command = fn(view: &mut View, count: usize);
25+pub type Command = fn(cx: &mut Context);
2026
21−pub fn move_char_left(view: &mut View, count: usize) {
27+pub fn move_char_left(cx: &mut Context) {
2228 let selection =
23− view.doc
29+ cx.view
30+ .doc
2431 .state
25− .move_selection(Direction::Backward, Granularity::Character, count);
26− view.doc.set_selection(selection);
32+ .move_selection(Direction::Backward, Granularity::Character, cx.count);
33+ cx.view.doc.set_selection(selection);
2734}
2835
29−pub fn move_char_right(view: &mut View, count: usize) {
36+pub fn move_char_right(cx: &mut Context) {
3037 let selection =
31− view.doc
38+ cx.view
39+ .doc
3240 .state
33− .move_selection(Direction::Forward, Granularity::Character, count);
34− view.doc.set_selection(selection);
41+ .move_selection(Direction::Forward, Granularity::Character, cx.count);
42+ cx.view.doc.set_selection(selection);
3543}
3644
37−pub fn move_line_up(view: &mut View, count: usize) {
38− let selection = view
39− .doc
40− .state
41− .move_selection(Direction::Backward, Granularity::Line, count);
42− view.doc.set_selection(selection);
45+pub fn move_line_up(cx: &mut Context) {
46+ let selection =
47+ cx.view
48+ .doc
49+ .state
50+ .move_selection(Direction::Backward, Granularity::Line, cx.count);
51+ cx.view.doc.set_selection(selection);
4352}
4453
45−pub fn move_line_down(view: &mut View, count: usize) {
46− let selection = view
47− .doc
48− .state
49− .move_selection(Direction::Forward, Granularity::Line, count);
50− view.doc.set_selection(selection);
54+pub fn move_line_down(cx: &mut Context) {
55+ let selection =
56+ cx.view
57+ .doc
58+ .state
59+ .move_selection(Direction::Forward, Granularity::Line, cx.count);
60+ cx.view.doc.set_selection(selection);
5161}
5262
53−pub fn move_line_end(view: &mut View, _count: usize) {
54− let lines = selection_lines(&view.doc.state);
63+pub fn move_line_end(cx: &mut Context) {
64+ let lines = selection_lines(&cx.view.doc.state);
5565
5666 let positions = lines
5767 .into_iter()
@@ -60,78 +70,78 @@ pub fn move_line_end(view: &mut View, _count: usize) {
6070
6171 // Line end is pos at the start of next line - 1
6272 // subtract another 1 because the line ends with \n
63− view.doc.text().line_to_char(index + 1).saturating_sub(2)
73+ cx.view.doc.text().line_to_char(index + 1).saturating_sub(2)
6474 })
6575 .map(|pos| Range::new(pos, pos));
6676
6777 let selection = Selection::new(positions.collect(), 0);
6878
69− view.doc.set_selection(selection);
79+ cx.view.doc.set_selection(selection);
7080}
7181
72−pub fn move_line_start(view: &mut View, _count: usize) {
73− let lines = selection_lines(&view.doc.state);
82+pub fn move_line_start(cx: &mut Context) {
83+ let lines = selection_lines(&cx.view.doc.state);
7484
7585 let positions = lines
7686 .into_iter()
7787 .map(|index| {
7888 // adjust all positions to the start of the line.
79− view.doc.text().line_to_char(index)
89+ cx.view.doc.text().line_to_char(index)
8090 })
8191 .map(|pos| Range::new(pos, pos));
8292
8393 let selection = Selection::new(positions.collect(), 0);
8494
85− view.doc.set_selection(selection);
95+ cx.view.doc.set_selection(selection);
8696}
8797
88−pub fn move_next_word_start(view: &mut View, count: usize) {
89− let pos = view.doc.state.move_pos(
90− view.doc.selection().cursor(),
98+pub fn move_next_word_start(cx: &mut Context) {
99+ let pos = cx.view.doc.state.move_pos(
100+ cx.view.doc.selection().cursor(),
91101 Direction::Forward,
92102 Granularity::Word,
93− count,
103+ cx.count,
94104 );
95105
96− view.doc.set_selection(Selection::point(pos));
106+ cx.view.doc.set_selection(Selection::point(pos));
97107}
98108
99−pub fn move_prev_word_start(view: &mut View, count: usize) {
100− let pos = view.doc.state.move_pos(
101− view.doc.selection().cursor(),
109+pub fn move_prev_word_start(cx: &mut Context) {
110+ let pos = cx.view.doc.state.move_pos(
111+ cx.view.doc.selection().cursor(),
102112 Direction::Backward,
103113 Granularity::Word,
104− count,
114+ cx.count,
105115 );
106116
107− view.doc.set_selection(Selection::point(pos));
117+ cx.view.doc.set_selection(Selection::point(pos));
108118}
109119
110−pub fn move_next_word_end(view: &mut View, count: usize) {
120+pub fn move_next_word_end(cx: &mut Context) {
111121 let pos = State::move_next_word_end(
112− &view.doc.text().slice(..),
113− view.doc.selection().cursor(),
114− count,
122+ &cx.view.doc.text().slice(..),
123+ cx.view.doc.selection().cursor(),
124+ cx.count,
115125 );
116126
117− view.doc.set_selection(Selection::point(pos));
127+ cx.view.doc.set_selection(Selection::point(pos));
118128}
119129
120−pub fn move_file_start(view: &mut View, _count: usize) {
121− view.doc.set_selection(Selection::point(0));
130+pub fn move_file_start(cx: &mut Context) {
131+ cx.view.doc.set_selection(Selection::point(0));
122132
123− view.doc.mode = Mode::Normal;
133+ cx.view.doc.mode = Mode::Normal;
124134}
125135
126−pub fn move_file_end(view: &mut View, _count: usize) {
127− let text = &view.doc.text();
136+pub fn move_file_end(cx: &mut Context) {
137+ let text = &cx.view.doc.text();
128138 let last_line = text.line_to_char(text.len_lines().saturating_sub(2));
129− view.doc.set_selection(Selection::point(last_line));
139+ cx.view.doc.set_selection(Selection::point(last_line));
130140
131− view.doc.mode = Mode::Normal;
141+ cx.view.doc.mode = Mode::Normal;
132142}
133143
134−pub fn check_cursor_in_view(view: &mut View) -> bool {
144+pub fn check_cursor_in_view(view: &View) -> bool {
135145 let cursor = view.doc.selection().cursor();
136146 let line = view.doc.text().char_to_line(cursor);
137147 let document_end = view.first_line + view.size.1.saturating_sub(1) as usize;
@@ -142,172 +152,182 @@ pub fn check_cursor_in_view(view: &mut View) -> bool {
142152 true
143153}
144154
145−pub fn page_up(view: &mut View, _count: usize) {
146− if view.first_line < PADDING {
155+pub fn page_up(cx: &mut Context) {
156+ if cx.view.first_line < PADDING {
147157 return;
148158 }
149159
150− view.first_line = view.first_line.saturating_sub(view.size.1 as usize);
160+ cx.view.first_line = cx.view.first_line.saturating_sub(cx.view.size.1 as usize);
151161
152− if !check_cursor_in_view(view) {
153− let text = view.doc.text();
154− let pos = text.line_to_char(view.last_line().saturating_sub(PADDING));
155− view.doc.set_selection(Selection::point(pos));
162+ if !check_cursor_in_view(cx.view) {
163+ let text = cx.view.doc.text();
164+ let pos = text.line_to_char(cx.view.last_line().saturating_sub(PADDING));
165+ cx.view.doc.set_selection(Selection::point(pos));
156166 }
157167}
158168
159−pub fn page_down(view: &mut View, _count: usize) {
160− view.first_line += view.size.1 as usize + PADDING;
169+pub fn page_down(cx: &mut Context) {
170+ cx.view.first_line += cx.view.size.1 as usize + PADDING;
161171
162− if view.first_line < view.doc.text().len_lines() {
163− let text = view.doc.text();
164− let pos = text.line_to_char(view.first_line as usize);
165− view.doc.set_selection(Selection::point(pos));
172+ if cx.view.first_line < cx.view.doc.text().len_lines() {
173+ let text = cx.view.doc.text();
174+ let pos = text.line_to_char(cx.view.first_line as usize);
175+ cx.view.doc.set_selection(Selection::point(pos));
166176 }
167177}
168178
169−pub fn half_page_up(view: &mut View, _count: usize) {
170− if view.first_line < PADDING {
179+pub fn half_page_up(cx: &mut Context) {
180+ if cx.view.first_line < PADDING {
171181 return;
172182 }
173183
174− view.first_line = view.first_line.saturating_sub(view.size.1 as usize / 2);
184+ cx.view.first_line = cx
185+ .view
186+ .first_line
187+ .saturating_sub(cx.view.size.1 as usize / 2);
175188
176− if !check_cursor_in_view(view) {
177− let text = &view.doc.text();
178− let pos = text.line_to_char(view.last_line() - PADDING);
179− view.doc.set_selection(Selection::point(pos));
189+ if !check_cursor_in_view(cx.view) {
190+ let text = &cx.view.doc.text();
191+ let pos = text.line_to_char(cx.view.last_line() - PADDING);
192+ cx.view.doc.set_selection(Selection::point(pos));
180193 }
181194}
182195
183−pub fn half_page_down(view: &mut View, _count: usize) {
184− let lines = view.doc.text().len_lines();
185− if view.first_line < lines.saturating_sub(view.size.1 as usize) {
186− view.first_line += view.size.1 as usize / 2;
196+pub fn half_page_down(cx: &mut Context) {
197+ let lines = cx.view.doc.text().len_lines();
198+ if cx.view.first_line < lines.saturating_sub(cx.view.size.1 as usize) {
199+ cx.view.first_line += cx.view.size.1 as usize / 2;
187200 }
188− if !check_cursor_in_view(view) {
189− let text = view.doc.text();
190− let pos = text.line_to_char(view.first_line as usize);
191− view.doc.set_selection(Selection::point(pos));
201+ if !check_cursor_in_view(cx.view) {
202+ let text = cx.view.doc.text();
203+ let pos = text.line_to_char(cx.view.first_line as usize);
204+ cx.view.doc.set_selection(Selection::point(pos));
192205 }
193206}
194207// avoid select by default by having a visual mode switch that makes movements into selects
195208
196−pub fn extend_char_left(view: &mut View, count: usize) {
209+pub fn extend_char_left(cx: &mut Context) {
197210 let selection =
198− view.doc
211+ cx.view
212+ .doc
199213 .state
200− .extend_selection(Direction::Backward, Granularity::Character, count);
201− view.doc.set_selection(selection);
214+ .extend_selection(Direction::Backward, Granularity::Character, cx.count);
215+ cx.view.doc.set_selection(selection);
202216}
203217
204−pub fn extend_char_right(view: &mut View, count: usize) {
218+pub fn extend_char_right(cx: &mut Context) {
205219 let selection =
206− view.doc
220+ cx.view
221+ .doc
207222 .state
208− .extend_selection(Direction::Forward, Granularity::Character, count);
209− view.doc.set_selection(selection);
223+ .extend_selection(Direction::Forward, Granularity::Character, cx.count);
224+ cx.view.doc.set_selection(selection);
210225}
211226
212−pub fn extend_line_up(view: &mut View, count: usize) {
213− let selection = view
214− .doc
215− .state
216− .extend_selection(Direction::Backward, Granularity::Line, count);
217− view.doc.set_selection(selection);
227+pub fn extend_line_up(cx: &mut Context) {
228+ let selection =
229+ cx.view
230+ .doc
231+ .state
232+ .extend_selection(Direction::Backward, Granularity::Line, cx.count);
233+ cx.view.doc.set_selection(selection);
218234}
219235
220−pub fn extend_line_down(view: &mut View, count: usize) {
221− let selection = view
222− .doc
223− .state
224− .extend_selection(Direction::Forward, Granularity::Line, count);
225− view.doc.set_selection(selection);
236+pub fn extend_line_down(cx: &mut Context) {
237+ let selection =
238+ cx.view
239+ .doc
240+ .state
241+ .extend_selection(Direction::Forward, Granularity::Line, cx.count);
242+ cx.view.doc.set_selection(selection);
226243}
227244
228−pub fn split_selection_on_newline(view: &mut View, _count: usize) {
229− let text = &view.doc.text().slice(..);
245+pub fn split_selection_on_newline(cx: &mut Context) {
246+ let text = &cx.view.doc.text().slice(..);
230247 // only compile the regex once
231248 #[allow(clippy::trivial_regex)]
232249 static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\n").unwrap());
233− let selection = selection::split_on_matches(text, view.doc.selection(), &REGEX);
234− view.doc.set_selection(selection);
250+ let selection = selection::split_on_matches(text, cx.view.doc.selection(), &REGEX);
251+ cx.view.doc.set_selection(selection);
235252}
236253
237−pub fn select_line(view: &mut View, _count: usize) {
254+pub fn select_line(cx: &mut Context) {
238255 // TODO: count
239− let pos = view.doc.selection().primary();
240− let text = view.doc.text();
256+ let pos = cx.view.doc.selection().primary();
257+ let text = cx.view.doc.text();
241258 let line = text.char_to_line(pos.head);
242259 let start = text.line_to_char(line);
243260 let end = text.line_to_char(line + 1).saturating_sub(1);
244261
245− view.doc.set_selection(Selection::single(start, end));
262+ cx.view.doc.set_selection(Selection::single(start, end));
246263}
247264
248−pub fn delete_selection(view: &mut View, _count: usize) {
249− let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
265+pub fn delete_selection(cx: &mut Context) {
266+ let transaction = Transaction::change_by_selection(&cx.view.doc.state, |range| {
250267 (range.from(), range.to() + 1, None)
251268 });
252− view.doc.apply(&transaction);
269+ cx.view.doc.apply(&transaction);
253270
254− append_changes_to_history(view);
271+ append_changes_to_history(cx);
255272}
256273
257−pub fn change_selection(view: &mut View, count: usize) {
258− delete_selection(view, count);
259− insert_mode(view, count);
274+pub fn change_selection(cx: &mut Context) {
275+ delete_selection(cx);
276+ insert_mode(cx);
260277}
261278
262−pub fn collapse_selection(view: &mut View, _count: usize) {
263− let selection = view
279+pub fn collapse_selection(cx: &mut Context) {
280+ let selection = cx
281+ .view
264282 .doc
265283 .selection()
266284 .transform(|range| Range::new(range.head, range.head));
267285
268− view.doc.set_selection(selection);
286+ cx.view.doc.set_selection(selection);
269287}
270288
271−pub fn flip_selections(view: &mut View, _count: usize) {
272− let selection = view
289+pub fn flip_selections(cx: &mut Context) {
290+ let selection = cx
291+ .view
273292 .doc
274293 .selection()
275294 .transform(|range| Range::new(range.head, range.anchor));
276295
277− view.doc.set_selection(selection);
296+ cx.view.doc.set_selection(selection);
278297}
279298
280−fn enter_insert_mode(view: &mut View) {
281− view.doc.mode = Mode::Insert;
299+fn enter_insert_mode(cx: &mut Context) {
300+ cx.view.doc.mode = Mode::Insert;
282301
283− append_changes_to_history(view);
302+ append_changes_to_history(cx);
284303}
285304// inserts at the start of each selection
286−pub fn insert_mode(view: &mut View, _count: usize) {
287− enter_insert_mode(view);
305+pub fn insert_mode(cx: &mut Context) {
306+ enter_insert_mode(cx);
288307
289− let selection = view
308+ let selection = cx
309+ .view
290310 .doc
291311 .selection()
292312 .transform(|range| Range::new(range.to(), range.from()));
293− view.doc.set_selection(selection);
313+ cx.view.doc.set_selection(selection);
294314}
295315
296316// inserts at the end of each selection
297−pub fn append_mode(view: &mut View, _count: usize) {
298− enter_insert_mode(view);
299− view.doc.restore_cursor = true;
317+pub fn append_mode(cx: &mut Context) {
318+ enter_insert_mode(cx);
319+ cx.view.doc.restore_cursor = true;
300320
301321 // TODO: as transaction
302− let text = &view.doc.text().slice(..);
303− let selection = view.doc.selection().transform(|range| {
322+ let text = &cx.view.doc.text().slice(..);
323+ let selection = cx.view.doc.selection().transform(|range| {
304324 // TODO: to() + next char
305325 Range::new(
306326 range.from(),
307327 graphemes::next_grapheme_boundary(text, range.to()),
308328 )
309329 });
310− view.doc.set_selection(selection);
330+ cx.view.doc.set_selection(selection);
311331}
312332
313333// TODO: I, A, o and O can share a lot of the primitives.
@@ -332,30 +352,30 @@ fn selection_lines(state: &State) -> Vec<usize> {
332352}
333353
334354// I inserts at the start of each line with a selection
335−pub fn prepend_to_line(view: &mut View, count: usize) {
336− enter_insert_mode(view);
355+pub fn prepend_to_line(cx: &mut Context) {
356+ enter_insert_mode(cx);
337357
338− move_line_start(view, count);
358+ move_line_start(cx);
339359}
340360
341361// A inserts at the end of each line with a selection
342−pub fn append_to_line(view: &mut View, count: usize) {
343− enter_insert_mode(view);
362+pub fn append_to_line(cx: &mut Context) {
363+ enter_insert_mode(cx);
344364
345− move_line_end(view, count);
365+ move_line_end(cx);
346366}
347367
348368// o inserts a new line after each line with a selection
349−pub fn open_below(view: &mut View, _count: usize) {
350− enter_insert_mode(view);
369+pub fn open_below(cx: &mut Context) {
370+ enter_insert_mode(cx);
351371
352− let lines = selection_lines(&view.doc.state);
372+ let lines = selection_lines(&cx.view.doc.state);
353373
354374 let positions: Vec<_> = lines
355375 .into_iter()
356376 .map(|index| {
357377 // adjust all positions to the end of the line/start of the next one.
358− view.doc.text().line_to_char(index + 1)
378+ cx.view.doc.text().line_to_char(index + 1)
359379 })
360380 .collect();
361381
@@ -376,82 +396,85 @@ pub fn open_below(view: &mut View, _count: usize) {
376396 0,
377397 );
378398
379− let transaction = Transaction::change(&view.doc.state, changes).with_selection(selection);
399+ let transaction = Transaction::change(&cx.view.doc.state, changes).with_selection(selection);
380400
381− view.doc.apply(&transaction);
401+ cx.view.doc.apply(&transaction);
382402}
383403
384404// O inserts a new line before each line with a selection
385405
386−fn append_changes_to_history(view: &mut View) {
387− if view.doc.changes.is_empty() {
406+fn append_changes_to_history(cx: &mut Context) {
407+ if cx.view.doc.changes.is_empty() {
388408 return;
389409 }
390410
391− let new_changeset = ChangeSet::new(view.doc.text());
392− let changes = std::mem::replace(&mut view.doc.changes, new_changeset);
411+ let new_changeset = ChangeSet::new(cx.view.doc.text());
412+ let changes = std::mem::replace(&mut cx.view.doc.changes, new_changeset);
393413 // Instead of doing this messy merge we could always commit, and based on transaction
394414 // annotations either add a new layer or compose into the previous one.
395− let transaction = Transaction::from(changes).with_selection(view.doc.selection().clone());
415+ let transaction = Transaction::from(changes).with_selection(cx.view.doc.selection().clone());
396416
397417 // increment document version
398418 // TODO: needs to happen on undo/redo too
399− view.doc.version += 1;
419+ cx.view.doc.version += 1;
400420
401421 // TODO: trigger lsp/documentDidChange with changes
402422
403423 // HAXX: we need to reconstruct the state as it was before the changes..
404− let old_state = std::mem::replace(&mut view.doc.old_state, view.doc.state.clone());
424+ let old_state = std::mem::replace(&mut cx.view.doc.old_state, cx.view.doc.state.clone());
405425 // TODO: take transaction by value?
406− view.doc.history.commit_revision(&transaction, &old_state);
426+ cx.view
427+ .doc
428+ .history
429+ .commit_revision(&transaction, &old_state);
407430
408431 // TODO: notify LSP of changes
409432}
410433
411−pub fn normal_mode(view: &mut View, _count: usize) {
412− view.doc.mode = Mode::Normal;
434+pub fn normal_mode(cx: &mut Context) {
435+ cx.view.doc.mode = Mode::Normal;
413436
414− append_changes_to_history(view);
437+ append_changes_to_history(cx);
415438
416439 // if leaving append mode, move cursor back by 1
417− if view.doc.restore_cursor {
418− let text = &view.doc.text().slice(..);
419− let selection = view.doc.selection().transform(|range| {
440+ if cx.view.doc.restore_cursor {
441+ let text = &cx.view.doc.text().slice(..);
442+ let selection = cx.view.doc.selection().transform(|range| {
420443 Range::new(
421444 range.from(),
422445 graphemes::prev_grapheme_boundary(text, range.to()),
423446 )
424447 });
425− view.doc.set_selection(selection);
448+ cx.view.doc.set_selection(selection);
426449
427− view.doc.restore_cursor = false;
450+ cx.view.doc.restore_cursor = false;
428451 }
429452}
430453
431−pub fn goto_mode(view: &mut View, _count: usize) {
432− view.doc.mode = Mode::Goto;
454+pub fn goto_mode(cx: &mut Context) {
455+ cx.view.doc.mode = Mode::Goto;
433456}
434457
435458// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
436459pub mod insert {
437460 use super::*;
438461 // TODO: insert means add text just before cursor, on exit we should be on the last letter.
439− pub fn insert_char(view: &mut View, c: char) {
462+ pub fn insert_char(cx: &mut Context, c: char) {
440463 let c = Tendril::from_char(c);
441− let transaction = Transaction::insert(&view.doc.state, c);
464+ let transaction = Transaction::insert(&cx.view.doc.state, c);
442465
443− view.doc.apply(&transaction);
466+ cx.view.doc.apply(&transaction);
444467 }
445468
446− pub fn insert_tab(view: &mut View, _count: usize) {
447− insert_char(view, '\t');
469+ pub fn insert_tab(cx: &mut Context) {
470+ insert_char(cx, '\t');
448471 }
449472
450− pub fn insert_newline(view: &mut View, _count: usize) {
451− let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
473+ pub fn insert_newline(cx: &mut Context) {
474+ let transaction = Transaction::change_by_selection(&cx.view.doc.state, |range| {
452475 let indent_level = helix_core::indent::suggested_indent_for_pos(
453− view.doc.syntax.as_ref(),
454− &view.doc.state,
476+ cx.view.doc.syntax.as_ref(),
477+ &cx.view.doc.state,
455478 range.head,
456479 );
457480 let indent = " ".repeat(TAB_WIDTH).repeat(indent_level);
@@ -460,32 +483,32 @@ pub mod insert {
460483 text.push_str(&indent);
461484 (range.head, range.head, Some(text.into()))
462485 });
463− view.doc.apply(&transaction);
486+ cx.view.doc.apply(&transaction);
464487 }
465488
466489 // TODO: handle indent-aware delete
467− pub fn delete_char_backward(view: &mut View, count: usize) {
468− let text = &view.doc.text().slice(..);
469− let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
490+ pub fn delete_char_backward(cx: &mut Context) {
491+ let text = &cx.view.doc.text().slice(..);
492+ let transaction = Transaction::change_by_selection(&cx.view.doc.state, |range| {
470493 (
471− graphemes::nth_prev_grapheme_boundary(text, range.head, count),
494+ graphemes::nth_prev_grapheme_boundary(text, range.head, cx.count),
472495 range.head,
473496 None,
474497 )
475498 });
476− view.doc.apply(&transaction);
499+ cx.view.doc.apply(&transaction);
477500 }
478501
479− pub fn delete_char_forward(view: &mut View, count: usize) {
480− let text = &view.doc.text().slice(..);
481− let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
502+ pub fn delete_char_forward(cx: &mut Context) {
503+ let text = &cx.view.doc.text().slice(..);
504+ let transaction = Transaction::change_by_selection(&cx.view.doc.state, |range| {
482505 (
483506 range.head,
484− graphemes::nth_next_grapheme_boundary(text, range.head, count),
507+ graphemes::nth_next_grapheme_boundary(text, range.head, cx.count),
485508 None,
486509 )
487510 });
488− view.doc.apply(&transaction);
511+ cx.view.doc.apply(&transaction);
489512 }
490513}
491514
@@ -495,31 +518,32 @@ pub fn insert_char_prompt(prompt: &mut Prompt, c: char) {
495518
496519// Undo / Redo
497520
498−pub fn undo(view: &mut View, _count: usize) {
499− if let Some(revert) = view.doc.history.undo() {
500− view.doc.version += 1;
501− view.doc.apply(&revert);
521+pub fn undo(cx: &mut Context) {
522+ if let Some(revert) = cx.view.doc.history.undo() {
523+ cx.view.doc.version += 1;
524+ cx.view.doc.apply(&revert);
502525 }
503526
504527 // TODO: each command could simply return a Option<transaction>, then the higher level handles storing it?
505528}
506529
507−pub fn redo(view: &mut View, _count: usize) {
508− if let Some(transaction) = view.doc.history.redo() {
509− view.doc.version += 1;
510− view.doc.apply(&transaction);
530+pub fn redo(cx: &mut Context) {
531+ if let Some(transaction) = cx.view.doc.history.redo() {
532+ cx.view.doc.version += 1;
533+ cx.view.doc.apply(&transaction);
511534 }
512535}
513536
514537// Yank / Paste
515538
516−pub fn yank(view: &mut View, _count: usize) {
539+pub fn yank(cx: &mut Context) {
517540 // TODO: should selections be made end inclusive?
518− let values = view
541+ let values = cx
542+ .view
519543 .doc
520544 .state
521545 .selection()
522− .fragments(&view.doc.text().slice(..))
546+ .fragments(&cx.view.doc.text().slice(..))
523547 .map(|cow| cow.into_owned())
524548 .collect();
525549
@@ -528,7 +552,7 @@ pub fn yank(view: &mut View, _count: usize) {
528552 register::set(reg, values);
529553}
530554
531−pub fn paste(view: &mut View, _count: usize) {
555+pub fn paste(cx: &mut Context) {
532556 // TODO: allow specifying reg
533557 let reg = '"';
534558 if let Some(values) = register::get(reg) {
@@ -560,19 +584,19 @@ pub fn paste(view: &mut View, _count: usize) {
560584 let transaction = if linewise {
561585 // paste on the next line
562586 // TODO: can simply take a range + modifier and compute the right pos without ifs
563− let text = view.doc.text();
564− Transaction::change_by_selection(&view.doc.state, |range| {
587+ let text = cx.view.doc.text();
588+ Transaction::change_by_selection(&cx.view.doc.state, |range| {
565589 let line_end = text.line_to_char(text.char_to_line(range.head) + 1);
566590 (line_end, line_end, Some(values.next().unwrap()))
567591 })
568592 } else {
569− Transaction::change_by_selection(&view.doc.state, |range| {
593+ Transaction::change_by_selection(&cx.view.doc.state, |range| {
570594 (range.head + 1, range.head + 1, Some(values.next().unwrap()))
571595 })
572596 };
573597
574− view.doc.apply(&transaction);
575− append_changes_to_history(view);
598+ cx.view.doc.apply(&transaction);
599+ append_changes_to_history(cx);
576600 }
577601}
578602
@@ -593,29 +617,29 @@ fn get_lines(view: &View) -> Vec<usize> {
593617 lines
594618}
595619
596−pub fn indent(view: &mut View, _count: usize) {
597− let lines = get_lines(view);
620+pub fn indent(cx: &mut Context) {
621+ let lines = get_lines(cx.view);
598622
599623 // Indent by one level
600624 let indent = Tendril::from(" ".repeat(TAB_WIDTH));
601625
602626 let transaction = Transaction::change(
603− &view.doc.state,
627+ &cx.view.doc.state,
604628 lines.into_iter().map(|line| {
605− let pos = view.doc.text().line_to_char(line);
629+ let pos = cx.view.doc.text().line_to_char(line);
606630 (pos, pos, Some(indent.clone()))
607631 }),
608632 );
609− view.doc.apply(&transaction);
610− append_changes_to_history(view);
633+ cx.view.doc.apply(&transaction);
634+ append_changes_to_history(cx);
611635}
612636
613−pub fn unindent(view: &mut View, _count: usize) {
614− let lines = get_lines(view);
637+pub fn unindent(cx: &mut Context) {
638+ let lines = get_lines(cx.view);
615639 let mut changes = Vec::with_capacity(lines.len());
616640
617641 for line_idx in lines {
618− let line = view.doc.text().line(line_idx);
642+ let line = cx.view.doc.text().line(line_idx);
619643 let mut width = 0;
620644
621645 for ch in line.chars() {
@@ -631,18 +655,18 @@ pub fn unindent(view: &mut View, _count: usize) {
631655 }
632656
633657 if width > 0 {
634− let start = view.doc.text().line_to_char(line_idx);
658+ let start = cx.view.doc.text().line_to_char(line_idx);
635659 changes.push((start, start + width, None))
636660 }
637661 }
638662
639− let transaction = Transaction::change(&view.doc.state, changes.into_iter());
663+ let transaction = Transaction::change(&cx.view.doc.state, changes.into_iter());
640664
641− view.doc.apply(&transaction);
642− append_changes_to_history(view);
665+ cx.view.doc.apply(&transaction);
666+ append_changes_to_history(cx);
643667}
644668
645−pub fn indent_selection(_view: &mut View, _count: usize) {
669+pub fn indent_selection(_cx: &mut Context) {
646670 // loop over each line and recompute proper indentation
647671 unimplemented!()
648672}