diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1741cf180..4f7cac7e7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -52,6 +52,7 @@ Scripting improvements - ``fish_opt`` no longer requires you give a short flag name when defining options, provided you give it a long flag name with more than one character. - ``argparse`` option specifiers for long only options can now start with ``/``, allowing the definition of long options with a single letter (withouht the ``/``, an option with a single letter is always interpreted as a short flag). Due to this change, the ``--long-only`` option to ``fish_opt`` is now no longer necessary and is deprecated. - ``fish_opt`` now has a ``-v`` / ``--validate`` option you can use to give a fish script to validate values of the option. +- The ``string pad`` command now has a ``-C/--center`` option. Interactive improvements ------------------------ diff --git a/doc_src/cmds/string-pad.rst b/doc_src/cmds/string-pad.rst index 5a255d487..66bab0641 100644 --- a/doc_src/cmds/string-pad.rst +++ b/doc_src/cmds/string-pad.rst @@ -8,7 +8,7 @@ Synopsis .. synopsis:: - string pad [-r | --right] [(-c | --char) CHAR] [(-w | --width) INTEGER] + string pad [-r | --right] [-C | --center] [(-c | --char) CHAR] [(-w | --width) INTEGER] [STRING ...] .. END SYNOPSIS @@ -22,6 +22,8 @@ Description The escape sequences reflect what fish knows about, and how it computes its output. Your terminal might support more escapes, or not support escape sequences that fish knows about. +If **-C** or **--center** is given, add the padding to before and after the string. If it is impossible to perfectly center the result (because the required amount of padding is an odd number), extra padding will be added to the left, unless **--right** is also given. + If **-r** or **--right** is given, add the padding after a string. If **-c** or **--char** is given, pad with *CHAR* instead of whitespace. diff --git a/doc_src/cmds/string.rst b/doc_src/cmds/string.rst index f53e6725f..653029965 100644 --- a/doc_src/cmds/string.rst +++ b/doc_src/cmds/string.rst @@ -18,7 +18,7 @@ Synopsis [-g | --groups-only] [-r | --regex] [-n | --index] [-q | --quiet] [-v | --invert] PATTERN [STRING ...] - string pad [-r | --right] [(-c | --char) CHAR] [(-w | --width) INTEGER] + string pad [-r | --right] [-C | --center] [(-c | --char) CHAR] [(-w | --width) INTEGER] [STRING ...] string repeat [(-n | --count) COUNT] [(-m | --max) MAX] [-N | --no-newline] [-q | --quiet] [STRING ...] diff --git a/po/de.po b/po/de.po index f292f4baa..8e6e9bbb7 100644 --- a/po/de.po +++ b/po/de.po @@ -40723,6 +40723,9 @@ msgstr "" msgid "Pacman log actions" msgstr "" +msgid "Pad both left and right" +msgstr "" + msgid "Pad right instead of left" msgstr "" diff --git a/po/en.po b/po/en.po index 1d0fe74df..32d70b3ba 100644 --- a/po/en.po +++ b/po/en.po @@ -40719,6 +40719,9 @@ msgstr "" msgid "Pacman log actions" msgstr "" +msgid "Pad both left and right" +msgstr "" + msgid "Pad right instead of left" msgstr "" diff --git a/po/fr.po b/po/fr.po index 1da521b76..62d71889e 100644 --- a/po/fr.po +++ b/po/fr.po @@ -40820,6 +40820,9 @@ msgstr "" msgid "Pacman log actions" msgstr "" +msgid "Pad both left and right" +msgstr "" + msgid "Pad right instead of left" msgstr "" diff --git a/po/pl.po b/po/pl.po index 1b2188634..e26e3af1f 100644 --- a/po/pl.po +++ b/po/pl.po @@ -40715,6 +40715,9 @@ msgstr "" msgid "Pacman log actions" msgstr "" +msgid "Pad both left and right" +msgstr "" + msgid "Pad right instead of left" msgstr "" diff --git a/po/pt_BR.po b/po/pt_BR.po index 5c4241f93..168ac5374 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -40736,6 +40736,9 @@ msgstr "" msgid "Pacman log actions" msgstr "" +msgid "Pad both left and right" +msgstr "" + msgid "Pad right instead of left" msgstr "" diff --git a/po/sv.po b/po/sv.po index 3d2f0d09b..66facbbf7 100644 --- a/po/sv.po +++ b/po/sv.po @@ -40718,6 +40718,9 @@ msgstr "" msgid "Pacman log actions" msgstr "" +msgid "Pad both left and right" +msgstr "" + msgid "Pad right instead of left" msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index e0a371558..22c510e9d 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -40718,6 +40718,9 @@ msgstr "将本地仓库中已有的文物装入捆绑, 用于上传请求" msgid "Pacman log actions" msgstr "Pacman 日志动作" +msgid "Pad both left and right" +msgstr "" + msgid "Pad right instead of left" msgstr "右侧而不是左侧" diff --git a/share/completions/string.fish b/share/completions/string.fish index b4a5c366d..b36f6d97a 100644 --- a/share/completions/string.fish +++ b/share/completions/string.fish @@ -54,6 +54,7 @@ complete -x -c string -n "test (count (commandline -xpc)) -ge 2" -n "contains -- complete -f -c string -n "test (count (commandline -xpc)) -ge 2" -n "contains -- (commandline -xpc)[2] repeat" -s N -l no-newline -d "Remove newline" complete -f -c string -n "test (count (commandline -xpc)) -lt 2" -a pad complete -x -c string -n "test (count (commandline -xpc)) -ge 2" -n "contains -- (commandline -xpc)[2] pad" -s r -l right -d "Pad right instead of left" +complete -x -c string -n "test (count (commandline -xpc)) -ge 2" -n "contains -- (commandline -xpc)[2] pad" -s r -l center -d "Pad both left and right" complete -x -c string -n "test (count (commandline -xpc)) -ge 2" -n "contains -- (commandline -xpc)[2] pad" -s c -l char -x -d "Character to use for padding" complete -x -c string -n "test (count (commandline -xpc)) -ge 2" -n "contains -- (commandline -xpc)[2] pad" -s w -l width -x -d "Integer width of the result, default is maximum width of inputs" complete -f -c string -n "test (count (commandline -xpc)) -lt 2" -a shorten diff --git a/src/builtins/string/pad.rs b/src/builtins/string/pad.rs index 1cb2ec1ac..a2713ff89 100644 --- a/src/builtins/string/pad.rs +++ b/src/builtins/string/pad.rs @@ -5,6 +5,7 @@ pub struct Pad { char_to_pad: char, pad_char_width: usize, pad_from: Direction, + center: bool, width: usize, } @@ -14,6 +15,7 @@ fn default() -> Self { char_to_pad: ' ', pad_char_width: 1, pad_from: Direction::Left, + center: false, width: 0, } } @@ -24,9 +26,10 @@ impl StringSubCommand<'_> for Pad { // FIXME docs say `--char`, there was no long_opt with `--char` in C++ wopt(L!("chars"), RequiredArgument, 'c'), wopt(L!("right"), NoArgument, 'r'), + wopt(L!("center"), NoArgument, 'C'), wopt(L!("width"), RequiredArgument, 'w'), ]; - const SHORT_OPTIONS: &'static wstr = L!("c:rw:"); + const SHORT_OPTIONS: &'static wstr = L!("c:rCw:"); fn parse_opt(&mut self, name: &wstr, c: char, arg: Option<&wstr>) -> Result<(), StringError> { match c { @@ -55,6 +58,7 @@ fn parse_opt(&mut self, name: &wstr, c: char, arg: Option<&wstr>) -> Result<(), .try_into() .map_err(|_| invalid_args!("%ls: Invalid width value '%ls'\n", name, arg))? } + 'C' => self.center = true, _ => return Err(StringError::UnknownOption), } return Ok(()); @@ -83,21 +87,22 @@ fn handle<'args>( for (input, width) in inputs { use std::iter::repeat; - let pad = (pad_width - width) / self.pad_char_width; - let remaining_width = (pad_width - width) % self.pad_char_width; - let mut padded: WString = match self.pad_from { - Direction::Left => repeat(self.char_to_pad) - .take(pad) - .chain(repeat(' ').take(remaining_width)) - .chain(input.chars()) - .collect(), - Direction::Right => input - .chars() - .chain(repeat(' ').take(remaining_width)) - .chain(repeat(self.char_to_pad).take(pad)) - .collect(), + let total_pad = pad_width - width; + let (left_pad, right_pad) = match (self.pad_from, self.center) { + (Direction::Left, false) => (total_pad, 0), + (Direction::Right, false) => (0, total_pad), + (Direction::Left, true) => (total_pad - total_pad / 2, total_pad / 2), + (Direction::Right, true) => (total_pad / 2, total_pad - total_pad / 2), }; + let chars = |w| repeat(self.char_to_pad).take(w / self.pad_char_width); + let spaces = |w| repeat(' ').take(w % self.pad_char_width); + let mut padded: WString = chars(left_pad) + .chain(spaces(left_pad)) + .chain(input.chars()) + .chain(spaces(right_pad)) + .chain(chars(right_pad)) + .collect(); if print_trailing_newline { padded.push('\n'); } diff --git a/tests/checks/string.fish b/tests/checks/string.fish index c64ab789b..e7bc81ad7 100644 --- a/tests/checks/string.fish +++ b/tests/checks/string.fish @@ -43,10 +43,14 @@ string length -q ""; and echo not zero length; or echo zero length # CHECK: zero length string pad foo +#CHECK: foo +string pad -C foo # CHECK: foo string pad -r -w 7 --chars - foo # CHECK: foo---- +string pad -r -w 7 --chars - --center foo +# CHECK: --foo-- # might overflow when converting sign string sub --start -9223372036854775808 abc @@ -54,24 +58,48 @@ string sub --start -9223372036854775808 abc string pad --width 7 -c '=' foo # CHECK: ====foo +string pad --width 7 -c '=' -C foo +# CHECK: ==foo== +string pad --width 8 -c '=' -C foo +# CHECK: ===foo== +string pad --width 8 -c '=' -Cr foo +# CHECK: ==foo=== echo \|(string pad --width 10 --right foo)\| # CHECK: |foo | +echo \|(string pad --width 10 --right --center foo)\| +# CHECK: | foo | +echo \|(string pad --width 10 --center foo)\| +# CHECK: | foo | begin set -l fish_emoji_width 2 # Pad string with multi-width emoji. string pad -w 4 -c . 🐟 # CHECK: ..🐟 + string pad -w 4 -c . -C 🐟 + # CHECK: .🐟. # Pad with multi-width character. string pad -w 3 -c 🐟 . # CHECK: 🐟. + # string pad would rather the result actually be centerd, than it actually contain + # the padding character (so since it can't print half a 🐟, it instead prints a space which is half as wide) + string collect \|(string pad -w 3 -c 🐟 -C .)\| + # CHECK: | . | + string collect \|(string pad -w 7 -c 🐟 -C .)\| + # CHECK: |🐟 . 🐟| # Multi-width pad with remainder, complemented with a space. string pad -w 4 -c 🐟 . .. # CHECK: 🐟 . # CHECK: 🐟.. + string collect \|(string pad -w 7 -c 🐟 -C . ..)\| + # CHECK: |🐟 . 🐟| + # CHECK: |🐟 ..🐟| + string collect \|(string pad -w 7 -c 🐟 -Cr . ..)\| + # CHECK: |🐟 . 🐟| + # CHECK: |🐟.. 🐟| end # Pad to the maximum length. @@ -79,12 +107,26 @@ string pad -c . long longer longest # CHECK: ...long # CHECK: .longer # CHECK: longest +string pad -c . -C long longer longest +# CHECK: ..long. +# CHECK: .longer +# CHECK: longest +string pad -c . -Cr long longer longest +# CHECK: .long.. +# CHECK: longer. +# CHECK: longest # This tests current behavior where the max width of an argument overrules # the width parameter. This could be changed if needed. string pad -c_ --width 5 longer-than-width-param x # CHECK: longer-than-width-param # CHECK: ______________________x +string pad -c_ --width 5 --center longer-than-width-param x +# CHECK: longer-than-width-param +# CHECK: ___________x___________ +string pad -c_ --width 5 --center --right longer-than-width-param x +# CHECK: longer-than-width-param +# CHECK: ___________x___________ # Current behavior is that only a single padding character is supported. # We can support longer strings in future without breaking compatibility.