on master help sign in
commands: Implement count for a few more commands.
01907b3Blaž Hrastnik
TODO.md+10−3
@@ -12,16 +12,16 @@
12- [x] % for whole doc selection
12- [x] % for whole doc selection
13- [x] vertical splits
13- [x] vertical splits
14- [x] input counts (30j)
14- [x] input counts (30j)
15− - [ ] input counts for b, w, e
15+ - [x] input counts for b, w, e
16- [ ] respect view fullscreen flag
16- [ ] respect view fullscreen flag
17- [x] retain horiz when moving vertically
17- [x] retain horiz when moving vertically
18+- [w] retain horiz when moving via ctrl-u/d
18- [x] deindent
19- [x] deindent
19- [ ] ensure_cursor_in_view always before rendering? or always in app after event process?
20- [ ] ensure_cursor_in_view always before rendering? or always in app after event process?
20- [x] update lsp on redo/undo
21- [x] update lsp on redo/undo
21- [ ] Implement marks (superset of Selection/Range)
22- [ ] Implement marks (superset of Selection/Range)
22- [ ] ctrl-v/ctrl-x on file picker
23- [ ] ctrl-v/ctrl-x on file picker
23- [ ] linewise selection work
24- [ ] linewise selection work
24−- [ ] goto definition
25- [ ] nixos packaging
25- [ ] nixos packaging
26- [ ] CI binary builds
26- [ ] CI binary builds
27
27
@@ -33,6 +33,13 @@
33- [ ] buffers should sit on editor.buffers, view simply refs them
33- [ ] buffers should sit on editor.buffers, view simply refs them
34
34
35
35
36+- [ ] lsp: signature help
37+- [ ] lsp: hover
38+- [ ] lsp: document symbols (nested/vec)
39+- [ ] lsp: code actions
40+- [ ] lsp: formatting
41+- [ ] lsp: goto
42+
362
432
37- [ ] tab completion for paths on the prompt
44- [ ] tab completion for paths on the prompt
38- [ ] extend selection (treesitter select parent node) (replaces viw, vi(, va( etc )
45- [ ] extend selection (treesitter select parent node) (replaces viw, vi(, va( etc )
@@ -41,7 +48,7 @@
41- [ ] completion signature popups/docs
48- [ ] completion signature popups/docs
42- [ ] multiple views into the same file
49- [ ] multiple views into the same file
43- [ ] selection align
50- [ ] selection align
44−- [ ] store some state: file positions, prompt history
51+- [ ] store some state between restarts: file positions, prompt history
45
52
463
533
47- [ ] diagnostics popups
54- [ ] diagnostics popups
helix-core/src/state.rs+55−47
@@ -120,76 +120,84 @@ impl State {
120 }
120 }
121 }
121 }
122
122
123− pub fn move_next_word_start(slice: RopeSlice, mut pos: usize) -> usize {
123+ pub fn move_next_word_start(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
124 // TODO: confirm it's fine without using graphemes, I think it should be
124 // TODO: confirm it's fine without using graphemes, I think it should be
125+ for _ in 0..count {
125− let ch = slice.char(pos);
126+ let ch = slice.char(pos);
126− let next = slice.char(pos.saturating_add(1));
127+ let next = slice.char(pos.saturating_add(1));
127− if categorize(ch) != categorize(next) {
128+ if categorize(ch) != categorize(next) {
128− pos += 1;
129+ pos += 1;
129− }
130+ }
130
131
131− // refetch
132+ // refetch
132− let ch = slice.char(pos);
133+ let ch = slice.char(pos);
133
134
134− if is_word(ch) {
135+ if is_word(ch) {
135− skip_over_next(slice, &mut pos, is_word);
136+ skip_over_next(slice, &mut pos, is_word);
136− } else if ch.is_ascii_punctuation() {
137+ } else if ch.is_ascii_punctuation() {
137− skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
138+ skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
138− }
139+ }
139
140
140− // TODO: don't include newline?
141+ // TODO: don't include newline?
141− skip_over_next(slice, &mut pos, |ch| ch.is_ascii_whitespace());
142+ skip_over_next(slice, &mut pos, |ch| ch.is_ascii_whitespace());
143+ }
142
144
143 pos
145 pos
144 }
146 }
145
147
146− pub fn move_prev_word_start(slice: RopeSlice, mut pos: usize) -> usize {
148+ pub fn move_prev_word_start(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
147 // TODO: confirm it's fine without using graphemes, I think it should be
149 // TODO: confirm it's fine without using graphemes, I think it should be
150+ for _ in 0..count {
148− let ch = slice.char(pos);
151+ let ch = slice.char(pos);
149− let prev = slice.char(pos.saturating_sub(1)); // TODO: just return original pos if at start
152+ let prev = slice.char(pos.saturating_sub(1)); // TODO: just return original pos if at start
150
153
151− if categorize(ch) != categorize(prev) {
154+ if categorize(ch) != categorize(prev) {
152− pos -= 1;
155+ pos -= 1;
153− }
156+ }
154
157
155− // TODO: skip while eol
158+ // TODO: skip while eol
156
159
157− // TODO: don't include newline?
160+ // TODO: don't include newline?
158− skip_over_prev(slice, &mut pos, |ch| ch.is_ascii_whitespace());
161+ skip_over_prev(slice, &mut pos, |ch| ch.is_ascii_whitespace());
159
162
160− // refetch
163+ // refetch
161− let ch = slice.char(pos);
164+ let ch = slice.char(pos);
162
165
163− if is_word(ch) {
166+ if is_word(ch) {
164− skip_over_prev(slice, &mut pos, is_word);
167+ skip_over_prev(slice, &mut pos, is_word);
165− } else if ch.is_ascii_punctuation() {
168+ } else if ch.is_ascii_punctuation() {
166− skip_over_prev(slice, &mut pos, |ch| ch.is_ascii_punctuation());
169+ skip_over_prev(slice, &mut pos, |ch| ch.is_ascii_punctuation());
170+ }
171+ pos = pos.saturating_add(1)
167 }
172 }
168
173
169− pos.saturating_add(1)
174+ pos
170 }
175 }
171
176
172− pub fn move_next_word_end(slice: RopeSlice, mut pos: usize, _count: usize) -> usize {
177+ pub fn move_next_word_end(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
178+ for _ in 0..count {
173− // TODO: confirm it's fine without using graphemes, I think it should be
179+ // TODO: confirm it's fine without using graphemes, I think it should be
174− let ch = slice.char(pos);
180+ let ch = slice.char(pos);
175− let next = slice.char(pos.saturating_add(1));
181+ let next = slice.char(pos.saturating_add(1));
176− if categorize(ch) != categorize(next) {
182+ if categorize(ch) != categorize(next) {
177− pos += 1;
183+ pos += 1;
178− }
184+ }
179
185
180− // TODO: don't include newline?
186+ // TODO: don't include newline?
181− skip_over_next(slice, &mut pos, |ch| ch.is_ascii_whitespace());
187+ skip_over_next(slice, &mut pos, |ch| ch.is_ascii_whitespace());
182
188
183− // refetch
189+ // refetch
184− let ch = slice.char(pos);
190+ let ch = slice.char(pos);
185
191
186− if is_word(ch) {
192+ if is_word(ch) {
187− skip_over_next(slice, &mut pos, is_word);
193+ skip_over_next(slice, &mut pos, is_word);
188− } else if ch.is_ascii_punctuation() {
194+ } else if ch.is_ascii_punctuation() {
189− skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
195+ skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
196+ }
197+ pos = pos.saturating_sub(1)
190 }
198 }
191
199
192− pos.saturating_sub(1)
200+ pos
193 }
201 }
194
202
195 pub fn move_selection(
203 pub fn move_selection(
helix-term/src/commands.rs+14−13
@@ -128,8 +128,7 @@ pub fn move_line_start(cx: &mut Context) {
128pub fn move_next_word_start(cx: &mut Context) {
128pub fn move_next_word_start(cx: &mut Context) {
129 let count = cx.count;
129 let count = cx.count;
130 let doc = cx.doc();
130 let doc = cx.doc();
131− // TODO: count
132− let pos = State::move_next_word_start(doc.text().slice(..), doc.selection().cursor());
131+ let pos = State::move_next_word_start(doc.text().slice(..), doc.selection().cursor(), count);
133
132
134 doc.set_selection(Selection::point(pos));
133 doc.set_selection(Selection::point(pos));
135}
134}
@@ -137,7 +136,7 @@ pub fn move_next_word_start(cx: &mut Context) {
137pub fn move_prev_word_start(cx: &mut Context) {
136pub fn move_prev_word_start(cx: &mut Context) {
138 let count = cx.count;
137 let count = cx.count;
139 let doc = cx.doc();
138 let doc = cx.doc();
140− let pos = State::move_prev_word_start(doc.text().slice(..), doc.selection().cursor());
139+ let pos = State::move_prev_word_start(doc.text().slice(..), doc.selection().cursor(), count);
141
140
142 doc.set_selection(Selection::point(pos));
141 doc.set_selection(Selection::point(pos));
143}
142}
@@ -169,11 +168,12 @@ pub fn move_file_end(cx: &mut Context) {
169pub fn extend_next_word_start(cx: &mut Context) {
168pub fn extend_next_word_start(cx: &mut Context) {
170 let count = cx.count;
169 let count = cx.count;
171 let doc = cx.doc();
170 let doc = cx.doc();
172− let mut selection = doc.selection().transform(|mut range| {
171+ let selection = doc.selection().transform(|mut range| {
172+ let pos =
173− let pos = State::move_next_word_start(doc.text().slice(..), doc.selection().cursor());
173+ State::move_next_word_start(doc.text().slice(..), doc.selection().cursor(), count);
174 range.head = pos;
174 range.head = pos;
175 range
175 range
176− }); // TODO: count
176+ });
177
177
178 doc.set_selection(selection);
178 doc.set_selection(selection);
179}
179}
@@ -181,22 +181,23 @@ pub fn extend_next_word_start(cx: &mut Context) {
181pub fn extend_prev_word_start(cx: &mut Context) {
181pub fn extend_prev_word_start(cx: &mut Context) {
182 let count = cx.count;
182 let count = cx.count;
183 let doc = cx.doc();
183 let doc = cx.doc();
184− let mut selection = doc.selection().transform(|mut range| {
184+ let selection = doc.selection().transform(|mut range| {
185+ let pos =
185− let pos = State::move_prev_word_start(doc.text().slice(..), doc.selection().cursor());
186+ State::move_prev_word_start(doc.text().slice(..), doc.selection().cursor(), count);
186 range.head = pos;
187 range.head = pos;
187 range
188 range
188− }); // TODO: count
189+ });
189 doc.set_selection(selection);
190 doc.set_selection(selection);
190}
191}
191
192
192pub fn extend_next_word_end(cx: &mut Context) {
193pub fn extend_next_word_end(cx: &mut Context) {
193 let count = cx.count;
194 let count = cx.count;
194 let doc = cx.doc();
195 let doc = cx.doc();
195− let mut selection = doc.selection().transform(|mut range| {
196+ let selection = doc.selection().transform(|mut range| {
196 let pos = State::move_next_word_end(doc.text().slice(..), doc.selection().cursor(), count);
197 let pos = State::move_next_word_end(doc.text().slice(..), doc.selection().cursor(), count);
197 range.head = pos;
198 range.head = pos;
198 range
199 range
199− }); // TODO: count
200+ });
200
201
201 doc.set_selection(selection);
202 doc.set_selection(selection);
202}
203}
@@ -417,13 +418,13 @@ pub fn search_selection(cx: &mut Context) {
417//
418//
418
419
419pub fn select_line(cx: &mut Context) {
420pub fn select_line(cx: &mut Context) {
420− // TODO: count
421+ let count = cx.count;
421 let doc = cx.doc();
422 let doc = cx.doc();
422 let pos = doc.selection().primary();
423 let pos = doc.selection().primary();
423 let text = doc.text();
424 let text = doc.text();
424 let line = text.char_to_line(pos.head);
425 let line = text.char_to_line(pos.head);
425 let start = text.line_to_char(line);
426 let start = text.line_to_char(line);
426− let end = text.line_to_char(line + 1).saturating_sub(1);
427+ let end = text.line_to_char(line + count).saturating_sub(1);
427
428
428 doc.set_selection(Selection::single(start, end));
429 doc.set_selection(Selection::single(start, end));
429}
430}
helix-view/src/editor.rs+1−1
@@ -12,7 +12,7 @@ pub struct Editor {
12 pub tree: Tree,
12 pub tree: Tree,
13 // pub documents: Vec<Document>,
13 // pub documents: Vec<Document>,
14 pub count: Option<usize>,
14 pub count: Option<usize>,
15− pub theme: Theme, // TODO: share one instance
15+ pub theme: Theme,
16 pub language_servers: helix_lsp::Registry,
16 pub language_servers: helix_lsp::Registry,
17}
17}
18
18