Add Increment
trait
This commit is contained in:
parent
2a0c685a78
commit
c9641fcced
5 changed files with 63 additions and 45 deletions
|
@ -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()
|
||||
);
|
||||
}
|
8
helix-core/src/increment/mod.rs
Normal file
8
helix-core/src/increment/mod.rs
Normal file
|
@ -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…
Reference in a new issue