From c9641fccedc51737a74ed47009279fa688462ea9 Mon Sep 17 00:00:00 2001 From: Jason Rodney Hansen Date: Sun, 21 Nov 2021 10:38:41 -0700 Subject: [PATCH] Add `Increment` trait --- helix-core/src/{ => increment}/date.rs | 37 ++++++++++++------- helix-core/src/increment/mod.rs | 8 ++++ .../src/{numbers.rs => increment/number.rs} | 30 +++++++++------ helix-core/src/lib.rs | 3 +- helix-term/src/commands.rs | 30 ++++++--------- 5 files changed, 63 insertions(+), 45 deletions(-) rename helix-core/src/{ => increment}/date.rs (95%) create mode 100644 helix-core/src/increment/mod.rs rename helix-core/src/{numbers.rs => increment/number.rs} (96%) diff --git a/helix-core/src/date.rs b/helix-core/src/increment/date.rs similarity index 95% rename from helix-core/src/date.rs rename to helix-core/src/increment/date.rs index c447ef70..05442990 100644 --- a/helix-core/src/date.rs +++ b/helix-core/src/increment/date.rs @@ -9,6 +9,8 @@ use crate::{Range, Tendril}; use chrono::{Datelike, Duration, NaiveDate}; +use super::Increment; + fn ndays_in_month(year: i32, month: u32) -> u32 { // The first day of the next month... let (y, m) = if month == 12 { @@ -29,6 +31,7 @@ fn add_days(date: NaiveDate, amount: i64) -> Option { fn add_months(date: NaiveDate, amount: i64) -> Option { let month = date.month0() as i64 + amount; let year = date.year() + i32::try_from(month / 12).ok()?; + let year = if month.is_negative() { year - 1 } else { year }; // Normalize month let month = month % 12; @@ -45,7 +48,6 @@ fn add_months(date: NaiveDate, amount: i64) -> Option { fn add_years(date: NaiveDate, amount: i64) -> Option { let year = i32::try_from(date.year() as i64 + amount).ok()?; - let ndays = ndays_in_month(year, date.month()); if date.day() > ndays { @@ -85,9 +87,8 @@ enum DateField { #[derive(Debug, PartialEq, Eq)] pub struct DateIncrementor { - pub date: NaiveDate, - pub range: Range, - + date: NaiveDate, + range: Range, field: DateField, format: Format, } @@ -150,8 +151,10 @@ impl DateIncrementor { }) }) } +} - pub fn incremented_text(&self, amount: i64) -> Tendril { +impl Increment for DateIncrementor { + fn increment(&self, amount: i64) -> (Range, Tendril) { let date = match self.field { DateField::Year => add_years(self.date, amount), DateField::Month => add_months(self.date, amount), @@ -159,15 +162,18 @@ impl DateIncrementor { } .unwrap_or(self.date); - format!( - "{:04}{}{:02}{}{:02}", - date.year(), - self.format.separator, - date.month(), - self.format.separator, - date.day() + ( + self.range, + format!( + "{:04}{}{:02}{}{:02}", + date.year(), + self.format.separator, + date.month(), + self.format.separator, + date.day() + ) + .into(), ) - .into() } } @@ -437,6 +443,8 @@ mod test { ("2020-02-29", 0, 1, "2021-03-01"), ("2020-01-31", 5, 1, "2020-02-29"), ("2020-01-20", 5, 1, "2020-02-20"), + ("2021-01-01", 5, -1, "2020-12-01"), + ("2021-01-31", 5, -2, "2020-11-30"), ("2020-02-28", 8, 1, "2020-02-29"), ("2021-02-28", 8, 1, "2021-03-01"), ("2021-02-28", 0, -1, "2020-02-28"), @@ -457,7 +465,8 @@ mod test { assert_eq!( DateIncrementor::from_range(rope.slice(..), range) .unwrap() - .incremented_text(amount), + .increment(amount) + .1, expected.into() ); } diff --git a/helix-core/src/increment/mod.rs b/helix-core/src/increment/mod.rs new file mode 100644 index 00000000..71a1f183 --- /dev/null +++ b/helix-core/src/increment/mod.rs @@ -0,0 +1,8 @@ +pub mod date; +pub mod number; + +use crate::{Range, Tendril}; + +pub trait Increment { + fn increment(&self, amount: i64) -> (Range, Tendril); +} diff --git a/helix-core/src/numbers.rs b/helix-core/src/increment/number.rs similarity index 96% rename from helix-core/src/numbers.rs rename to helix-core/src/increment/number.rs index e9f3c898..a19b7e75 100644 --- a/helix-core/src/numbers.rs +++ b/helix-core/src/increment/number.rs @@ -2,6 +2,8 @@ use std::borrow::Cow; use ropey::RopeSlice; +use super::Increment; + use crate::{ textobject::{textobject_word, TextObject}, Range, Tendril, @@ -9,9 +11,9 @@ use crate::{ #[derive(Debug, PartialEq, Eq)] pub struct NumberIncrementor<'a> { - pub range: Range, - pub value: i64, - pub radix: u32, + value: i64, + radix: u32, + range: Range, text: RopeSlice<'a>, } @@ -71,9 +73,10 @@ impl<'a> NumberIncrementor<'a> { text, }) } +} - /// Add `amount` to the number and return the formatted text. - pub fn incremented_text(&self, amount: i64) -> Tendril { +impl<'a> Increment for NumberIncrementor<'a> { + fn increment(&self, amount: i64) -> (Range, Tendril) { let old_text: Cow = self.text.slice(self.range.from()..self.range.to()).into(); let old_length = old_text.len(); let new_value = self.value.wrapping_add(amount); @@ -144,7 +147,7 @@ impl<'a> NumberIncrementor<'a> { } } - new_text.into() + (self.range, new_text.into()) } } @@ -366,7 +369,8 @@ mod test { assert_eq!( NumberIncrementor::from_range(rope.slice(..), range) .unwrap() - .incremented_text(amount), + .increment(amount) + .1, expected.into() ); } @@ -392,7 +396,8 @@ mod test { assert_eq!( NumberIncrementor::from_range(rope.slice(..), range) .unwrap() - .incremented_text(amount), + .increment(amount) + .1, expected.into() ); } @@ -419,7 +424,8 @@ mod test { assert_eq!( NumberIncrementor::from_range(rope.slice(..), range) .unwrap() - .incremented_text(amount), + .increment(amount) + .1, expected.into() ); } @@ -464,7 +470,8 @@ mod test { assert_eq!( NumberIncrementor::from_range(rope.slice(..), range) .unwrap() - .incremented_text(amount), + .increment(amount) + .1, expected.into() ); } @@ -491,7 +498,8 @@ mod test { assert_eq!( NumberIncrementor::from_range(rope.slice(..), range) .unwrap() - .incremented_text(amount), + .increment(amount) + .1, expected.into() ); } diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index b16a716f..4ae044cc 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -1,17 +1,16 @@ pub mod auto_pairs; pub mod chars; pub mod comment; -pub mod date; pub mod diagnostic; pub mod diff; pub mod graphemes; pub mod history; +pub mod increment; pub mod indent; pub mod line_ending; pub mod macros; pub mod match_brackets; pub mod movement; -pub mod numbers; pub mod object; pub mod path; mod position; diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 639bbd83..6329dec7 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1,14 +1,13 @@ use helix_core::{ - comment, coords_at_pos, - date::DateIncrementor, - find_first_non_whitespace_char, find_root, graphemes, + comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes, history::UndoKind, + increment::date::DateIncrementor, + increment::{number::NumberIncrementor, Increment}, indent, indent::IndentStyle, line_ending::{get_line_ending_of_str, line_end_char_index, str_is_line_ending}, match_brackets, movement::{self, Direction}, - numbers::NumberIncrementor, object, pos_at_coords, regex::{self, Regex, RegexBuilder}, search, selection, surround, textobject, @@ -5804,23 +5803,18 @@ fn increment_impl(cx: &mut Context, amount: i64) { let text = doc.text(); let changes = selection.ranges().iter().filter_map(|range| { - if let Some(incrementor) = DateIncrementor::from_range(text.slice(..), *range) { - let new_text = incrementor.incremented_text(amount); - Some(( - incrementor.range.from(), - incrementor.range.to(), - Some(new_text), - )) + let incrementor: Option> = if let Some(incrementor) = + DateIncrementor::from_range(text.slice(..), *range) + { + Some(Box::new(incrementor)) } else if let Some(incrementor) = NumberIncrementor::from_range(text.slice(..), *range) { - let new_text = incrementor.incremented_text(amount); - Some(( - incrementor.range.from(), - incrementor.range.to(), - Some(new_text), - )) + Some(Box::new(incrementor)) } else { None - } + }; + + let (range, new_text) = incrementor?.increment(amount); + Some((range.from(), range.to(), Some(new_text))) }); if changes.clone().count() > 0 {