mirror of https://github.com/helix-editor/helix
parent
2cc5222226
commit
b0251ef715
|
@ -59,6 +59,7 @@
|
|||
| `switch_to_pascal_case` | Switch to PascalCase | normal: `` `p ``, select: `` `p `` |
|
||||
| `switch_to_camel_case` | Switch to camelCase | normal: `` `c ``, select: `` `c `` |
|
||||
| `switch_to_title_case` | Switch to Title Case | normal: `` `t ``, select: `` `t `` |
|
||||
| `switch_to_sentence_case` | Switch to Sentence case | normal: `` `S ``, select: `` `S `` |
|
||||
| `switch_to_snake_case` | Switch to snake_case | normal: `` `s ``, select: `` `s `` |
|
||||
| `switch_to_kebab_case` | Switch to kebab-case | normal: `` `k ``, select: `` `k `` |
|
||||
| `page_up` | Move page up | normal: `` <C-b> ``, `` Z<C-b> ``, `` z<C-b> ``, `` <pageup> ``, `` Z<pageup> ``, `` z<pageup> ``, select: `` <C-b> ``, `` Z<C-b> ``, `` z<C-b> ``, `` <pageup> ``, `` Z<pageup> ``, `` z<pageup> ``, insert: `` <pageup> `` |
|
||||
|
|
|
@ -247,6 +247,7 @@ Various commands for changing the case of text in different ways.
|
|||
| `p` | Switch text to Pascal Case | `switch_to_pascal_case` |
|
||||
| `c` | Switch text to camelCase | `switch_to_camel_case` |
|
||||
| `t` | Switch text to Title Case | `switch_to_title_case` |
|
||||
| `S` | Switch text to Sentence case | `switch_to_sentence_case` |
|
||||
| `s` | Switch text to snake_case | `switch_to_snake_case` |
|
||||
| `k` | Switch text to kebab-case | `switch_to_kebab_case` |
|
||||
| `a` | Switch text to aLTERNATE cASE | `switch_to_alternate_case` |
|
||||
|
|
|
@ -9,13 +9,20 @@ fn has_camel_transition(prev: Option<char>, current: char) -> bool {
|
|||
current.is_uppercase() && prev.is_some_and(|ch| ch.is_lowercase())
|
||||
}
|
||||
|
||||
pub fn smart_case_conversion(
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
enum CapitalizeWords {
|
||||
AllButFirst,
|
||||
All,
|
||||
First,
|
||||
}
|
||||
|
||||
fn smart_case_conversion(
|
||||
chars: impl Iterator<Item = char>,
|
||||
buf: &mut Tendril,
|
||||
capitalize_first: bool,
|
||||
capitalize: CapitalizeWords,
|
||||
separator: Option<char>,
|
||||
) {
|
||||
let mut should_capitalize_current = capitalize_first;
|
||||
let mut should_capitalize_current = capitalize != CapitalizeWords::AllButFirst;
|
||||
let mut prev = None;
|
||||
|
||||
let add_separator_if_needed = |prev: Option<char>, buf: &mut Tendril| {
|
||||
|
@ -30,7 +37,7 @@ pub fn smart_case_conversion(
|
|||
|
||||
for current in chars.skip_while(|ch| ch.is_whitespace()) {
|
||||
if !current.is_alphanumeric() {
|
||||
should_capitalize_current = true;
|
||||
should_capitalize_current = capitalize != CapitalizeWords::First;
|
||||
add_separator_if_needed(prev, buf);
|
||||
prev = Some(current);
|
||||
continue;
|
||||
|
@ -38,7 +45,7 @@ pub fn smart_case_conversion(
|
|||
|
||||
if has_camel_transition(prev, current) {
|
||||
add_separator_if_needed(prev, buf);
|
||||
should_capitalize_current = true;
|
||||
should_capitalize_current = capitalize != CapitalizeWords::First;
|
||||
}
|
||||
|
||||
if should_capitalize_current {
|
||||
|
@ -54,7 +61,7 @@ pub fn smart_case_conversion(
|
|||
*buf = buf.trim_end().into();
|
||||
}
|
||||
|
||||
pub fn separator_case_conversion(
|
||||
fn separator_case_conversion(
|
||||
chars: impl Iterator<Item = char>,
|
||||
buf: &mut Tendril,
|
||||
separator: char,
|
||||
|
@ -143,15 +150,19 @@ pub fn into_snake_case(chars: impl Iterator<Item = char>, buf: &mut Tendril) {
|
|||
}
|
||||
|
||||
pub fn into_title_case(chars: impl Iterator<Item = char>, buf: &mut Tendril) {
|
||||
smart_case_conversion(chars, buf, true, Some(' '));
|
||||
smart_case_conversion(chars, buf, CapitalizeWords::All, Some(' '));
|
||||
}
|
||||
|
||||
pub fn into_sentence_case(chars: impl Iterator<Item = char>, buf: &mut Tendril) {
|
||||
smart_case_conversion(chars, buf, CapitalizeWords::First, Some(' '));
|
||||
}
|
||||
|
||||
pub fn into_camel_case(chars: impl Iterator<Item = char>, buf: &mut Tendril) {
|
||||
smart_case_conversion(chars, buf, false, None);
|
||||
smart_case_conversion(chars, buf, CapitalizeWords::AllButFirst, None);
|
||||
}
|
||||
|
||||
pub fn into_pascal_case(chars: impl Iterator<Item = char>, buf: &mut Tendril) {
|
||||
smart_case_conversion(chars, buf, true, None);
|
||||
smart_case_conversion(chars, buf, CapitalizeWords::All, None);
|
||||
}
|
||||
|
||||
/// Create functional versions of the "into_*" case functions that take a `&mut Tendril`
|
||||
|
@ -176,6 +187,7 @@ to_case! {
|
|||
into_title_case => to_title_case
|
||||
into_kebab_case => to_kebab_case
|
||||
into_snake_case => to_snake_case
|
||||
into_sentence_case => to_sentence_case
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -296,6 +308,7 @@ mod tests {
|
|||
fn test_title_case_conversion() {
|
||||
let tests = [
|
||||
("hello world", "Hello World"),
|
||||
("hello world again", "Hello World Again"),
|
||||
("Hello World", "Hello World"),
|
||||
("hello_world", "Hello World"),
|
||||
("HELLO_WORLD", "Hello World"),
|
||||
|
@ -315,6 +328,30 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sentence_case_conversion() {
|
||||
let tests = [
|
||||
("hello world", "Hello world"),
|
||||
("hello world again", "Hello world again"),
|
||||
("Hello World", "Hello world"),
|
||||
("hello_world", "Hello world"),
|
||||
("HELLO_WORLD", "Hello world"),
|
||||
("hello-world", "Hello world"),
|
||||
("hello world", "Hello world"),
|
||||
(" hello world", "Hello world"),
|
||||
("hello\tworld", "Hello world"),
|
||||
("HELLO WORLD", "Hello world"),
|
||||
("HELLO-world", "Hello world"),
|
||||
("hello WORLD ", "Hello world"),
|
||||
("helloWorld", "Hello world"),
|
||||
];
|
||||
|
||||
for (input, expected) in tests {
|
||||
dbg!(input);
|
||||
assert_eq!(to_sentence_case(input.chars()), expected)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kebab_case_conversion() {
|
||||
let tests = [
|
||||
|
|
|
@ -18,11 +18,7 @@ use tui::{
|
|||
pub use typed::*;
|
||||
|
||||
use helix_core::{
|
||||
case_conversion::{
|
||||
to_alternate_case, to_camel_case, to_kebab_case, to_lowercase, to_pascal_case,
|
||||
to_snake_case, to_title_case, to_uppercase,
|
||||
},
|
||||
char_idx_at_visual_offset,
|
||||
case_conversion, char_idx_at_visual_offset,
|
||||
chars::char_is_word,
|
||||
command_line, comment,
|
||||
doc_formatter::TextFormat,
|
||||
|
@ -361,6 +357,7 @@ impl MappableCommand {
|
|||
switch_to_pascal_case, "Switch to PascalCase",
|
||||
switch_to_camel_case, "Switch to camelCase",
|
||||
switch_to_title_case, "Switch to Title Case",
|
||||
switch_to_sentence_case, "Switch to Sentence case",
|
||||
switch_to_snake_case, "Switch to snake_case",
|
||||
switch_to_kebab_case, "Switch to kebab-case",
|
||||
page_up, "Move page up",
|
||||
|
@ -1717,6 +1714,7 @@ fn replace(cx: &mut Context) {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn switch_case_impl<F>(cx: &mut Context, change_fn: F)
|
||||
where
|
||||
F: for<'a> Fn(&mut (dyn Iterator<Item = char> + 'a)) -> Tendril,
|
||||
|
@ -1739,35 +1737,39 @@ where
|
|||
}
|
||||
|
||||
fn switch_to_pascal_case(cx: &mut Context) {
|
||||
switch_case_impl(cx, |chars| to_pascal_case(chars))
|
||||
switch_case_impl(cx, |chars| case_conversion::to_pascal_case(chars))
|
||||
}
|
||||
|
||||
fn switch_to_camel_case(cx: &mut Context) {
|
||||
switch_case_impl(cx, |chars| to_camel_case(chars))
|
||||
switch_case_impl(cx, |chars| case_conversion::to_camel_case(chars))
|
||||
}
|
||||
|
||||
fn switch_to_lowercase(cx: &mut Context) {
|
||||
switch_case_impl(cx, |chars| to_lowercase(chars))
|
||||
switch_case_impl(cx, |chars| case_conversion::to_lowercase(chars))
|
||||
}
|
||||
|
||||
fn switch_to_uppercase(cx: &mut Context) {
|
||||
switch_case_impl(cx, |chars| to_uppercase(chars))
|
||||
switch_case_impl(cx, |chars| case_conversion::to_uppercase(chars))
|
||||
}
|
||||
|
||||
fn switch_to_alternate_case(cx: &mut Context) {
|
||||
switch_case_impl(cx, |chars| to_alternate_case(chars))
|
||||
switch_case_impl(cx, |chars| case_conversion::to_alternate_case(chars))
|
||||
}
|
||||
|
||||
fn switch_to_title_case(cx: &mut Context) {
|
||||
switch_case_impl(cx, |chars| to_title_case(chars))
|
||||
switch_case_impl(cx, |chars| case_conversion::to_title_case(chars))
|
||||
}
|
||||
|
||||
fn switch_to_sentence_case(cx: &mut Context) {
|
||||
switch_case_impl(cx, |chars| case_conversion::to_sentence_case(chars))
|
||||
}
|
||||
|
||||
fn switch_to_snake_case(cx: &mut Context) {
|
||||
switch_case_impl(cx, |chars| to_snake_case(chars))
|
||||
switch_case_impl(cx, |chars| case_conversion::to_snake_case(chars))
|
||||
}
|
||||
|
||||
fn switch_to_kebab_case(cx: &mut Context) {
|
||||
switch_case_impl(cx, |chars| to_kebab_case(chars))
|
||||
switch_case_impl(cx, |chars| case_conversion::to_kebab_case(chars))
|
||||
}
|
||||
|
||||
pub fn scroll(cx: &mut Context, offset: usize, direction: Direction, sync_cursor: bool) {
|
||||
|
|
|
@ -27,6 +27,7 @@ pub fn default() -> HashMap<Mode, KeyTrie> {
|
|||
"p" => switch_to_pascal_case,
|
||||
"c" => switch_to_camel_case,
|
||||
"t" => switch_to_title_case,
|
||||
"S" => switch_to_sentence_case,
|
||||
"s" => switch_to_snake_case,
|
||||
"k" => switch_to_kebab_case,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue