Add `Increment` trait

pull/1235/head
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 chrono::{Datelike, Duration, NaiveDate};
use super::Increment;
fn ndays_in_month(year: i32, month: u32) -> u32 { fn ndays_in_month(year: i32, month: u32) -> u32 {
// The first day of the next month... // The first day of the next month...
let (y, m) = if month == 12 { 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> { fn add_months(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
let month = date.month0() as i64 + amount; let month = date.month0() as i64 + amount;
let year = date.year() + i32::try_from(month / 12).ok()?; let year = date.year() + i32::try_from(month / 12).ok()?;
let year = if month.is_negative() { year - 1 } else { year };
// Normalize month // Normalize month
let month = month % 12; 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> { fn add_years(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
let year = i32::try_from(date.year() as i64 + amount).ok()?; let year = i32::try_from(date.year() as i64 + amount).ok()?;
let ndays = ndays_in_month(year, date.month()); let ndays = ndays_in_month(year, date.month());
if date.day() > ndays { if date.day() > ndays {
@ -85,9 +87,8 @@ enum DateField {
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct DateIncrementor { pub struct DateIncrementor {
pub date: NaiveDate, date: NaiveDate,
pub range: Range, range: Range,
field: DateField, field: DateField,
format: Format, 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 { let date = match self.field {
DateField::Year => add_years(self.date, amount), DateField::Year => add_years(self.date, amount),
DateField::Month => add_months(self.date, amount), DateField::Month => add_months(self.date, amount),
@ -159,15 +162,18 @@ impl DateIncrementor {
} }
.unwrap_or(self.date); .unwrap_or(self.date);
format!( (
"{:04}{}{:02}{}{:02}", self.range,
date.year(), format!(
self.format.separator, "{:04}{}{:02}{}{:02}",
date.month(), date.year(),
self.format.separator, self.format.separator,
date.day() date.month(),
self.format.separator,
date.day()
)
.into(),
) )
.into()
} }
} }
@ -437,6 +443,8 @@ mod test {
("2020-02-29", 0, 1, "2021-03-01"), ("2020-02-29", 0, 1, "2021-03-01"),
("2020-01-31", 5, 1, "2020-02-29"), ("2020-01-31", 5, 1, "2020-02-29"),
("2020-01-20", 5, 1, "2020-02-20"), ("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"), ("2020-02-28", 8, 1, "2020-02-29"),
("2021-02-28", 8, 1, "2021-03-01"), ("2021-02-28", 8, 1, "2021-03-01"),
("2021-02-28", 0, -1, "2020-02-28"), ("2021-02-28", 0, -1, "2020-02-28"),
@ -457,7 +465,8 @@ mod test {
assert_eq!( assert_eq!(
DateIncrementor::from_range(rope.slice(..), range) DateIncrementor::from_range(rope.slice(..), range)
.unwrap() .unwrap()
.incremented_text(amount), .increment(amount)
.1,
expected.into() 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 ropey::RopeSlice;
use super::Increment;
use crate::{ use crate::{
textobject::{textobject_word, TextObject}, textobject::{textobject_word, TextObject},
Range, Tendril, Range, Tendril,
@ -9,9 +11,9 @@ use crate::{
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct NumberIncrementor<'a> { pub struct NumberIncrementor<'a> {
pub range: Range, value: i64,
pub value: i64, radix: u32,
pub radix: u32, range: Range,
text: RopeSlice<'a>, text: RopeSlice<'a>,
} }
@ -71,9 +73,10 @@ impl<'a> NumberIncrementor<'a> {
text, text,
}) })
} }
}
/// Add `amount` to the number and return the formatted text. impl<'a> Increment for NumberIncrementor<'a> {
pub fn incremented_text(&self, amount: i64) -> Tendril { fn increment(&self, amount: i64) -> (Range, Tendril) {
let old_text: Cow<str> = self.text.slice(self.range.from()..self.range.to()).into(); let old_text: Cow<str> = self.text.slice(self.range.from()..self.range.to()).into();
let old_length = old_text.len(); let old_length = old_text.len();
let new_value = self.value.wrapping_add(amount); 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!( assert_eq!(
NumberIncrementor::from_range(rope.slice(..), range) NumberIncrementor::from_range(rope.slice(..), range)
.unwrap() .unwrap()
.incremented_text(amount), .increment(amount)
.1,
expected.into() expected.into()
); );
} }
@ -392,7 +396,8 @@ mod test {
assert_eq!( assert_eq!(
NumberIncrementor::from_range(rope.slice(..), range) NumberIncrementor::from_range(rope.slice(..), range)
.unwrap() .unwrap()
.incremented_text(amount), .increment(amount)
.1,
expected.into() expected.into()
); );
} }
@ -419,7 +424,8 @@ mod test {
assert_eq!( assert_eq!(
NumberIncrementor::from_range(rope.slice(..), range) NumberIncrementor::from_range(rope.slice(..), range)
.unwrap() .unwrap()
.incremented_text(amount), .increment(amount)
.1,
expected.into() expected.into()
); );
} }
@ -464,7 +470,8 @@ mod test {
assert_eq!( assert_eq!(
NumberIncrementor::from_range(rope.slice(..), range) NumberIncrementor::from_range(rope.slice(..), range)
.unwrap() .unwrap()
.incremented_text(amount), .increment(amount)
.1,
expected.into() expected.into()
); );
} }
@ -491,7 +498,8 @@ mod test {
assert_eq!( assert_eq!(
NumberIncrementor::from_range(rope.slice(..), range) NumberIncrementor::from_range(rope.slice(..), range)
.unwrap() .unwrap()
.incremented_text(amount), .increment(amount)
.1,
expected.into() expected.into()
); );
} }

@ -1,17 +1,16 @@
pub mod auto_pairs; pub mod auto_pairs;
pub mod chars; pub mod chars;
pub mod comment; pub mod comment;
pub mod date;
pub mod diagnostic; pub mod diagnostic;
pub mod diff; pub mod diff;
pub mod graphemes; pub mod graphemes;
pub mod history; pub mod history;
pub mod increment;
pub mod indent; pub mod indent;
pub mod line_ending; pub mod line_ending;
pub mod macros; pub mod macros;
pub mod match_brackets; pub mod match_brackets;
pub mod movement; pub mod movement;
pub mod numbers;
pub mod object; pub mod object;
pub mod path; pub mod path;
mod position; mod position;

@ -1,14 +1,13 @@
use helix_core::{ use helix_core::{
comment, coords_at_pos, comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes,
date::DateIncrementor,
find_first_non_whitespace_char, find_root, graphemes,
history::UndoKind, history::UndoKind,
increment::date::DateIncrementor,
increment::{number::NumberIncrementor, Increment},
indent, indent,
indent::IndentStyle, indent::IndentStyle,
line_ending::{get_line_ending_of_str, line_end_char_index, str_is_line_ending}, line_ending::{get_line_ending_of_str, line_end_char_index, str_is_line_ending},
match_brackets, match_brackets,
movement::{self, Direction}, movement::{self, Direction},
numbers::NumberIncrementor,
object, pos_at_coords, object, pos_at_coords,
regex::{self, Regex, RegexBuilder}, regex::{self, Regex, RegexBuilder},
search, selection, surround, textobject, search, selection, surround, textobject,
@ -5804,23 +5803,18 @@ fn increment_impl(cx: &mut Context, amount: i64) {
let text = doc.text(); let text = doc.text();
let changes = selection.ranges().iter().filter_map(|range| { let changes = selection.ranges().iter().filter_map(|range| {
if let Some(incrementor) = DateIncrementor::from_range(text.slice(..), *range) { let incrementor: Option<Box<dyn Increment>> = if let Some(incrementor) =
let new_text = incrementor.incremented_text(amount); DateIncrementor::from_range(text.slice(..), *range)
Some(( {
incrementor.range.from(), Some(Box::new(incrementor))
incrementor.range.to(),
Some(new_text),
))
} else if let Some(incrementor) = NumberIncrementor::from_range(text.slice(..), *range) { } else if let Some(incrementor) = NumberIncrementor::from_range(text.slice(..), *range) {
let new_text = incrementor.incremented_text(amount); Some(Box::new(incrementor))
Some((
incrementor.range.from(),
incrementor.range.to(),
Some(new_text),
))
} else { } else {
None None
} };
let (range, new_text) = incrementor?.increment(amount);
Some((range.from(), range.to(), Some(new_text)))
}); });
if changes.clone().count() > 0 { if changes.clone().count() > 0 {

Loading…
Cancel
Save