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_pascal_case` | Switch to PascalCase | normal: `` `p ``, select: `` `p `` |
|
||||||
| `switch_to_camel_case` | Switch to camelCase | normal: `` `c ``, select: `` `c `` |
|
| `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_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_snake_case` | Switch to snake_case | normal: `` `s ``, select: `` `s `` |
|
||||||
| `switch_to_kebab_case` | Switch to kebab-case | normal: `` `k ``, select: `` `k `` |
|
| `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> `` |
|
| `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` |
|
| `p` | Switch text to Pascal Case | `switch_to_pascal_case` |
|
||||||
| `c` | Switch text to camelCase | `switch_to_camel_case` |
|
| `c` | Switch text to camelCase | `switch_to_camel_case` |
|
||||||
| `t` | Switch text to Title Case | `switch_to_title_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` |
|
| `s` | Switch text to snake_case | `switch_to_snake_case` |
|
||||||
| `k` | Switch text to kebab-case | `switch_to_kebab_case` |
|
| `k` | Switch text to kebab-case | `switch_to_kebab_case` |
|
||||||
| `a` | Switch text to aLTERNATE cASE | `switch_to_alternate_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())
|
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>,
|
chars: impl Iterator<Item = char>,
|
||||||
buf: &mut Tendril,
|
buf: &mut Tendril,
|
||||||
capitalize_first: bool,
|
capitalize: CapitalizeWords,
|
||||||
separator: Option<char>,
|
separator: Option<char>,
|
||||||
) {
|
) {
|
||||||
let mut should_capitalize_current = capitalize_first;
|
let mut should_capitalize_current = capitalize != CapitalizeWords::AllButFirst;
|
||||||
let mut prev = None;
|
let mut prev = None;
|
||||||
|
|
||||||
let add_separator_if_needed = |prev: Option<char>, buf: &mut Tendril| {
|
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()) {
|
for current in chars.skip_while(|ch| ch.is_whitespace()) {
|
||||||
if !current.is_alphanumeric() {
|
if !current.is_alphanumeric() {
|
||||||
should_capitalize_current = true;
|
should_capitalize_current = capitalize != CapitalizeWords::First;
|
||||||
add_separator_if_needed(prev, buf);
|
add_separator_if_needed(prev, buf);
|
||||||
prev = Some(current);
|
prev = Some(current);
|
||||||
continue;
|
continue;
|
||||||
|
@ -38,7 +45,7 @@ pub fn smart_case_conversion(
|
||||||
|
|
||||||
if has_camel_transition(prev, current) {
|
if has_camel_transition(prev, current) {
|
||||||
add_separator_if_needed(prev, buf);
|
add_separator_if_needed(prev, buf);
|
||||||
should_capitalize_current = true;
|
should_capitalize_current = capitalize != CapitalizeWords::First;
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_capitalize_current {
|
if should_capitalize_current {
|
||||||
|
@ -54,7 +61,7 @@ pub fn smart_case_conversion(
|
||||||
*buf = buf.trim_end().into();
|
*buf = buf.trim_end().into();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn separator_case_conversion(
|
fn separator_case_conversion(
|
||||||
chars: impl Iterator<Item = char>,
|
chars: impl Iterator<Item = char>,
|
||||||
buf: &mut Tendril,
|
buf: &mut Tendril,
|
||||||
separator: char,
|
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) {
|
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) {
|
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) {
|
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`
|
/// 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_title_case => to_title_case
|
||||||
into_kebab_case => to_kebab_case
|
into_kebab_case => to_kebab_case
|
||||||
into_snake_case => to_snake_case
|
into_snake_case => to_snake_case
|
||||||
|
into_sentence_case => to_sentence_case
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -296,6 +308,7 @@ mod tests {
|
||||||
fn test_title_case_conversion() {
|
fn test_title_case_conversion() {
|
||||||
let tests = [
|
let tests = [
|
||||||
("hello world", "Hello World"),
|
("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"),
|
||||||
|
@ -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]
|
#[test]
|
||||||
fn test_kebab_case_conversion() {
|
fn test_kebab_case_conversion() {
|
||||||
let tests = [
|
let tests = [
|
||||||
|
|
|
@ -18,11 +18,7 @@ use tui::{
|
||||||
pub use typed::*;
|
pub use typed::*;
|
||||||
|
|
||||||
use helix_core::{
|
use helix_core::{
|
||||||
case_conversion::{
|
case_conversion, char_idx_at_visual_offset,
|
||||||
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,
|
|
||||||
chars::char_is_word,
|
chars::char_is_word,
|
||||||
command_line, comment,
|
command_line, comment,
|
||||||
doc_formatter::TextFormat,
|
doc_formatter::TextFormat,
|
||||||
|
@ -361,6 +357,7 @@ impl MappableCommand {
|
||||||
switch_to_pascal_case, "Switch to PascalCase",
|
switch_to_pascal_case, "Switch to PascalCase",
|
||||||
switch_to_camel_case, "Switch to camelCase",
|
switch_to_camel_case, "Switch to camelCase",
|
||||||
switch_to_title_case, "Switch to Title Case",
|
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_snake_case, "Switch to snake_case",
|
||||||
switch_to_kebab_case, "Switch to kebab-case",
|
switch_to_kebab_case, "Switch to kebab-case",
|
||||||
page_up, "Move page up",
|
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)
|
fn switch_case_impl<F>(cx: &mut Context, change_fn: F)
|
||||||
where
|
where
|
||||||
F: for<'a> Fn(&mut (dyn Iterator<Item = char> + 'a)) -> Tendril,
|
F: for<'a> Fn(&mut (dyn Iterator<Item = char> + 'a)) -> Tendril,
|
||||||
|
@ -1739,35 +1737,39 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn switch_to_pascal_case(cx: &mut Context) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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,
|
"p" => switch_to_pascal_case,
|
||||||
"c" => switch_to_camel_case,
|
"c" => switch_to_camel_case,
|
||||||
"t" => switch_to_title_case,
|
"t" => switch_to_title_case,
|
||||||
|
"S" => switch_to_sentence_case,
|
||||||
"s" => switch_to_snake_case,
|
"s" => switch_to_snake_case,
|
||||||
"k" => switch_to_kebab_case,
|
"k" => switch_to_kebab_case,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue