Skip to content

Commit

Permalink
added Incrementer for config driven ordered lists.
Browse files Browse the repository at this point in the history
  • Loading branch information
Aiko Mastboom committed Aug 18, 2022
1 parent c18b542 commit 7f05340
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 2 deletions.
1 change: 1 addition & 0 deletions book/src/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ You may also specify a file to use for configuration with the `-c` or
| `true-color` | Set to `true` to override automatic detection of terminal truecolor support in the event of a false negative. | `false` |
| `rulers` | List of column positions at which to display the rulers. Can be overridden by language specific `rulers` in `languages.toml` file. | `[]` |
| `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` |
| `ordered-lists` | Use increment/decrement command to traverse these lists (of arbitrary length) | `[["yes", "no"],["on","off"]]`|

### `[editor.statusline]` Section

Expand Down
1 change: 1 addition & 0 deletions helix-core/src/increment/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod date_time;
pub mod number;
pub mod ordered_list;

use crate::{Range, Tendril};

Expand Down
144 changes: 144 additions & 0 deletions helix-core/src/increment/ordered_list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
use super::Increment;
use ropey::RopeSlice;
use std::string::String;

use crate::{
textobject::{textobject_word, TextObject},
Range, Tendril,
};

#[derive(Debug, PartialEq, Eq)]
pub struct OrderedListWalker<'a> {
walkway: &'a Vec<String>,
index: usize,
is_capitalized: bool,
range: Range,
}

impl<'a> OrderedListWalker<'a> {
pub fn from_range(
text: RopeSlice,
range: Range,
config: &'a Vec<Vec<String>>,
) -> Option<OrderedListWalker<'a>> {
let range = textobject_word(text, range, TextObject::Inside, 1, false);
let word: String = text.slice(range.from()..range.to()).chars().collect();
if word.len() <= 0 {
// no word found
return None;
}
let lower_case_word: String = word.to_lowercase();
for (_i, walkway) in config.into_iter().enumerate() {
for (index, w) in walkway.into_iter().enumerate() {
if w.len() > 0 && lower_case_word.eq(w.to_lowercase().as_str()) {
let is_capitalized: bool = word.chars().next().unwrap().is_uppercase();
return Some(OrderedListWalker {
walkway,
index,
is_capitalized,
range,
});
}
}
}
None
}
}

impl<'a> Increment for OrderedListWalker<'a> {
fn increment(&self, amount: i64) -> (Range, Tendril) {
let pos: usize =
(self.index as i64 + amount).rem_euclid(self.walkway.len() as i64) as usize;
let mut s: String = self.walkway.get(pos).unwrap().into();
if self.is_capitalized {
// https://stackoverflow.com/questions/38406793/why-is-capitalizing-the-first-letter-of-a-string-so-convoluted-in-rust
s = s.chars().next().unwrap().to_uppercase().to_string()
+ s.chars().skip(1).collect::<String>().as_str();
}
(self.range, s.into())
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::Rope;

#[test]
fn test_ordered_from_range() {
let rope = Rope::from_str("Test text true more text.");
let range = Range::point(12);
let walkway_one = vec!["true".to_owned(), "false".to_owned()];
let walkway_two = vec!["ja".to_owned(), "nee".to_owned()];
let config = vec![walkway_two, walkway_one.to_owned()];
assert_eq!(
OrderedListWalker::from_range(rope.slice(..), range, &config),
Some(OrderedListWalker {
range: Range::new(10, 14),
walkway: &walkway_one,
index: 0,
is_capitalized: false,
})
);
let range = Range::point(10);
assert_eq!(
OrderedListWalker::from_range(rope.slice(..), range, &config),
Some(OrderedListWalker {
range: Range::new(10, 14),
walkway: &walkway_one,
index: 0,
is_capitalized: false,
})
);
let range = Range::point(13);
assert_eq!(
OrderedListWalker::from_range(rope.slice(..), range, &config),
Some(OrderedListWalker {
range: Range::new(10, 14),
walkway: &walkway_one,
index: 0,
is_capitalized: false,
})
);
let range = Range::point(14);
assert_eq!(
OrderedListWalker::from_range(rope.slice(..), range, &config),
None,
);
let range = Range::point(9);
assert_eq!(
OrderedListWalker::from_range(rope.slice(..), range, &config),
None,
);
}

#[test]
#[ignore]
fn test_ordered_increment() {
let walkway_one = vec!["true".to_owned(), "false".to_owned()];
let walkway_two = vec!["ja".to_owned(), "nee".to_owned()];
let config = vec![walkway_two, walkway_one];

let tests = [
("false", "false", 2),
("false", "true", 1),
("false", "true", -1),
("false", "false", -2),
("False", "True", 1),
("True", "False", -1),
("Ja", "Nee", 3),
];

for (original, expected, amount) in tests {
let rope = Rope::from_str(original);
let range = Range::point(0);
assert_eq!(
OrderedListWalker::from_range(rope.slice(..), range, &config)
.unwrap()
.increment(amount)
.1,
Tendril::from(expected)
);
}
}
}
11 changes: 9 additions & 2 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ pub use typed::*;
use helix_core::{
comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes,
history::UndoKind,
increment::date_time::DateTimeIncrementor,
increment::{number::NumberIncrementor, Increment},
increment::{
date_time::DateTimeIncrementor, number::NumberIncrementor, ordered_list::OrderedListWalker,
Increment,
},
indent,
indent::IndentStyle,
line_ending::{get_line_ending_of_str, line_end_char_index, str_is_line_ending},
Expand Down Expand Up @@ -4739,6 +4741,7 @@ fn increment_impl(cx: &mut Context, amount: i64) {
1,
);

let ordered_lists = &cx.editor.config().ordered_lists;
let (view, doc) = current!(cx.editor);
let selection = doc.selection(view.id);
let text = doc.text().slice(..);
Expand All @@ -4752,6 +4755,10 @@ fn increment_impl(cx: &mut Context, amount: i64) {
Box::new(incrementor)
} else if let Some(incrementor) = NumberIncrementor::from_range(text, *range) {
Box::new(incrementor)
} else if let Some(incrementor) =
OrderedListWalker::from_range(text, *range, ordered_lists)
{
Box::new(incrementor)
} else {
return None;
};
Expand Down
6 changes: 6 additions & 0 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ pub struct Config {
pub indent_guides: IndentGuidesConfig,
/// Whether to color modes with different colors. Defaults to `false`.
pub color_modes: bool,
/// ordered lists
pub ordered_lists: Vec<Vec<String>>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -499,6 +501,10 @@ impl Default for Config {
whitespace: WhitespaceConfig::default(),
indent_guides: IndentGuidesConfig::default(),
color_modes: false,
ordered_lists: vec![
vec!["yes".to_owned(), "no".to_owned()],
vec!["on".to_owned(), "off".to_owned()],
],
}
}
}
Expand Down

0 comments on commit 7f05340

Please sign in to comment.