Add `Increment` trait

imgbot
Jason Rodney Hansen 3 years ago committed by Ivan Tham
parent 2a0c685a78
commit c9641fcced

@ -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<NaiveDate> {
fn add_months(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
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<NaiveDate> {
fn add_years(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
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()
);
}

@ -0,0 +1,8 @@
pub mod date;
pub mod number;
use crate::{Range, Tendril};
pub trait Increment {
fn increment(&self, amount: i64) -> (Range, Tendril);
}

@ -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<str> = 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()
);
}

@ -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;

@ -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<Box<dyn Increment>> = 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 {

Loading…
Cancel
Save