on master help sign in
Add `Increment` trait
commitc9641fccedc51737a74ed47009279fa688462ea9 authorJason Rodney Hansen <jasonrodneyhansen@gmail.com> dateSun 21 Nov 2021, 10:38 (5 years ago) parent2a0c685
5 files changed+63−45
helix-core/src/date.rs → helix-core/src/increment/date.rs+23−14 helix-core/src/increment/mod.rs+8 helix-core/src/numbers.rs → helix-core/src/increment/number.rs+19−11 helix-core/src/lib.rs+1−2 helix-term/src/commands.rs+12−18
helix-core/src/date.rs → helix-core/src/increment/date.rsrenamed+23−14
@@ -9,6 +9,8 @@ use crate::{Range, Tendril};
99
1010use chrono::{Datelike, Duration, NaiveDate};
1111
12+use super::Increment;
13+
1214fn ndays_in_month(year: i32, month: u32) -> u32 {
1315 // The first day of the next month...
1416 let (y, m) = if month == 12 {
@@ -29,6 +31,7 @@ fn add_days(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
2931fn add_months(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
3032 let month = date.month0() as i64 + amount;
3133 let year = date.year() + i32::try_from(month / 12).ok()?;
34+ let year = if month.is_negative() { year - 1 } else { year };
3235
3336 // Normalize month
3437 let month = month % 12;
@@ -45,7 +48,6 @@ fn add_months(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
4548
4649fn add_years(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
4750 let year = i32::try_from(date.year() as i64 + amount).ok()?;
48−
4951 let ndays = ndays_in_month(year, date.month());
5052
5153 if date.day() > ndays {
@@ -85,9 +87,8 @@ enum DateField {
8587
8688#[derive(Debug, PartialEq, Eq)]
8789pub struct DateIncrementor {
88− pub date: NaiveDate,
89− pub range: Range,
90−
90+ date: NaiveDate,
91+ range: Range,
9192 field: DateField,
9293 format: Format,
9394}
@@ -150,8 +151,10 @@ impl DateIncrementor {
150151 })
151152 })
152153 }
154+}
153155
154− pub fn incremented_text(&self, amount: i64) -> Tendril {
156+impl Increment for DateIncrementor {
157+ fn increment(&self, amount: i64) -> (Range, Tendril) {
155158 let date = match self.field {
156159 DateField::Year => add_years(self.date, amount),
157160 DateField::Month => add_months(self.date, amount),
@@ -159,15 +162,18 @@ impl DateIncrementor {
159162 }
160163 .unwrap_or(self.date);
161164
162− format!(
163− "{:04}{}{:02}{}{:02}",
164− date.year(),
165− self.format.separator,
166− date.month(),
167− self.format.separator,
168− date.day()
165+ (
166+ self.range,
167+ format!(
168+ "{:04}{}{:02}{}{:02}",
169+ date.year(),
170+ self.format.separator,
171+ date.month(),
172+ self.format.separator,
173+ date.day()
174+ )
175+ .into(),
169176 )
170− .into()
171177 }
172178}
173179
@@ -437,6 +443,8 @@ mod test {
437443 ("2020-02-29", 0, 1, "2021-03-01"),
438444 ("2020-01-31", 5, 1, "2020-02-29"),
439445 ("2020-01-20", 5, 1, "2020-02-20"),
446+ ("2021-01-01", 5, -1, "2020-12-01"),
447+ ("2021-01-31", 5, -2, "2020-11-30"),
440448 ("2020-02-28", 8, 1, "2020-02-29"),
441449 ("2021-02-28", 8, 1, "2021-03-01"),
442450 ("2021-02-28", 0, -1, "2020-02-28"),
@@ -457,7 +465,8 @@ mod test {
457465 assert_eq!(
458466 DateIncrementor::from_range(rope.slice(..), range)
459467 .unwrap()
460− .incremented_text(amount),
468+ .increment(amount)
469+ .1,
461470 expected.into()
462471 );
463472 }
helix-core/src/increment/mod.rsnew file+8
@@ -0,0 +1,8 @@
1+pub mod date;
2+pub mod number;
3+
4+use crate::{Range, Tendril};
5+
6+pub trait Increment {
7+ fn increment(&self, amount: i64) -> (Range, Tendril);
8+}
helix-core/src/numbers.rs → helix-core/src/increment/number.rsrenamed+19−11
@@ -2,6 +2,8 @@ use std::borrow::Cow;
22
33use ropey::RopeSlice;
44
5+use super::Increment;
6+
57use crate::{
68 textobject::{textobject_word, TextObject},
79 Range, Tendril,
@@ -9,9 +11,9 @@ use crate::{
911
1012#[derive(Debug, PartialEq, Eq)]
1113pub struct NumberIncrementor<'a> {
12− pub range: Range,
13− pub value: i64,
14− pub radix: u32,
14+ value: i64,
15+ radix: u32,
16+ range: Range,
1517
1618 text: RopeSlice<'a>,
1719}
@@ -71,9 +73,10 @@ impl<'a> NumberIncrementor<'a> {
7173 text,
7274 })
7375 }
76+}
7477
75− /// Add `amount` to the number and return the formatted text.
76− pub fn incremented_text(&self, amount: i64) -> Tendril {
78+impl<'a> Increment for NumberIncrementor<'a> {
79+ fn increment(&self, amount: i64) -> (Range, Tendril) {
7780 let old_text: Cow<str> = self.text.slice(self.range.from()..self.range.to()).into();
7881 let old_length = old_text.len();
7982 let new_value = self.value.wrapping_add(amount);
@@ -144,7 +147,7 @@ impl<'a> NumberIncrementor<'a> {
144147 }
145148 }
146149
147− new_text.into()
150+ (self.range, new_text.into())
148151 }
149152}
150153
@@ -366,7 +369,8 @@ mod test {
366369 assert_eq!(
367370 NumberIncrementor::from_range(rope.slice(..), range)
368371 .unwrap()
369− .incremented_text(amount),
372+ .increment(amount)
373+ .1,
370374 expected.into()
371375 );
372376 }
@@ -392,7 +396,8 @@ mod test {
392396 assert_eq!(
393397 NumberIncrementor::from_range(rope.slice(..), range)
394398 .unwrap()
395− .incremented_text(amount),
399+ .increment(amount)
400+ .1,
396401 expected.into()
397402 );
398403 }
@@ -419,7 +424,8 @@ mod test {
419424 assert_eq!(
420425 NumberIncrementor::from_range(rope.slice(..), range)
421426 .unwrap()
422− .incremented_text(amount),
427+ .increment(amount)
428+ .1,
423429 expected.into()
424430 );
425431 }
@@ -464,7 +470,8 @@ mod test {
464470 assert_eq!(
465471 NumberIncrementor::from_range(rope.slice(..), range)
466472 .unwrap()
467− .incremented_text(amount),
473+ .increment(amount)
474+ .1,
468475 expected.into()
469476 );
470477 }
@@ -491,7 +498,8 @@ mod test {
491498 assert_eq!(
492499 NumberIncrementor::from_range(rope.slice(..), range)
493500 .unwrap()
494− .incremented_text(amount),
501+ .increment(amount)
502+ .1,
495503 expected.into()
496504 );
497505 }
helix-core/src/lib.rs+1−2
@@ -1,17 +1,16 @@
11pub mod auto_pairs;
22pub mod chars;
33pub mod comment;
4−pub mod date;
54pub mod diagnostic;
65pub mod diff;
76pub mod graphemes;
87pub mod history;
8+pub mod increment;
99pub mod indent;
1010pub mod line_ending;
1111pub mod macros;
1212pub mod match_brackets;
1313pub mod movement;
14−pub mod numbers;
1514pub mod object;
1615pub mod path;
1716mod position;
helix-term/src/commands.rs+12−18
@@ -1,14 +1,13 @@
11use helix_core::{
2− comment, coords_at_pos,
3− date::DateIncrementor,
4− find_first_non_whitespace_char, find_root, graphemes,
2+ comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes,
53 history::UndoKind,
4+ increment::date::DateIncrementor,
5+ increment::{number::NumberIncrementor, Increment},
66 indent,
77 indent::IndentStyle,
88 line_ending::{get_line_ending_of_str, line_end_char_index, str_is_line_ending},
99 match_brackets,
1010 movement::{self, Direction},
11− numbers::NumberIncrementor,
1211 object, pos_at_coords,
1312 regex::{self, Regex, RegexBuilder},
1413 search, selection, surround, textobject,
@@ -5804,23 +5803,18 @@ fn increment_impl(cx: &mut Context, amount: i64) {
58045803 let text = doc.text();
58055804
58065805 let changes = selection.ranges().iter().filter_map(|range| {
5807− if let Some(incrementor) = DateIncrementor::from_range(text.slice(..), *range) {
5808− let new_text = incrementor.incremented_text(amount);
5809− Some((
5810− incrementor.range.from(),
5811− incrementor.range.to(),
5812− Some(new_text),
5813− ))
5806+ let incrementor: Option<Box<dyn Increment>> = if let Some(incrementor) =
5807+ DateIncrementor::from_range(text.slice(..), *range)
5808+ {
5809+ Some(Box::new(incrementor))
58145810 } else if let Some(incrementor) = NumberIncrementor::from_range(text.slice(..), *range) {
5815− let new_text = incrementor.incremented_text(amount);
5816− Some((
5817− incrementor.range.from(),
5818− incrementor.range.to(),
5819− Some(new_text),
5820− ))
5811+ Some(Box::new(incrementor))
58215812 } else {
58225813 None
5823− }
5814+ };
5815+
5816+ let (range, new_text) = incrementor?.increment(amount);
5817+ Some((range.from(), range.to(), Some(new_text)))
58245818 });
58255819
58265820 if changes.clone().count() > 0 {