From 01907b349771106865853dc2ea90aaa0913a7297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Wed, 24 Feb 2021 17:29:28 +0900 Subject: [PATCH] commands: Implement count for a few more commands. --- TODO.md | 13 +++- helix-core/src/state.rs | 120 ++++++++++++++++++++----------------- helix-term/src/commands.rs | 27 +++++---- helix-view/src/editor.rs | 2 +- 4 files changed, 89 insertions(+), 73 deletions(-) diff --git a/TODO.md b/TODO.md index e378d457..9f20ebb2 100644 --- a/TODO.md +++ b/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 diff --git a/helix-core/src/state.rs b/helix-core/src/state.rs index 78c9deb0..90e75eb4 100644 --- a/helix-core/src/state.rs +++ b/helix-core/src/state.rs @@ -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( diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 2b8fe405..7d7ad0c9 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -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)); } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index b70a6abd..1c737b3e 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -12,7 +12,7 @@ pub struct Editor { pub tree: Tree, // pub documents: Vec, pub count: Option, - pub theme: Theme, // TODO: share one instance + pub theme: Theme, pub language_servers: helix_lsp::Registry, }