commands: Implement count for a few more commands.

This commit is contained in:
Blaž Hrastnik 2021-02-24 17:29:28 +09:00
parent 5fa1ba6b1c
commit 01907b3497
4 changed files with 89 additions and 73 deletions

13
TODO.md
View file

@ -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

View file

@ -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(

View file

@ -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));
}

View file

@ -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,
}