Repository: kkawakam/rustyline (Rust)

Issue:
Caret key (`^`) does not work as expected in evcxr_repl in vi edit mode
I originally posted the issue in google/evcxr#239 , but it turned out to be a bug of thi scrate, rustyline.

> Caret key should jump the cursor to the first non-empty character in the current line.  But it is implemented that it instead jumps ...
```
>> abc def
       ^ here.
```
> Seems that it instead moves the cursor to the character right after the first whitespace instead.

This seems due to a wrong implementation [here](https://github.com/kkawakam/rustyline/blob/05f94b12fb94a2329d5227b10a8520a93ad4a893/src/command.rs#L52-L55):

```rust
        Cmd::Move(Movement::ViFirstPrint) => {
            s.edit_move_home()?;
            s.edit_move_to_next_word(At::Start, Word::Big, 1)?;
        }
```

In this implementation, it first jumps to the beginning of the line, and then move to the "next" word considering any consecutive sequence of non-empty characters as a word.   This is problematic only when the first character is a non-empty character; since the cursor is already at the beginning of a "word", it jumps it to the succeeding word, causing the unintuitive behavior.

I am nst sure how should I properly fix it.  `s.edit_move_to_next_word` eventually calls `LineBuffer::next_word_pos` to find the actual position to jump to.   Should I modify the signature of this method to accept an additional argument for "Inclusive/Exclusive" enum?  Or shuold I call a different method in the `Move(ViFirstPrint)` match arm?


Discussion:
Thanks for the bug report.
```diff
diff --git a/src/command.rs b/src/command.rs
index c16f966..652e9f1 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -51,7 +51,9 @@ pub fn execute<H: Helper>(
         }
         Cmd::Move(Movement::ViFirstPrint) => {
             s.edit_move_home()?;
-            s.edit_move_to_next_word(At::Start, Word::Big, 1)?;
+            if s.line.starts_with(char::is_whitespace) {
+                s.edit_move_to_next_word(At::Start, Word::Big, 1)?;
+            }
         }
         Cmd::Move(Movement::BackwardChar(n)) => {
             // Move back a character.
```
not tested...
It worked!  (I modified `examples/example.rs` to change `Emcas` to `Vi` and ran it.)



Patch:
diff --git a/src/command.rs b/src/command.rs
index c16f9669f..652e9f1c0 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -51,7 +51,9 @@ pub fn execute<H: Helper>(
         }
         Cmd::Move(Movement::ViFirstPrint) => {
             s.edit_move_home()?;
-            s.edit_move_to_next_word(At::Start, Word::Big, 1)?;
+            if s.line.starts_with(char::is_whitespace) {
+                s.edit_move_to_next_word(At::Start, Word::Big, 1)?;
+            }
         }
         Cmd::Move(Movement::BackwardChar(n)) => {
             // Move back a character.


Test patch:
diff --git a/src/test/vi_cmd.rs b/src/test/vi_cmd.rs
index be8437d2d..c8ff89b2f 100644
--- a/src/test/vi_cmd.rs
+++ b/src/test/vi_cmd.rs
@@ -58,6 +58,16 @@ fn caret() {
     );
 }
 
+#[test]
+fn caret_no_whitespace() {
+    assert_cursor(
+        EditMode::Vi,
+        ("Hi", ""),
+        &[E::ESC, E::from('^'), E::ENTER],
+        ("", "Hi"),
+    );
+}
+
 #[test]
 fn a() {
     assert_cursor(