diff --git a/crates/vim/src/normal/increment.rs b/crates/vim/src/normal/increment.rs index b0501eeef7da3c2930af4971971f4ce2a0c44456..ec24064b31adb79c8158a5a9ab6a890265ae2ec3 100644 --- a/crates/vim/src/normal/increment.rs +++ b/crates/vim/src/normal/increment.rs @@ -98,32 +98,40 @@ impl Vim { } } -fn increment_decimal_string(mut num: &str, mut delta: i64) -> String { - let mut negative = false; - if num.chars().next() == Some('-') { - negative = true; - delta = 0 - delta; - num = &num[1..]; - } - let result = if let Ok(value) = u64::from_str_radix(num, 10) { - let wrapped = value.wrapping_add_signed(delta); - if delta < 0 && wrapped > value { - negative = !negative; - (u64::MAX - wrapped).wrapping_add(1) - } else if delta > 0 && wrapped < value { - negative = !negative; - u64::MAX - wrapped - } else { - wrapped +fn increment_decimal_string(num: &str, delta: i64) -> String { + let (negative, delta, num_str) = match num.strip_prefix('-') { + Some(n) => (true, -delta, n), + None => (false, delta, num), + }; + let num_length = num_str.len(); + let leading_zero = num_str.starts_with('0'); + + let (result, new_negative) = match u64::from_str_radix(num_str, 10) { + Ok(value) => { + let wrapped = value.wrapping_add_signed(delta); + if delta < 0 && wrapped > value { + ((u64::MAX - wrapped).wrapping_add(1), !negative) + } else if delta > 0 && wrapped < value { + (u64::MAX - wrapped, !negative) + } else { + (wrapped, negative) + } } + Err(_) => (u64::MAX, negative), + }; + + let formatted = format!("{}", result); + let new_significant_digits = formatted.len(); + let padding = if leading_zero { + num_length.saturating_sub(new_significant_digits) } else { - u64::MAX + 0 }; - if result == 0 || !negative { - format!("{}", result) + if new_negative && result != 0 { + format!("-{}{}", "0".repeat(padding), formatted) } else { - format!("-{}", result) + format!("{}{}", "0".repeat(padding), formatted) } } @@ -286,6 +294,63 @@ mod test { "}); } + #[gpui::test] + async fn test_increment_with_leading_zeros(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await; + + cx.set_shared_state(indoc! {" + 000ˇ9 + "}) + .await; + + cx.simulate_shared_keystrokes("ctrl-a").await; + cx.shared_state().await.assert_eq(indoc! {" + 001ˇ0 + "}); + cx.simulate_shared_keystrokes("2 ctrl-x").await; + cx.shared_state().await.assert_eq(indoc! {" + 000ˇ8 + "}); + } + + #[gpui::test] + async fn test_increment_with_leading_zeros_and_zero(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await; + + cx.set_shared_state(indoc! {" + 01ˇ1 + "}) + .await; + + cx.simulate_shared_keystrokes("ctrl-a").await; + cx.shared_state().await.assert_eq(indoc! {" + 01ˇ2 + "}); + cx.simulate_shared_keystrokes("1 2 ctrl-x").await; + cx.shared_state().await.assert_eq(indoc! {" + 00ˇ0 + "}); + } + + #[gpui::test] + async fn test_increment_with_changing_leading_zeros(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await; + + cx.set_shared_state(indoc! {" + 099ˇ9 + "}) + .await; + + cx.simulate_shared_keystrokes("ctrl-a").await; + cx.shared_state().await.assert_eq(indoc! {" + 100ˇ0 + "}); + cx.simulate_shared_keystrokes("2 ctrl-x").await; + cx.shared_state().await.assert_eq(indoc! {" + 99ˇ8 + "}); + } + #[gpui::test] async fn test_increment_with_two_dots(cx: &mut gpui::TestAppContext) { let mut cx = NeovimBackedTestContext::new(cx).await; @@ -322,6 +387,27 @@ mod test { "}); } + #[gpui::test] + async fn test_increment_sign_change_with_leading_zeros(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await; + cx.set_shared_state(indoc! {" + 00ˇ1 + "}) + .await; + cx.simulate_shared_keystrokes("ctrl-x").await; + cx.shared_state().await.assert_eq(indoc! {" + 00ˇ0 + "}); + cx.simulate_shared_keystrokes("ctrl-x").await; + cx.shared_state().await.assert_eq(indoc! {" + -00ˇ1 + "}); + cx.simulate_shared_keystrokes("2 ctrl-a").await; + cx.shared_state().await.assert_eq(indoc! {" + 00ˇ1 + "}); + } + #[gpui::test] async fn test_increment_bin_wrapping_and_padding(cx: &mut gpui::TestAppContext) { let mut cx = NeovimBackedTestContext::new(cx).await; diff --git a/crates/vim/test_data/test_increment_sign_change_with_leading_zeros.json b/crates/vim/test_data/test_increment_sign_change_with_leading_zeros.json new file mode 100644 index 0000000000000000000000000000000000000000..c1257012b5656d0122651b51a0815533a3638f40 --- /dev/null +++ b/crates/vim/test_data/test_increment_sign_change_with_leading_zeros.json @@ -0,0 +1,8 @@ +{"Put":{"state":"00ˇ1\n"}} +{"Key":"ctrl-x"} +{"Get":{"state":"00ˇ0\n","mode":"Normal"}} +{"Key":"ctrl-x"} +{"Get":{"state":"-00ˇ1\n","mode":"Normal"}} +{"Key":"2"} +{"Key":"ctrl-a"} +{"Get":{"state":"00ˇ1\n","mode":"Normal"}} diff --git a/crates/vim/test_data/test_increment_with_changing_leading_zeros.json b/crates/vim/test_data/test_increment_with_changing_leading_zeros.json new file mode 100644 index 0000000000000000000000000000000000000000..dce392e25f286ae114adb3fd1014fef8f211322e --- /dev/null +++ b/crates/vim/test_data/test_increment_with_changing_leading_zeros.json @@ -0,0 +1,6 @@ +{"Put":{"state":"099ˇ9\n"}} +{"Key":"ctrl-a"} +{"Get":{"state":"100ˇ0\n","mode":"Normal"}} +{"Key":"2"} +{"Key":"ctrl-x"} +{"Get":{"state":"99ˇ8\n","mode":"Normal"}} diff --git a/crates/vim/test_data/test_increment_with_leading_zeros.json b/crates/vim/test_data/test_increment_with_leading_zeros.json new file mode 100644 index 0000000000000000000000000000000000000000..bab262463f6be0d61885364642945eee41485d41 --- /dev/null +++ b/crates/vim/test_data/test_increment_with_leading_zeros.json @@ -0,0 +1,6 @@ +{"Put":{"state":"000ˇ9\n"}} +{"Key":"ctrl-a"} +{"Get":{"state":"001ˇ0\n","mode":"Normal"}} +{"Key":"2"} +{"Key":"ctrl-x"} +{"Get":{"state":"000ˇ8\n","mode":"Normal"}} diff --git a/crates/vim/test_data/test_increment_with_leading_zeros_and_zero.json b/crates/vim/test_data/test_increment_with_leading_zeros_and_zero.json new file mode 100644 index 0000000000000000000000000000000000000000..94a1a1a71573afa84eb1d0327e2b172a5a492072 --- /dev/null +++ b/crates/vim/test_data/test_increment_with_leading_zeros_and_zero.json @@ -0,0 +1,7 @@ +{"Put":{"state":"01ˇ1\n"}} +{"Key":"ctrl-a"} +{"Get":{"state":"01ˇ2\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"2"} +{"Key":"ctrl-x"} +{"Get":{"state":"00ˇ0\n","mode":"Normal"}} diff --git a/crates/vim/test_data/test_increment_zero_leading_zeros.json b/crates/vim/test_data/test_increment_zero_leading_zeros.json new file mode 100644 index 0000000000000000000000000000000000000000..5361fcbc7fb481416559769b71ae2d606cf88600 --- /dev/null +++ b/crates/vim/test_data/test_increment_zero_leading_zeros.json @@ -0,0 +1,4 @@ +{"Put":{"state":"001ˇ0\n"}} +{"Key":"10"} +{"Key":"ctrl-x"} +{"Get":{"state":"000ˇ9\n","mode":"Normal"}}