commands: Implement count for a few more commands.
This commit is contained in:
parent
5fa1ba6b1c
commit
01907b3497
4 changed files with 89 additions and 73 deletions
13
TODO.md
13
TODO.md
|
@ -12,16 +12,16 @@
|
|||
- [x] % for whole doc selection
|
||||
- [x] vertical splits
|
||||
- [x] input counts (30j)
|
||||
- [ ] input counts for b, w, e
|
||||
- [x] input counts for b, w, e
|
||||
- [ ] respect view fullscreen flag
|
||||
- [x] retain horiz when moving vertically
|
||||
- [w] retain horiz when moving via ctrl-u/d
|
||||
- [x] deindent
|
||||
- [ ] ensure_cursor_in_view always before rendering? or always in app after event process?
|
||||
- [x] update lsp on redo/undo
|
||||
- [ ] Implement marks (superset of Selection/Range)
|
||||
- [ ] ctrl-v/ctrl-x on file picker
|
||||
- [ ] linewise selection work
|
||||
- [ ] goto definition
|
||||
- [ ] nixos packaging
|
||||
- [ ] CI binary builds
|
||||
|
||||
|
@ -33,6 +33,13 @@
|
|||
- [ ] buffers should sit on editor.buffers, view simply refs them
|
||||
|
||||
|
||||
- [ ] lsp: signature help
|
||||
- [ ] lsp: hover
|
||||
- [ ] lsp: document symbols (nested/vec)
|
||||
- [ ] lsp: code actions
|
||||
- [ ] lsp: formatting
|
||||
- [ ] lsp: goto
|
||||
|
||||
2
|
||||
- [ ] tab completion for paths on the prompt
|
||||
- [ ] extend selection (treesitter select parent node) (replaces viw, vi(, va( etc )
|
||||
|
@ -41,7 +48,7 @@
|
|||
- [ ] completion signature popups/docs
|
||||
- [ ] multiple views into the same file
|
||||
- [ ] selection align
|
||||
- [ ] store some state: file positions, prompt history
|
||||
- [ ] store some state between restarts: file positions, prompt history
|
||||
|
||||
3
|
||||
- [ ] diagnostics popups
|
||||
|
|
|
@ -120,76 +120,84 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn move_next_word_start(slice: RopeSlice, mut pos: usize) -> usize {
|
||||
pub fn move_next_word_start(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
|
||||
// TODO: confirm it's fine without using graphemes, I think it should be
|
||||
let ch = slice.char(pos);
|
||||
let next = slice.char(pos.saturating_add(1));
|
||||
if categorize(ch) != categorize(next) {
|
||||
pos += 1;
|
||||
for _ in 0..count {
|
||||
let ch = slice.char(pos);
|
||||
let next = slice.char(pos.saturating_add(1));
|
||||
if categorize(ch) != categorize(next) {
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
// refetch
|
||||
let ch = slice.char(pos);
|
||||
|
||||
if is_word(ch) {
|
||||
skip_over_next(slice, &mut pos, is_word);
|
||||
} else if ch.is_ascii_punctuation() {
|
||||
skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
|
||||
}
|
||||
|
||||
// TODO: don't include newline?
|
||||
skip_over_next(slice, &mut pos, |ch| ch.is_ascii_whitespace());
|
||||
}
|
||||
|
||||
// refetch
|
||||
let ch = slice.char(pos);
|
||||
|
||||
if is_word(ch) {
|
||||
skip_over_next(slice, &mut pos, is_word);
|
||||
} else if ch.is_ascii_punctuation() {
|
||||
skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
|
||||
}
|
||||
|
||||
// TODO: don't include newline?
|
||||
skip_over_next(slice, &mut pos, |ch| ch.is_ascii_whitespace());
|
||||
|
||||
pos
|
||||
}
|
||||
|
||||
pub fn move_prev_word_start(slice: RopeSlice, mut pos: usize) -> usize {
|
||||
pub fn move_prev_word_start(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
|
||||
// TODO: confirm it's fine without using graphemes, I think it should be
|
||||
let ch = slice.char(pos);
|
||||
let prev = slice.char(pos.saturating_sub(1)); // TODO: just return original pos if at start
|
||||
for _ in 0..count {
|
||||
let ch = slice.char(pos);
|
||||
let prev = slice.char(pos.saturating_sub(1)); // TODO: just return original pos if at start
|
||||
|
||||
if categorize(ch) != categorize(prev) {
|
||||
pos -= 1;
|
||||
if categorize(ch) != categorize(prev) {
|
||||
pos -= 1;
|
||||
}
|
||||
|
||||
// TODO: skip while eol
|
||||
|
||||
// TODO: don't include newline?
|
||||
skip_over_prev(slice, &mut pos, |ch| ch.is_ascii_whitespace());
|
||||
|
||||
// refetch
|
||||
let ch = slice.char(pos);
|
||||
|
||||
if is_word(ch) {
|
||||
skip_over_prev(slice, &mut pos, is_word);
|
||||
} else if ch.is_ascii_punctuation() {
|
||||
skip_over_prev(slice, &mut pos, |ch| ch.is_ascii_punctuation());
|
||||
}
|
||||
pos = pos.saturating_add(1)
|
||||
}
|
||||
|
||||
// TODO: skip while eol
|
||||
|
||||
// TODO: don't include newline?
|
||||
skip_over_prev(slice, &mut pos, |ch| ch.is_ascii_whitespace());
|
||||
|
||||
// refetch
|
||||
let ch = slice.char(pos);
|
||||
|
||||
if is_word(ch) {
|
||||
skip_over_prev(slice, &mut pos, is_word);
|
||||
} else if ch.is_ascii_punctuation() {
|
||||
skip_over_prev(slice, &mut pos, |ch| ch.is_ascii_punctuation());
|
||||
}
|
||||
|
||||
pos.saturating_add(1)
|
||||
pos
|
||||
}
|
||||
|
||||
pub fn move_next_word_end(slice: RopeSlice, mut pos: usize, _count: usize) -> usize {
|
||||
// TODO: confirm it's fine without using graphemes, I think it should be
|
||||
let ch = slice.char(pos);
|
||||
let next = slice.char(pos.saturating_add(1));
|
||||
if categorize(ch) != categorize(next) {
|
||||
pos += 1;
|
||||
pub fn move_next_word_end(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
|
||||
for _ in 0..count {
|
||||
// TODO: confirm it's fine without using graphemes, I think it should be
|
||||
let ch = slice.char(pos);
|
||||
let next = slice.char(pos.saturating_add(1));
|
||||
if categorize(ch) != categorize(next) {
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
// TODO: don't include newline?
|
||||
skip_over_next(slice, &mut pos, |ch| ch.is_ascii_whitespace());
|
||||
|
||||
// refetch
|
||||
let ch = slice.char(pos);
|
||||
|
||||
if is_word(ch) {
|
||||
skip_over_next(slice, &mut pos, is_word);
|
||||
} else if ch.is_ascii_punctuation() {
|
||||
skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
|
||||
}
|
||||
pos = pos.saturating_sub(1)
|
||||
}
|
||||
|
||||
// TODO: don't include newline?
|
||||
skip_over_next(slice, &mut pos, |ch| ch.is_ascii_whitespace());
|
||||
|
||||
// refetch
|
||||
let ch = slice.char(pos);
|
||||
|
||||
if is_word(ch) {
|
||||
skip_over_next(slice, &mut pos, is_word);
|
||||
} else if ch.is_ascii_punctuation() {
|
||||
skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
|
||||
}
|
||||
|
||||
pos.saturating_sub(1)
|
||||
pos
|
||||
}
|
||||
|
||||
pub fn move_selection(
|
||||
|
|
|
@ -128,8 +128,7 @@ pub fn move_line_start(cx: &mut Context) {
|
|||
pub fn move_next_word_start(cx: &mut Context) {
|
||||
let count = cx.count;
|
||||
let doc = cx.doc();
|
||||
// TODO: count
|
||||
let pos = State::move_next_word_start(doc.text().slice(..), doc.selection().cursor());
|
||||
let pos = State::move_next_word_start(doc.text().slice(..), doc.selection().cursor(), count);
|
||||
|
||||
doc.set_selection(Selection::point(pos));
|
||||
}
|
||||
|
@ -137,7 +136,7 @@ pub fn move_next_word_start(cx: &mut Context) {
|
|||
pub fn move_prev_word_start(cx: &mut Context) {
|
||||
let count = cx.count;
|
||||
let doc = cx.doc();
|
||||
let pos = State::move_prev_word_start(doc.text().slice(..), doc.selection().cursor());
|
||||
let pos = State::move_prev_word_start(doc.text().slice(..), doc.selection().cursor(), count);
|
||||
|
||||
doc.set_selection(Selection::point(pos));
|
||||
}
|
||||
|
@ -169,11 +168,12 @@ pub fn move_file_end(cx: &mut Context) {
|
|||
pub fn extend_next_word_start(cx: &mut Context) {
|
||||
let count = cx.count;
|
||||
let doc = cx.doc();
|
||||
let mut selection = doc.selection().transform(|mut range| {
|
||||
let pos = State::move_next_word_start(doc.text().slice(..), doc.selection().cursor());
|
||||
let selection = doc.selection().transform(|mut range| {
|
||||
let pos =
|
||||
State::move_next_word_start(doc.text().slice(..), doc.selection().cursor(), count);
|
||||
range.head = pos;
|
||||
range
|
||||
}); // TODO: count
|
||||
});
|
||||
|
||||
doc.set_selection(selection);
|
||||
}
|
||||
|
@ -181,22 +181,23 @@ pub fn extend_next_word_start(cx: &mut Context) {
|
|||
pub fn extend_prev_word_start(cx: &mut Context) {
|
||||
let count = cx.count;
|
||||
let doc = cx.doc();
|
||||
let mut selection = doc.selection().transform(|mut range| {
|
||||
let pos = State::move_prev_word_start(doc.text().slice(..), doc.selection().cursor());
|
||||
let selection = doc.selection().transform(|mut range| {
|
||||
let pos =
|
||||
State::move_prev_word_start(doc.text().slice(..), doc.selection().cursor(), count);
|
||||
range.head = pos;
|
||||
range
|
||||
}); // TODO: count
|
||||
});
|
||||
doc.set_selection(selection);
|
||||
}
|
||||
|
||||
pub fn extend_next_word_end(cx: &mut Context) {
|
||||
let count = cx.count;
|
||||
let doc = cx.doc();
|
||||
let mut selection = doc.selection().transform(|mut range| {
|
||||
let selection = doc.selection().transform(|mut range| {
|
||||
let pos = State::move_next_word_end(doc.text().slice(..), doc.selection().cursor(), count);
|
||||
range.head = pos;
|
||||
range
|
||||
}); // TODO: count
|
||||
});
|
||||
|
||||
doc.set_selection(selection);
|
||||
}
|
||||
|
@ -417,13 +418,13 @@ pub fn search_selection(cx: &mut Context) {
|
|||
//
|
||||
|
||||
pub fn select_line(cx: &mut Context) {
|
||||
// TODO: count
|
||||
let count = cx.count;
|
||||
let doc = cx.doc();
|
||||
let pos = doc.selection().primary();
|
||||
let text = doc.text();
|
||||
let line = text.char_to_line(pos.head);
|
||||
let start = text.line_to_char(line);
|
||||
let end = text.line_to_char(line + 1).saturating_sub(1);
|
||||
let end = text.line_to_char(line + count).saturating_sub(1);
|
||||
|
||||
doc.set_selection(Selection::single(start, end));
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ pub struct Editor {
|
|||
pub tree: Tree,
|
||||
// pub documents: Vec<Document>,
|
||||
pub count: Option<usize>,
|
||||
pub theme: Theme, // TODO: share one instance
|
||||
pub theme: Theme,
|
||||
pub language_servers: helix_lsp::Registry,
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue