Added a -C/--center option to string pad.

The --center option does exactly what you'd expect. When a
perfectly centred result is not possible, this adds extra padding to
the left. If the --right option is also given, the extra padding is
added to the right.
This commit is contained in:
Isaac Oscar Gariano
2025-08-28 13:18:45 +10:00
parent c0c9245d99
commit 6149ac4e40
13 changed files with 88 additions and 16 deletions

View File

@@ -42,6 +42,7 @@ Deprecations and removed features
Scripting improvements
----------------------
- The ``psub`` command now allows combining ``--suffix`` with ``--fifo`` (:issue:`11729`).
- The ``string pad`` command now has a ``-C/--center`` option.
Interactive improvements
------------------------

View File

@@ -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.

View File

@@ -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 ...]

View File

@@ -40692,6 +40692,9 @@ msgstr ""
msgid "Pacman log actions"
msgstr ""
msgid "Pad both left and right"
msgstr ""
msgid "Pad right instead of left"
msgstr ""

View File

@@ -40688,6 +40688,9 @@ msgstr ""
msgid "Pacman log actions"
msgstr ""
msgid "Pad both left and right"
msgstr ""
msgid "Pad right instead of left"
msgstr ""

View File

@@ -40789,6 +40789,9 @@ msgstr ""
msgid "Pacman log actions"
msgstr ""
msgid "Pad both left and right"
msgstr ""
msgid "Pad right instead of left"
msgstr ""

View File

@@ -40684,6 +40684,9 @@ msgstr ""
msgid "Pacman log actions"
msgstr ""
msgid "Pad both left and right"
msgstr ""
msgid "Pad right instead of left"
msgstr ""

View File

@@ -40705,6 +40705,9 @@ msgstr ""
msgid "Pacman log actions"
msgstr ""
msgid "Pad both left and right"
msgstr ""
msgid "Pad right instead of left"
msgstr ""

View File

@@ -40687,6 +40687,9 @@ msgstr ""
msgid "Pacman log actions"
msgstr ""
msgid "Pad both left and right"
msgstr ""
msgid "Pad right instead of left"
msgstr ""

View File

@@ -40687,6 +40687,9 @@ msgstr "将本地仓库中已有的文物装入捆绑, 用于上传请求"
msgid "Pacman log actions"
msgstr "Pacman 日志动作"
msgid "Pad both left and right"
msgstr ""
msgid "Pad right instead of left"
msgstr "右侧而不是左侧"

View File

@@ -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

View File

@@ -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');
}

View File

@@ -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.