2019-06-25 23:21:11 +08:00
|
|
|
#RUN: %fish %s
|
|
|
|
# Tests for string builtin. Mostly taken from man page examples.
|
|
|
|
|
|
|
|
string match -r -v "c.*" dog can cat diz; and echo "exit 0"
|
|
|
|
# CHECK: dog
|
|
|
|
# CHECK: diz
|
|
|
|
# CHECK: exit 0
|
|
|
|
|
|
|
|
string match -q -r -v "c.*" dog can cat diz; and echo "exit 0"
|
|
|
|
# CHECK: exit 0
|
|
|
|
|
|
|
|
string match -v "c*" dog can cat diz; and echo "exit 0"
|
|
|
|
# CHECK: dog
|
|
|
|
# CHECK: diz
|
|
|
|
# CHECK: exit 0
|
|
|
|
|
|
|
|
string match -q -v "c*" dog can cat diz; and echo "exit 0"
|
|
|
|
# CHECK: exit 0
|
|
|
|
|
|
|
|
string match -v "d*" dog dan dat diz; or echo "exit 1"
|
|
|
|
# CHECK: exit 1
|
|
|
|
|
|
|
|
string match -q -v "d*" dog dan dat diz; or echo "exit 1"
|
|
|
|
# CHECK: exit 1
|
|
|
|
|
|
|
|
string match -r -v x y; and echo "exit 0"
|
|
|
|
# CHECK: y
|
|
|
|
# CHECK: exit 0
|
|
|
|
|
|
|
|
string match -r -v x x; or echo "exit 1"
|
|
|
|
# CHECK: exit 1
|
|
|
|
|
|
|
|
string match -q -r -v x y; and echo "exit 0"
|
|
|
|
# CHECK: exit 0
|
|
|
|
|
|
|
|
string match -q -r -v x x; or echo "exit 1"
|
|
|
|
# CHECK: exit 1
|
|
|
|
|
|
|
|
string length "hello, world"
|
|
|
|
# CHECK: 12
|
|
|
|
|
|
|
|
string length -q ""; and echo not zero length; or echo zero length
|
|
|
|
# CHECK: zero length
|
|
|
|
|
2020-09-28 01:12:42 +08:00
|
|
|
string pad foo
|
|
|
|
# CHECK: foo
|
|
|
|
|
2023-06-20 10:28:35 +08:00
|
|
|
string pad -r -w 7 --chars - foo
|
2020-09-28 01:12:42 +08:00
|
|
|
# CHECK: foo----
|
|
|
|
|
2023-06-20 10:28:35 +08:00
|
|
|
# might overflow when converting sign
|
|
|
|
string sub --start -9223372036854775808 abc
|
|
|
|
# CHECK: abc
|
|
|
|
|
2020-09-28 01:12:42 +08:00
|
|
|
string pad --width 7 -c '=' foo
|
|
|
|
# CHECK: ====foo
|
|
|
|
|
|
|
|
echo \|(string pad --width 10 --right foo)\|
|
|
|
|
# CHECK: |foo |
|
|
|
|
|
2020-09-28 23:53:27 +08:00
|
|
|
begin
|
|
|
|
set -l fish_emoji_width 2
|
|
|
|
# Pad string with multi-width emoji.
|
|
|
|
string pad -w 4 -c . 🐟
|
|
|
|
# CHECK: ..🐟
|
|
|
|
|
|
|
|
# Pad with multi-width character.
|
|
|
|
string pad -w 3 -c 🐟 .
|
|
|
|
# CHECK: 🐟.
|
|
|
|
|
|
|
|
# Multi-width pad with remainder, complemented with a space.
|
|
|
|
string pad -w 4 -c 🐟 . ..
|
|
|
|
# CHECK: 🐟 .
|
|
|
|
# CHECK: 🐟..
|
|
|
|
end
|
2020-09-28 03:51:20 +08:00
|
|
|
|
|
|
|
# Pad to the maximum length.
|
2020-09-28 01:12:42 +08:00
|
|
|
string pad -c . long longer longest
|
|
|
|
# CHECK: ...long
|
|
|
|
# CHECK: .longer
|
|
|
|
# CHECK: longest
|
|
|
|
|
2020-09-28 03:51:20 +08:00
|
|
|
# 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
|
|
|
|
|
|
|
|
# Current behavior is that only a single padding character is supported.
|
|
|
|
# We can support longer strings in future without breaking compatibilty.
|
|
|
|
string pad -c ab -w4 .
|
|
|
|
# CHECKERR: string pad: Padding should be a character 'ab'
|
|
|
|
|
2023-07-13 10:17:19 +08:00
|
|
|
# nonprintable characters does not make sense
|
|
|
|
string pad -c \u07 .
|
|
|
|
# CHECKERR: string pad: Invalid padding character of width zero {{'\a'}}
|
|
|
|
|
Let visible length work with CR and LF
Because we are, ultimately, interested in how many cells a string
occupies, we *have* to handle carriage return (`\r`) and line
feed (`\n`).
A carriage return sets the current tally to 0, and only the longest
tally is kept. The idea here is that the last position is the same as
the last position of the longest string. So:
abcdef\r123
ends up looking like
123def
which is the same width as abcdef, 6.
A line feed meanwhile means we flush the current tally and start a new
one. Every line is printed separately, even if it's given as one.
That's because, well, counting the width over multiple lines
doesn't *help*.
As a sidenote: This is necessarily imperfect, because, while we may
know the width of the terminal ($COLUMNS), we don't know the current
cursor position. So we can only give the width, and the user can then
figure something out on their own.
But for the common case of figuring out how wide the prompt is, this
should do.
2021-07-30 02:49:14 +08:00
|
|
|
# Visible length. Let's start off simple, colors are ignored:
|
|
|
|
string length --visible (set_color red)abc
|
|
|
|
# CHECK: 3
|
|
|
|
begin
|
|
|
|
set -l fish_emoji_width 2
|
|
|
|
# This should print the emoji width
|
2022-02-15 05:31:30 +08:00
|
|
|
string length --visible . \U2693
|
Let visible length work with CR and LF
Because we are, ultimately, interested in how many cells a string
occupies, we *have* to handle carriage return (`\r`) and line
feed (`\n`).
A carriage return sets the current tally to 0, and only the longest
tally is kept. The idea here is that the last position is the same as
the last position of the longest string. So:
abcdef\r123
ends up looking like
123def
which is the same width as abcdef, 6.
A line feed meanwhile means we flush the current tally and start a new
one. Every line is printed separately, even if it's given as one.
That's because, well, counting the width over multiple lines
doesn't *help*.
As a sidenote: This is necessarily imperfect, because, while we may
know the width of the terminal ($COLUMNS), we don't know the current
cursor position. So we can only give the width, and the user can then
figure something out on their own.
But for the common case of figuring out how wide the prompt is, this
should do.
2021-07-30 02:49:14 +08:00
|
|
|
# CHECK: 1
|
|
|
|
# CHECK: 2
|
|
|
|
set -l fish_emoji_width 1
|
2022-02-15 05:31:30 +08:00
|
|
|
string length --visible . \U2693
|
Let visible length work with CR and LF
Because we are, ultimately, interested in how many cells a string
occupies, we *have* to handle carriage return (`\r`) and line
feed (`\n`).
A carriage return sets the current tally to 0, and only the longest
tally is kept. The idea here is that the last position is the same as
the last position of the longest string. So:
abcdef\r123
ends up looking like
123def
which is the same width as abcdef, 6.
A line feed meanwhile means we flush the current tally and start a new
one. Every line is printed separately, even if it's given as one.
That's because, well, counting the width over multiple lines
doesn't *help*.
As a sidenote: This is necessarily imperfect, because, while we may
know the width of the terminal ($COLUMNS), we don't know the current
cursor position. So we can only give the width, and the user can then
figure something out on their own.
But for the common case of figuring out how wide the prompt is, this
should do.
2021-07-30 02:49:14 +08:00
|
|
|
# CHECK: 1
|
|
|
|
# CHECK: 1
|
|
|
|
end
|
|
|
|
|
|
|
|
# Only the longest run between carriage returns is kept because the rest is overwritten.
|
|
|
|
string length --visible (set_color normal)abcdef\rfooba(set_color red)raaa
|
|
|
|
# (foobaraaa)
|
|
|
|
# CHECK: 9
|
|
|
|
|
|
|
|
# Visible length is *always* split by line
|
|
|
|
string length --visible a(set_color blue)b\ncde
|
|
|
|
# CHECK: 2
|
|
|
|
# CHECK: 3
|
|
|
|
|
2021-09-23 18:57:44 +08:00
|
|
|
# Backslashes and visible length:
|
|
|
|
# It can't move us before the start of the line.
|
|
|
|
string length --visible \b
|
|
|
|
# CHECK: 0
|
|
|
|
|
|
|
|
# It can't move us before the start of the line.
|
|
|
|
string length --visible \bf
|
|
|
|
# CHECK: 1
|
|
|
|
|
|
|
|
# But it does erase chars before.
|
|
|
|
string length --visible \bf\b
|
|
|
|
# CHECK: 0
|
|
|
|
|
|
|
|
# Never move past 0.
|
|
|
|
string length --visible \bf\b\b\b\b\b
|
|
|
|
# CHECK: 0
|
|
|
|
|
2019-06-25 23:21:11 +08:00
|
|
|
string sub --length 2 abcde
|
|
|
|
# CHECK: ab
|
|
|
|
|
|
|
|
string sub -s 2 -l 2 abcde
|
|
|
|
# CHECK: bc
|
|
|
|
|
|
|
|
string sub --start=-2 abcde
|
|
|
|
# CHECK: de
|
|
|
|
|
2020-03-22 22:53:09 +08:00
|
|
|
string sub --end=3 abcde
|
|
|
|
# CHECK: abc
|
|
|
|
|
|
|
|
string sub --end=-4 abcde
|
|
|
|
# CHECK: a
|
|
|
|
|
|
|
|
string sub --start=2 --end=-2 abcde
|
|
|
|
# CHECK: bc
|
|
|
|
|
|
|
|
string sub -s -5 -e -2 abcdefgh
|
|
|
|
# CHECK: def
|
|
|
|
|
|
|
|
string sub -s -100 -e -2 abcde
|
|
|
|
# CHECK: abc
|
|
|
|
|
|
|
|
string sub -s -5 -e 2 abcde
|
|
|
|
# CHECK: ab
|
|
|
|
|
|
|
|
string sub -s -50 -e -100 abcde
|
|
|
|
# CHECK:
|
|
|
|
|
|
|
|
string sub -s 2 -e -5 abcde
|
|
|
|
# CHECK:
|
|
|
|
|
2019-06-25 23:21:11 +08:00
|
|
|
string split . example.com
|
|
|
|
# CHECK: example
|
|
|
|
# CHECK: com
|
|
|
|
|
|
|
|
string split -r -m1 / /usr/local/bin/fish
|
|
|
|
# CHECK: /usr/local/bin
|
|
|
|
# CHECK: fish
|
|
|
|
|
|
|
|
string split "" abc
|
|
|
|
# CHECK: a
|
|
|
|
# CHECK: b
|
|
|
|
# CHECK: c
|
|
|
|
|
2023-06-20 10:28:35 +08:00
|
|
|
string split --max 1 --right 12 "AB12CD"
|
|
|
|
# CHECK: AB
|
|
|
|
# CHECK: CD
|
|
|
|
|
2020-03-21 00:31:23 +08:00
|
|
|
string split --fields=2 "" abc
|
|
|
|
# CHECK: b
|
|
|
|
|
2020-03-22 00:30:00 +08:00
|
|
|
string split --fields=3,2 "" abc
|
2020-03-21 00:31:23 +08:00
|
|
|
# CHECK: c
|
2020-03-22 00:30:00 +08:00
|
|
|
# CHECK: b
|
2020-03-21 00:31:23 +08:00
|
|
|
|
2020-03-24 22:25:37 +08:00
|
|
|
string split --fields=2,9 "" abc; or echo "exit 1"
|
|
|
|
# CHECK: exit 1
|
2020-03-21 00:31:23 +08:00
|
|
|
|
2023-06-20 10:28:35 +08:00
|
|
|
string split --fields=2-3-,9 "" a
|
|
|
|
# CHECKERR: string split: 2-3-,9: invalid integer
|
|
|
|
|
|
|
|
string split --fields=1-99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 "" abc
|
|
|
|
# CHECKERR: string split: 1-99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999: invalid integer
|
|
|
|
|
|
|
|
string split --fields=99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999-1 "" abc
|
|
|
|
# CHECKERR: string split: 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999-1: invalid integer
|
|
|
|
|
|
|
|
string split --fields=1--2 "" b
|
|
|
|
# CHECKERR: string split: 1--2: invalid integer
|
|
|
|
|
|
|
|
string split --fields=0 "" c
|
|
|
|
# CHECKERR: string split: Invalid fields value '0'
|
|
|
|
|
|
|
|
string split --fields=99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 "" abc
|
|
|
|
# CHECKERR: string split: 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999: invalid integer
|
|
|
|
|
|
|
|
string split --fields=1-0 "" d
|
|
|
|
# CHECKERR: string split: Invalid range value for field '1-0'
|
|
|
|
|
|
|
|
string split --fields=0-1 "" e
|
|
|
|
# CHECKERR: string split: Invalid range value for field '0-1'
|
|
|
|
|
|
|
|
string split --fields=-1 "" f
|
|
|
|
# CHECKERR: string split: -1: invalid integer
|
|
|
|
|
|
|
|
string split --fields=1a "" g
|
|
|
|
# CHECKERR: string split: 1a: invalid integer
|
|
|
|
|
|
|
|
string split --fields=a "" h
|
|
|
|
# CHECKERR: string split: a: invalid integer
|
|
|
|
|
2020-03-22 00:30:00 +08:00
|
|
|
string split --fields=1-3,5,9-7 "" 123456789
|
|
|
|
# CHECK: 1
|
|
|
|
# CHECK: 2
|
|
|
|
# CHECK: 3
|
|
|
|
# CHECK: 5
|
|
|
|
# CHECK: 9
|
|
|
|
# CHECK: 8
|
|
|
|
# CHECK: 7
|
|
|
|
|
2020-04-18 12:03:54 +08:00
|
|
|
string split -f1 ' ' 'a b' 'c d'
|
|
|
|
# CHECK: a
|
|
|
|
# CHECK: c
|
|
|
|
|
2020-04-18 14:25:08 +08:00
|
|
|
string split --allow-empty --fields=2,9 "" abc
|
|
|
|
# CHECK: b
|
|
|
|
|
2019-06-25 23:21:11 +08:00
|
|
|
seq 3 | string join ...
|
|
|
|
# CHECK: 1...2...3
|
|
|
|
|
|
|
|
string trim " abc "
|
|
|
|
# CHECK: abc
|
|
|
|
|
|
|
|
string trim --right --chars=yz xyzzy zany
|
|
|
|
# CHECK: x
|
|
|
|
# CHECK: zan
|
|
|
|
|
|
|
|
echo \x07 | string escape
|
|
|
|
# CHECK: \cg
|
|
|
|
|
|
|
|
string escape --style=script 'a b#c"\'d'
|
|
|
|
# CHECK: a\ b\#c\"\'d
|
|
|
|
|
|
|
|
string escape --style=url 'a b#c"\'d'
|
|
|
|
# CHECK: a%20b%23c%22%27d
|
|
|
|
|
|
|
|
string escape --style=url \na\nb%c~d\n
|
|
|
|
# CHECK: %0Aa%0Ab%25c~d%0A
|
|
|
|
|
|
|
|
string escape --style=var 'a b#c"\'d'
|
|
|
|
# CHECK: a_20_b_23_c_22_27_d
|
|
|
|
|
|
|
|
string escape --style=var a\nghi_
|
|
|
|
# CHECK: a_0A_ghi__
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string escape --style=var abc
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: abc
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string escape --style=var _a_b_c_
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: __a__b__c__
|
|
|
|
|
|
|
|
string escape --style=var -- -
|
|
|
|
# CHECK: _2D_
|
|
|
|
|
|
|
|
# string escape with multibyte chars
|
|
|
|
string escape --style=url aöb
|
|
|
|
string escape --style=url 中
|
|
|
|
string escape --style=url aöb | string unescape --style=url
|
|
|
|
string escape --style=url 中 | string unescape --style=url
|
|
|
|
|
|
|
|
string escape --style=var aöb
|
|
|
|
string escape --style=var 中
|
|
|
|
string escape --style=var aöb | string unescape --style=var
|
|
|
|
string escape --style=var 中 | string unescape --style=var
|
|
|
|
# CHECK: a%C3%B6b
|
|
|
|
# CHECK: %E4%B8%AD
|
|
|
|
# CHECK: aöb
|
|
|
|
# CHECK: 中
|
|
|
|
# CHECK: a_C3_B6_b
|
|
|
|
# CHECK: _E4_B8_AD_
|
|
|
|
# CHECK: aöb
|
|
|
|
# CHECK: 中
|
|
|
|
|
|
|
|
# test regex escaping
|
|
|
|
string escape --style=regex ".ext"
|
|
|
|
string escape --style=regex "bonjour, amigo"
|
|
|
|
string escape --style=regex "^this is a literal string"
|
|
|
|
# CHECK: \.ext
|
|
|
|
# CHECK: bonjour, amigo
|
|
|
|
# CHECK: \^this is a literal string
|
|
|
|
|
|
|
|
### Verify that we can correctly unescape the same strings
|
|
|
|
# we tested escaping above.
|
|
|
|
set x (string unescape (echo \x07 | string escape))
|
|
|
|
test $x = \x07
|
|
|
|
and echo success
|
|
|
|
# CHECK: success
|
|
|
|
|
|
|
|
string unescape --style=script (string escape --style=script 'a b#c"\'d')
|
|
|
|
# CHECK: a b#c"'d
|
|
|
|
|
|
|
|
string unescape --style=url (string escape --style=url 'a b#c"\'d')
|
|
|
|
# CHECK: a b#c"'d
|
|
|
|
|
|
|
|
string unescape --style=url (string escape --style=url \na\nb%c~d\n)
|
2020-09-28 01:12:42 +08:00
|
|
|
# CHECK:
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: a
|
|
|
|
# CHECK: b%c~d
|
|
|
|
|
|
|
|
string unescape --style=var (string escape --style=var 'a b#c"\'d')
|
|
|
|
# CHECK: a b#c"'d
|
|
|
|
|
|
|
|
string unescape --style=var (string escape --style=var a\nghi_)
|
|
|
|
# CHECK: a
|
|
|
|
# CHECK: ghi_
|
|
|
|
|
|
|
|
string unescape --style=var (string escape --style=var 'abc')
|
|
|
|
# CHECK: abc
|
|
|
|
|
|
|
|
string unescape --style=var (string escape --style=var '_a_b_c_')
|
|
|
|
# CHECK: _a_b_c_
|
|
|
|
|
|
|
|
string unescape --style=var -- (string escape --style=var -- -)
|
|
|
|
# CHECK: -
|
|
|
|
|
|
|
|
### Verify that we can correctly match strings.
|
|
|
|
string match "*" a
|
|
|
|
# CHECK: a
|
|
|
|
|
|
|
|
string match "a*b" axxb
|
|
|
|
# CHECK: axxb
|
|
|
|
|
|
|
|
string match -i "a**B" Axxb
|
|
|
|
# CHECK: Axxb
|
|
|
|
|
|
|
|
echo "ok?" | string match "*?"
|
|
|
|
# CHECK: ok?
|
|
|
|
|
|
|
|
string match -r "cat|dog|fish" "nice dog"
|
|
|
|
# CHECK: dog
|
|
|
|
|
|
|
|
string match -r "(\d\d?):(\d\d):(\d\d)" 2:34:56
|
|
|
|
# CHECK: 2:34:56
|
|
|
|
# CHECK: 2
|
|
|
|
# CHECK: 34
|
|
|
|
# CHECK: 56
|
|
|
|
|
|
|
|
string match -r "^(\w{2,4})\g1\$" papa mud murmur
|
|
|
|
# CHECK: papa
|
|
|
|
# CHECK: pa
|
|
|
|
# CHECK: murmur
|
|
|
|
# CHECK: mur
|
|
|
|
|
|
|
|
string match -r -a -n at ratatat
|
|
|
|
# CHECK: 2 2
|
|
|
|
# CHECK: 4 2
|
|
|
|
# CHECK: 6 2
|
|
|
|
|
|
|
|
string match -r -i "0x[0-9a-f]{1,8}" "int magic = 0xBadC0de;"
|
|
|
|
# CHECK: 0xBadC0de
|
|
|
|
|
|
|
|
string replace is was "blue is my favorite"
|
|
|
|
# CHECK: blue was my favorite
|
|
|
|
|
|
|
|
string replace 3rd last 1st 2nd 3rd
|
|
|
|
# CHECK: 1st
|
|
|
|
# CHECK: 2nd
|
|
|
|
# CHECK: last
|
|
|
|
|
|
|
|
string replace -a " " _ "spaces to underscores"
|
|
|
|
# CHECK: spaces_to_underscores
|
|
|
|
|
|
|
|
string replace -r -a "[^\d.]+" " " "0 one two 3.14 four 5x"
|
2020-09-28 01:12:42 +08:00
|
|
|
# CHECK: 0 3.14 5
|
2019-06-25 23:21:11 +08:00
|
|
|
|
|
|
|
string replace -r "(\w+)\s+(\w+)" "\$2 \$1 \$\$" "left right"
|
|
|
|
# CHECK: right left $
|
|
|
|
|
|
|
|
string replace -r "\s*newline\s*" "\n" "put a newline here"
|
|
|
|
# CHECK: put a
|
|
|
|
# CHECK: here
|
|
|
|
|
|
|
|
string replace -r -a "(\w)" "\$1\$1" ab
|
|
|
|
# CHECK: aabb
|
|
|
|
|
2023-06-20 10:28:35 +08:00
|
|
|
echo a | string replace b c -q
|
|
|
|
or echo No replace fails
|
|
|
|
# CHECK: No replace fails
|
|
|
|
|
|
|
|
echo a | string replace -r b c -q
|
|
|
|
or echo No replace regex fails
|
|
|
|
# CHECK: No replace regex fails
|
|
|
|
|
2019-06-25 23:21:11 +08:00
|
|
|
string replace --filter x X abc axc x def jkx
|
|
|
|
or echo Unexpected exit status at line (status --current-line-number)
|
|
|
|
# CHECK: aXc
|
|
|
|
# CHECK: X
|
|
|
|
# CHECK: jkX
|
|
|
|
|
|
|
|
string replace --filter y Y abc axc x def jkx
|
|
|
|
and echo Unexpected exit status at line (status --current-line-number)
|
|
|
|
|
|
|
|
string replace --regex -f "\d" X 1bc axc 2 d3f jk4 xyz
|
|
|
|
or echo Unexpected exit status at line (status --current-line-number)
|
|
|
|
# CHECK: Xbc
|
|
|
|
# CHECK: X
|
|
|
|
# CHECK: dXf
|
|
|
|
# CHECK: jkX
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string replace --regex -f Z X 1bc axc 2 d3f jk4 xyz
|
2019-06-25 23:21:11 +08:00
|
|
|
and echo Unexpected exit status at line (status --current-line-number)
|
|
|
|
|
|
|
|
# From https://github.com/fish-shell/fish-shell/issues/5201
|
|
|
|
# 'string match -r with empty capture groups'
|
|
|
|
string match -r '^([ugoa]*)([=+-]?)([rwx]*)$' '=r'
|
|
|
|
#CHECK: =r
|
2020-09-28 01:12:42 +08:00
|
|
|
#CHECK:
|
2019-06-25 23:21:11 +08:00
|
|
|
#CHECK: =
|
|
|
|
#CHECK: r
|
|
|
|
|
|
|
|
### Test some failure cases
|
|
|
|
string match -r "[" "a[sd"; and echo "unexpected exit 0"
|
|
|
|
# CHECKERR: string match: Regular expression compile error: missing terminating ] for character class
|
|
|
|
# CHECKERR: string match: [
|
|
|
|
# CHECKERR: string match: ^
|
|
|
|
|
|
|
|
# FIXME: This prints usage summary?
|
|
|
|
#string invalidarg; and echo "unexpected exit 0"
|
|
|
|
# DONTCHECKERR: string: Subcommand 'invalidarg' is not valid
|
|
|
|
|
|
|
|
string length; or echo "missing argument returns 1"
|
|
|
|
# CHECK: missing argument returns 1
|
|
|
|
|
|
|
|
string match -r -v "[dcantg].*" dog can cat diz; or echo "no regexp invert match"
|
|
|
|
# CHECK: no regexp invert match
|
|
|
|
|
|
|
|
string match -v "*" dog can cat diz; or echo "no glob invert match"
|
|
|
|
# CHECK: no glob invert match
|
|
|
|
|
|
|
|
string match -rvn a bbb; or echo "exit 1"
|
|
|
|
# CHECK: 1 3
|
|
|
|
|
|
|
|
### Test repeat subcommand
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat -n 2 foo
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: foofoo
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat --count 2 foo
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: foofoo
|
|
|
|
|
|
|
|
echo foo | string repeat -n 2
|
|
|
|
# CHECK: foofoo
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat -n2 -q foo; and echo "exit 0"
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: exit 0
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat -n2 --quiet foo; and echo "exit 0"
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: exit 0
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat -n0 foo; or echo "exit 1"
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: exit 1
|
|
|
|
|
|
|
|
string repeat -n0; or echo "exit 1"
|
|
|
|
# CHECK: exit 1
|
|
|
|
|
|
|
|
string repeat -m0; or echo "exit 1"
|
|
|
|
# CHECK: exit 1
|
|
|
|
|
2020-01-14 03:34:22 +08:00
|
|
|
string repeat -n1 -N "there is "
|
|
|
|
echo "no newline"
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: there is no newline
|
|
|
|
|
2020-01-14 03:34:22 +08:00
|
|
|
string repeat -n1 --no-newline "there is "
|
|
|
|
echo "no newline"
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: there is no newline
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat -n10 -m4 foo
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: foof
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat -n10 --max 5 foo
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: foofo
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat -n3 -m20 foo
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: foofoofoo
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat -m4 foo
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: foof
|
|
|
|
|
2021-01-12 08:30:33 +08:00
|
|
|
string repeat -n 5 a b c
|
|
|
|
# CHECK: aaaaa
|
|
|
|
# CHECK: bbbbb
|
|
|
|
# CHECK: ccccc
|
|
|
|
|
|
|
|
string repeat -n 5 --max 4 123 456 789
|
|
|
|
# CHECK: 1231
|
|
|
|
# CHECK: 4564
|
|
|
|
# CHECK: 7897
|
|
|
|
|
|
|
|
string repeat -n 5 --max 4 123 '' 789
|
|
|
|
# CHECK: 1231
|
|
|
|
# CHECK:
|
|
|
|
# CHECK: 7897
|
|
|
|
|
2023-06-20 10:28:35 +08:00
|
|
|
# FIXME: handle overflowing nicely
|
|
|
|
# overflow behaviour depends on 32 vs 64 bit
|
|
|
|
|
|
|
|
# count here is isize::MAX
|
|
|
|
# we store what to print as usize, so this will overflow
|
|
|
|
# but we limit it to less than whatever the overflow is
|
|
|
|
# so this should be fine
|
|
|
|
# string repeat -m1 -n 9223372036854775807 aa
|
|
|
|
# DONTCHECK: a
|
|
|
|
|
|
|
|
# count is here (i64::MAX + 1) / 2
|
|
|
|
# we end up overflowing, and the result is 0
|
|
|
|
# but this should work fine, as we limit it way before the overflow
|
|
|
|
# string repeat -m1 -n 4611686018427387904 aaaa
|
|
|
|
# DONTCHECK: a
|
|
|
|
|
2021-01-12 08:30:33 +08:00
|
|
|
# Historical string repeat behavior is no newline if no output.
|
|
|
|
echo -n before
|
|
|
|
string repeat -n 5 ''
|
|
|
|
echo after
|
|
|
|
# CHECK: beforeafter
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat -n-1 foo; and echo "exit 0"
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECKERR: string repeat: Invalid count value '-1'
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat -m-1 foo; and echo "exit 0"
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECKERR: string repeat: Invalid max value '-1'
|
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat -n notanumber foo; and echo "exit 0"
|
2021-11-04 13:52:17 +08:00
|
|
|
# CHECKERR: string repeat: notanumber: invalid integer
|
2019-06-25 23:21:11 +08:00
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
string repeat -m notanumber foo; and echo "exit 0"
|
2021-11-04 13:52:17 +08:00
|
|
|
# CHECKERR: string repeat: notanumber: invalid integer
|
2019-06-25 23:21:11 +08:00
|
|
|
|
2020-03-10 02:36:12 +08:00
|
|
|
echo stdin | string repeat -n1 "and arg"; and echo "exit 0"
|
2021-11-04 13:52:17 +08:00
|
|
|
# CHECKERR: string repeat: too many arguments
|
2019-06-25 23:21:11 +08:00
|
|
|
|
|
|
|
string repeat -n; and echo "exit 0"
|
2021-11-04 13:52:17 +08:00
|
|
|
# CHECKERR: string repeat: -n: option requires an argument
|
2019-06-25 23:21:11 +08:00
|
|
|
|
|
|
|
# FIXME: Also triggers usage
|
|
|
|
# string repeat -l fakearg
|
|
|
|
# DONTCHECKERR: string repeat: Unknown option '-l'
|
|
|
|
|
|
|
|
string repeat ""
|
|
|
|
or echo string repeat empty string failed
|
|
|
|
# CHECK: string repeat empty string failed
|
|
|
|
|
|
|
|
string repeat -n3 ""
|
|
|
|
or echo string repeat empty string failed
|
|
|
|
# CHECK: string repeat empty string failed
|
|
|
|
|
2022-08-10 01:58:56 +08:00
|
|
|
# See that we hit the expected length
|
|
|
|
# First with "max", i.e. maximum number of characters
|
|
|
|
string repeat -m 5000 aab | string length
|
|
|
|
# CHECK: 5000
|
|
|
|
string repeat -m 5000 ab | string length
|
|
|
|
# CHECK: 5000
|
|
|
|
string repeat -m 5000 a | string length
|
|
|
|
# CHECK: 5000
|
|
|
|
string repeat -m 17 aab | string length
|
|
|
|
# CHECK: 17
|
|
|
|
string repeat -m 17 ab | string length
|
|
|
|
# CHECK: 17
|
|
|
|
string repeat -m 17 a | string length
|
|
|
|
# CHECK: 17
|
|
|
|
# Then with "count", i.e. number of repetitions.
|
|
|
|
# (these are count * length long)
|
|
|
|
string repeat -n 17 aab | string length
|
|
|
|
# CHECK: 51
|
|
|
|
string repeat -n 17 ab | string length
|
|
|
|
# CHECK: 34
|
|
|
|
string repeat -n 17 a | string length
|
|
|
|
# CHECK: 17
|
|
|
|
# And a more tricksy case with a long string that we truncate.
|
|
|
|
string repeat -m 5 (string repeat -n 500000 aaaaaaaaaaaaaaaaaa) | string length
|
|
|
|
# CHECK: 5
|
|
|
|
|
2023-07-17 20:53:03 +08:00
|
|
|
# might cause integer overflow
|
|
|
|
string repeat -n 2999 \n | count
|
|
|
|
# CHECK: 3000
|
|
|
|
|
2019-06-25 23:21:11 +08:00
|
|
|
# Test equivalent matches with/without the --entire, --regex, and --invert flags.
|
|
|
|
string match -e x abc dxf xyz jkx x z
|
|
|
|
or echo exit 1
|
|
|
|
# CHECK: dxf
|
|
|
|
# CHECK: xyz
|
|
|
|
# CHECK: jkx
|
|
|
|
# CHECK: x
|
|
|
|
|
|
|
|
string match x abc dxf xyz jkx x z
|
|
|
|
# CHECK: x
|
|
|
|
|
|
|
|
string match --entire -r "a*b[xy]+" abc abxc bye aaabyz kaabxz abbxy abcx caabxyxz
|
|
|
|
or echo exit 1
|
|
|
|
# CHECK: abxc
|
|
|
|
# CHECK: bye
|
|
|
|
# CHECK: aaabyz
|
|
|
|
# CHECK: kaabxz
|
|
|
|
# CHECK: abbxy
|
|
|
|
# CHECK: caabxyxz
|
|
|
|
|
|
|
|
# 'string match --entire "" -- banana'
|
|
|
|
string match --entire "" -- banana
|
|
|
|
or echo exit 1
|
|
|
|
# CHECK: banana
|
|
|
|
|
|
|
|
# 'string match -r "a*b[xy]+" abc abxc bye aaabyz kaabxz abbxy abcx caabxyxz'
|
|
|
|
string match -r "a*b[xy]+" abc abxc bye aaabyz kaabxz abbxy abcx caabxyxz
|
|
|
|
or echo exit 1
|
|
|
|
# CHECK: abx
|
|
|
|
# CHECK: by
|
|
|
|
# CHECK: aaaby
|
|
|
|
# CHECK: aabx
|
|
|
|
# CHECK: bxy
|
|
|
|
# CHECK: aabxyx
|
|
|
|
|
|
|
|
# Make sure that groups are handled correct with/without --entire.
|
|
|
|
# 'string match --entire -r "a*b([xy]+)" abc abxc bye aaabyz kaabxz abbxy abcx caabxyxz'
|
|
|
|
string match --entire -r "a*b([xy]+)" abc abxc bye aaabyz kaabxz abbxy abcx caabxyxz
|
|
|
|
or echo exit 1
|
|
|
|
# CHECK: abxc
|
|
|
|
# CHECK: x
|
|
|
|
# CHECK: bye
|
|
|
|
# CHECK: y
|
|
|
|
# CHECK: aaabyz
|
|
|
|
# CHECK: y
|
|
|
|
# CHECK: kaabxz
|
|
|
|
# CHECK: x
|
|
|
|
# CHECK: abbxy
|
|
|
|
# CHECK: xy
|
|
|
|
# CHECK: caabxyxz
|
|
|
|
# CHECK: xyx
|
|
|
|
|
|
|
|
# 'string match -r "a*b([xy]+)" abc abxc bye aaabyz kaabxz abbxy abcx caabxyxz'
|
|
|
|
string match -r "a*b([xy]+)" abc abxc bye aaabyz kaabxz abbxy abcx caabxyxz
|
|
|
|
or echo exit 1
|
|
|
|
# CHECK: abx
|
|
|
|
# CHECK: x
|
|
|
|
# CHECK: by
|
|
|
|
# CHECK: y
|
|
|
|
# CHECK: aaaby
|
|
|
|
# CHECK: y
|
|
|
|
# CHECK: aabx
|
|
|
|
# CHECK: x
|
|
|
|
# CHECK: bxy
|
|
|
|
# CHECK: xy
|
|
|
|
# CHECK: aabxyx
|
|
|
|
# CHECK: xyx
|
|
|
|
|
|
|
|
# Test `string lower` and `string upper`.
|
|
|
|
set x (string lower abc DEF gHi)
|
|
|
|
or echo string lower exit 1
|
2020-03-10 02:36:12 +08:00
|
|
|
test $x[1] = abc -a $x[2] = def -a $x[3] = ghi
|
2019-06-25 23:21:11 +08:00
|
|
|
or echo strings not converted to lowercase
|
|
|
|
|
|
|
|
set x (echo abc DEF gHi | string lower)
|
|
|
|
or echo string lower exit 1
|
|
|
|
test $x[1] = 'abc def ghi'
|
|
|
|
or echo strings not converted to lowercase
|
|
|
|
|
|
|
|
string lower -q abc
|
|
|
|
and echo lowercasing a lowercase string did not fail as expected
|
|
|
|
|
|
|
|
set x (string upper abc DEF gHi)
|
|
|
|
or echo string upper exit 1
|
2020-03-10 02:36:12 +08:00
|
|
|
test $x[1] = ABC -a $x[2] = DEF -a $x[3] = GHI
|
2019-06-25 23:21:11 +08:00
|
|
|
or echo strings not converted to uppercase
|
|
|
|
|
|
|
|
set x (echo abc DEF gHi | string upper)
|
|
|
|
or echo string upper exit 1
|
|
|
|
test $x[1] = 'ABC DEF GHI'
|
|
|
|
or echo strings not converted to uppercase
|
|
|
|
|
|
|
|
string upper -q ABC DEF
|
|
|
|
and echo uppercasing a uppercase string did not fail as expected
|
|
|
|
|
|
|
|
# 'Check NUL'
|
|
|
|
# Note: We do `string escape` at the end to make a `\0` literal visible.
|
2021-11-23 04:08:56 +08:00
|
|
|
printf 'a\0b\n' | string escape
|
|
|
|
printf 'a\0c\n' | string match -e a | string escape
|
|
|
|
printf 'a\0d\n' | string split '' | string escape
|
|
|
|
printf 'a\0b\n' | string match -r '.*b$' | string escape
|
|
|
|
printf 'a\0b\n' | string replace b g | string escape
|
|
|
|
printf 'a\0b\n' | string replace -r b g | string escape
|
2019-06-25 23:21:11 +08:00
|
|
|
# TODO: These do not yet work!
|
|
|
|
# printf 'a\0b' | string match '*b' | string escape
|
|
|
|
# CHECK: a\x00b
|
|
|
|
# CHECK: a\x00c
|
|
|
|
# CHECK: a
|
|
|
|
# CHECK: \x00
|
|
|
|
# CHECK: d
|
|
|
|
# CHECK: a\x00b
|
|
|
|
# CHECK: a\x00g
|
|
|
|
# CHECK: a\x00g
|
|
|
|
|
|
|
|
# string split0
|
|
|
|
count (echo -ne 'abcdefghi' | string split0)
|
|
|
|
# CHECK: 1
|
|
|
|
count (echo -ne 'abc\x00def\x00ghi\x00' | string split0)
|
|
|
|
# CHECK: 3
|
|
|
|
count (echo -ne 'abc\x00def\x00ghi\x00\x00' | string split0)
|
|
|
|
# CHECK: 4
|
|
|
|
count (echo -ne 'abc\x00def\x00ghi' | string split0)
|
|
|
|
# CHECK: 3
|
|
|
|
count (echo -ne 'abc\ndef\x00ghi\x00' | string split0)
|
|
|
|
# CHECK: 2
|
|
|
|
count (echo -ne 'abc\ndef\nghi' | string split0)
|
|
|
|
# CHECK: 1
|
|
|
|
# #5701 - split0 always returned 1
|
|
|
|
echo -ne 'a\x00b' | string split0
|
|
|
|
and echo Split something
|
|
|
|
# CHECK: a
|
|
|
|
# CHECK: b
|
|
|
|
# CHECK: Split something
|
|
|
|
|
|
|
|
# string join0
|
|
|
|
set tmp beta alpha\ngamma
|
|
|
|
count (string join \n $tmp)
|
|
|
|
# CHECK: 3
|
|
|
|
count (string join0 $tmp)
|
|
|
|
# CHECK: 2
|
|
|
|
count (string join0 $tmp | string split0)
|
|
|
|
# CHECK: 2
|
|
|
|
|
|
|
|
# string split0 in functions
|
|
|
|
# This function outputs some newline-separated content, and some
|
|
|
|
# explicitly separated content.
|
|
|
|
function dualsplit
|
2020-01-14 03:34:22 +08:00
|
|
|
echo alpha
|
|
|
|
echo beta
|
|
|
|
echo -ne 'gamma\x00delta' | string split0
|
2019-06-25 23:21:11 +08:00
|
|
|
end
|
|
|
|
count (dualsplit)
|
|
|
|
# CHECK: 4
|
|
|
|
|
2019-07-22 04:53:05 +08:00
|
|
|
# Ensure we handle empty outputs correctly (#5987)
|
|
|
|
count (string split / /)
|
|
|
|
# CHECK: 2
|
|
|
|
count (echo -ne '\x00\x00\x00' | string split0)
|
|
|
|
# CHECK: 3
|
|
|
|
|
2019-06-25 23:21:11 +08:00
|
|
|
# string collect
|
|
|
|
count (echo one\ntwo\nthree\nfour | string collect)
|
|
|
|
count (echo one | string collect)
|
|
|
|
# CHECK: 1
|
|
|
|
# CHECK: 1
|
|
|
|
echo [(echo one\ntwo\nthree | string collect)]
|
|
|
|
# CHECK: [one
|
|
|
|
# CHECK: two
|
|
|
|
# CHECK: three]
|
|
|
|
echo [(echo one\ntwo\nthree | string collect -N)]
|
|
|
|
# CHECK: [one
|
|
|
|
# CHECK: two
|
|
|
|
# CHECK: three
|
|
|
|
# CHECK: ]
|
|
|
|
printf '[%s]\n' (string collect one\n\n two\n)
|
|
|
|
# CHECK: [one]
|
|
|
|
# CHECK: [two]
|
|
|
|
printf '[%s]\n' (string collect -N one\n\n two\n)
|
|
|
|
# CHECK: [one
|
2020-09-28 01:12:42 +08:00
|
|
|
# CHECK:
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: ]
|
|
|
|
# CHECK: [two
|
|
|
|
# CHECK: ]
|
|
|
|
printf '[%s]\n' (string collect --no-trim-newlines one\n\n two\n)
|
|
|
|
# CHECK: [one
|
2020-09-28 01:12:42 +08:00
|
|
|
# CHECK:
|
2019-06-25 23:21:11 +08:00
|
|
|
# CHECK: ]
|
|
|
|
# CHECK: [two
|
|
|
|
# CHECK: ]
|
|
|
|
# string collect returns 0 when it has any output, otherwise 1
|
|
|
|
string collect >/dev/null; and echo unexpected success; or echo expected failure
|
|
|
|
# CHECK: expected failure
|
|
|
|
echo -n | string collect >/dev/null; and echo unexpected success; or echo expected failure
|
|
|
|
# CHECK: expected failure
|
|
|
|
echo | string collect -N >/dev/null; and echo expected success; or echo unexpected failure
|
|
|
|
# CHECK: expected success
|
|
|
|
echo | string collect >/dev/null; and echo unexpected success; or echo expected failure
|
|
|
|
# CHECK: expected failure
|
|
|
|
string collect a >/dev/null; and echo expected success; or echo unexpected failure
|
|
|
|
# CHECK: expected success
|
|
|
|
string collect -N '' >/dev/null; and echo unexpected success; or echo expected failure
|
|
|
|
# CHECK: expected failure
|
|
|
|
string collect \n\n >/dev/null; and echo unexpected success; or echo expected failure
|
|
|
|
# CHECK: expected failure
|
|
|
|
|
2021-07-10 03:20:58 +08:00
|
|
|
echo "foo"(true | string collect --allow-empty)"bar"
|
|
|
|
# CHECK: foobar
|
|
|
|
test -z (string collect)
|
|
|
|
and echo Nothing
|
|
|
|
# CHECK: Nothing
|
|
|
|
test -n (string collect)
|
|
|
|
and echo Something
|
|
|
|
# CHECK: Something
|
|
|
|
test -n (string collect -a)
|
|
|
|
or echo No, actually nothing
|
|
|
|
# CHECK: No, actually nothing
|
|
|
|
|
2019-06-25 23:21:11 +08:00
|
|
|
# string collect in functions
|
|
|
|
# This function outputs some newline-separated content, and some
|
|
|
|
# explicitly un-separated content.
|
|
|
|
function dualcollect
|
2020-01-14 03:34:22 +08:00
|
|
|
echo alpha
|
|
|
|
echo beta
|
|
|
|
echo gamma\ndelta\nomega | string collect
|
2019-06-25 23:21:11 +08:00
|
|
|
end
|
|
|
|
count (dualcollect)
|
|
|
|
# CHECK: 3
|
2019-10-23 03:56:44 +08:00
|
|
|
|
|
|
|
string match -qer asd asd
|
2019-11-05 00:33:37 +08:00
|
|
|
echo $status
|
|
|
|
# CHECK: 0
|
|
|
|
|
2023-06-20 10:28:35 +08:00
|
|
|
# should not be able to enable UTF mode
|
|
|
|
string match -r "(*UTF).*" "aaa"
|
|
|
|
# CHECKERR: string match: Regular expression compile error: using UTF is disabled by the application
|
|
|
|
# CHECKERR: string match: (*UTF).*
|
|
|
|
# CHECKERR: string match: ^
|
|
|
|
|
|
|
|
string replace -r "(*UTF).*" "aaa"
|
|
|
|
# CHECKERR: string replace: Regular expression compile error: using UTF is disabled by the application
|
|
|
|
# CHECKERR: string replace: (*UTF).*
|
|
|
|
# CHECKERR: string replace: ^
|
|
|
|
|
|
|
|
|
2019-11-05 00:33:37 +08:00
|
|
|
string match -eq asd asd
|
|
|
|
echo $status
|
|
|
|
# CHECK: 0
|
2020-09-20 16:33:04 +08:00
|
|
|
|
|
|
|
# Unmatched capturing groups are treated as empty
|
2020-09-28 03:51:20 +08:00
|
|
|
echo az | string replace -r -- 'a(b.+)?z' 'a:$1z'
|
2020-09-20 16:33:04 +08:00
|
|
|
# CHECK: a:z
|
2020-11-29 19:06:48 +08:00
|
|
|
|
|
|
|
# --quiet should quit early
|
|
|
|
echo "Checking that --quiet quits early - if this is broken it hangs"
|
|
|
|
# CHECK: Checking that --quiet quits early - if this is broken it hangs
|
|
|
|
yes | string match -q y
|
|
|
|
echo $status
|
|
|
|
# CHECK: 0
|
|
|
|
yes | string length -q
|
|
|
|
echo $status
|
|
|
|
# CHECK: 0
|
|
|
|
yes | string replace -q y n
|
|
|
|
echo $status
|
|
|
|
# CHECK: 0
|
2020-12-06 22:31:04 +08:00
|
|
|
|
|
|
|
# `string` can't be wrapped properly anymore, since `string match` creates variables:
|
|
|
|
function string
|
|
|
|
builtin string $argv
|
|
|
|
end
|
2021-11-04 13:52:17 +08:00
|
|
|
# CHECKERR: checks/string.fish (line {{\d+}}): function: string: cannot use reserved keyword as function name
|
2020-12-06 22:31:04 +08:00
|
|
|
# CHECKERR: function string
|
|
|
|
# CHECKERR: ^
|
2021-01-16 19:49:49 +08:00
|
|
|
|
|
|
|
string escape \x7F
|
|
|
|
# CHECK: \x7f
|
2021-03-10 01:32:15 +08:00
|
|
|
|
|
|
|
# This used to crash.
|
|
|
|
string pad -w 8 he \eh
|
|
|
|
# CHECK: he
|
|
|
|
# CHECK: {{\x1bh}}
|
2019-06-11 22:05:24 +08:00
|
|
|
|
|
|
|
string match -rg '(.*)fish' catfish
|
|
|
|
# CHECK: cat
|
|
|
|
string match -rg '(.*)fish' shellfish
|
|
|
|
# CHECK: shell
|
|
|
|
# An empty match
|
|
|
|
string match -rg '(.*)fish' fish
|
|
|
|
# No match at all
|
|
|
|
string match -rg '(.*)fish' banana
|
|
|
|
# Make sure it doesn't start matching something
|
|
|
|
string match -r --groups-only '(.+)fish' fish
|
|
|
|
echo $status
|
|
|
|
# CHECK: 1
|
|
|
|
# Multiple groups
|
|
|
|
string match -r --groups-only '(.+)fish(.*)' catfishcolor
|
|
|
|
# CHECK: cat
|
|
|
|
# CHECK: color
|
|
|
|
|
|
|
|
# Examples specifically called out in #6056.
|
|
|
|
echo "foo bar baz" | string match -rg 'foo (bar) baz'
|
|
|
|
# CHECK: bar
|
|
|
|
echo "foo1x foo2x foo3x" | string match -arg 'foo(\d)x'
|
|
|
|
# CHECK: 1
|
|
|
|
# CHECK: 2
|
|
|
|
# CHECK: 3
|
2021-11-23 04:08:56 +08:00
|
|
|
|
|
|
|
# Most subcommands preserve missing newline (#3847).
|
|
|
|
echo -n abc | string upper
|
|
|
|
echo '<eol>'
|
|
|
|
# CHECK: ABC<eol>
|
2023-06-20 10:28:35 +08:00
|
|
|
|
|
|
|
# newline should not appear from nowhere when command does not split on newline
|
|
|
|
echo -n abc | string collect
|
|
|
|
echo '<eol>'
|
|
|
|
# CHECK: abc<eol>
|
|
|
|
|
2021-11-23 04:08:56 +08:00
|
|
|
printf \<
|
|
|
|
printf my-password | string replace -ra . \*
|
|
|
|
printf \>\n
|
|
|
|
# CHECK: <***********>
|
Add string shorten
This is essentially the inverse of `string pad`.
Where that adds characters to get up to the specified width,
this adds an ellipsis to a string if it goes over a specific maximum width.
The char can be given, but defaults to our ellipsis string.
("…" if the locale can handle it and "..." otherwise)
If the ellipsis string is empty, it just truncates.
For arguments given via argv, it goes line-by-line,
because otherwise length makes no sense.
If "--no-newline" is given, it adds an ellipsis instead and removes all subsequent lines.
Like pad and `length --visible`, it goes by visible width,
skipping recognized escape sequences, as those have no influence on width.
The default target width is the shortest of the given widths that is non-zero.
If the ellipsis is already wider than the target width,
we truncate instead. This is safer overall, so we don't e.g. move into a new line.
This is especially important given our default ellipsis might be width 3.
2022-08-16 23:57:19 +08:00
|
|
|
|
|
|
|
string shorten -m 3 foo
|
|
|
|
# CHECK: foo
|
|
|
|
string shorten -m 2 foo
|
|
|
|
# CHECK: f…
|
|
|
|
|
|
|
|
string shorten -m 5 foobar
|
|
|
|
# CHECK: foob…
|
|
|
|
|
|
|
|
# Char is longer than width, we truncate instead.
|
|
|
|
string shorten -m 5 --char ........ foobar
|
|
|
|
# CHECK: fooba
|
|
|
|
|
|
|
|
string shorten --max 4 -c /// foobar
|
|
|
|
# CHECK: f///
|
|
|
|
|
|
|
|
string shorten --max 4 -c /// foobarnana
|
|
|
|
# CHECK: f///
|
|
|
|
|
|
|
|
string shorten --max 2 --chars "" foo
|
|
|
|
# CHECK: fo
|
|
|
|
|
|
|
|
string shorten foo foobar
|
|
|
|
# CHECK: foo
|
|
|
|
# CHECK: fo…
|
|
|
|
|
2023-07-13 10:17:19 +08:00
|
|
|
# pad with a bell, it has zero width, that's fine
|
|
|
|
string shorten -c \a foo foobar | string escape
|
|
|
|
# CHECK: foo
|
|
|
|
# CHECK: foo\cg
|
|
|
|
|
|
|
|
string shorten -c \aw foo foobar | string escape
|
|
|
|
# CHECK: foo
|
|
|
|
# CHECK: fo\cgw
|
|
|
|
|
|
|
|
# backspace is fine!
|
|
|
|
string shorten -c \b foo foobar | string escape
|
|
|
|
# CHECK: foo
|
|
|
|
# CHECK: foo\b
|
|
|
|
|
|
|
|
string shorten -c \ba foo foobar | string escape
|
|
|
|
# CHECK: foo
|
|
|
|
# CHECK: fo\ba
|
|
|
|
|
|
|
|
string shorten -c cool\b\b\b\b foo foobar | string escape
|
|
|
|
# CHECK: foo
|
|
|
|
# CHECK: foocool\b\b\b\b
|
|
|
|
|
|
|
|
string shorten -c cool\b\b\b\b\b foo foobar | string escape
|
|
|
|
# CHECK: foo
|
|
|
|
# negative width ellipsis is fine
|
|
|
|
# CHECK: foocool\b\b\b\b\b
|
|
|
|
|
|
|
|
string shorten -c \a\aXX foo foobar | string escape
|
|
|
|
# CHECK: foo
|
|
|
|
# CHECK: f\cg\cgXX
|
|
|
|
|
Add string shorten
This is essentially the inverse of `string pad`.
Where that adds characters to get up to the specified width,
this adds an ellipsis to a string if it goes over a specific maximum width.
The char can be given, but defaults to our ellipsis string.
("…" if the locale can handle it and "..." otherwise)
If the ellipsis string is empty, it just truncates.
For arguments given via argv, it goes line-by-line,
because otherwise length makes no sense.
If "--no-newline" is given, it adds an ellipsis instead and removes all subsequent lines.
Like pad and `length --visible`, it goes by visible width,
skipping recognized escape sequences, as those have no influence on width.
The default target width is the shortest of the given widths that is non-zero.
If the ellipsis is already wider than the target width,
we truncate instead. This is safer overall, so we don't e.g. move into a new line.
This is especially important given our default ellipsis might be width 3.
2022-08-16 23:57:19 +08:00
|
|
|
# A weird case - our minimum width here is 1,
|
|
|
|
# so everything that goes over the width becomes "x"
|
|
|
|
for i in (seq 1 10)
|
|
|
|
math 2 ^ $i
|
|
|
|
end | string shorten -c x
|
|
|
|
# CHECK: 2
|
|
|
|
# CHECK: 4
|
|
|
|
# CHECK: 8
|
|
|
|
# CHECK: x
|
|
|
|
# CHECK: x
|
|
|
|
# CHECK: x
|
|
|
|
# CHECK: x
|
|
|
|
# CHECK: x
|
|
|
|
# CHECK: x
|
|
|
|
# CHECK: x
|
|
|
|
|
|
|
|
string shorten -N -cx bar\nfooo
|
|
|
|
# CHECK: barx
|
|
|
|
|
|
|
|
# Shorten and emoji width.
|
|
|
|
begin
|
|
|
|
# \U1F4A9 was widened in unicode 9, so it's affected
|
|
|
|
# by $fish_emoji_width
|
|
|
|
# "…" isn't and always has width 1.
|
|
|
|
#
|
|
|
|
# "abcde" has width 5, we have a total width of 6,
|
|
|
|
# so we need to overwrite the "e" with our ellipsis.
|
|
|
|
fish_emoji_width=1 string shorten --max=5 -- abcde💩
|
|
|
|
# CHECK: abcd…
|
|
|
|
# This fits assuming the poo fits in one column
|
|
|
|
fish_emoji_width=1 string shorten --max=6 -- abcde💩
|
|
|
|
# CHECK: abcde💩
|
|
|
|
|
|
|
|
# This has a total width of 7 (assuming double-wide poo),
|
|
|
|
# so we need to add the ellipsis on the "e"
|
|
|
|
fish_emoji_width=2 string shorten --max=5 -- abcde💩
|
|
|
|
# CHECK: abcd…
|
|
|
|
# This still doesn't fit!
|
|
|
|
fish_emoji_width=2 string shorten --max=6 -- abcde💩
|
|
|
|
# CHECK: abcde…
|
|
|
|
fish_emoji_width=2 string shorten --max=7 -- abcde💩
|
|
|
|
# CHECK: abcde💩
|
|
|
|
end
|
|
|
|
|
|
|
|
# See that colors aren't counted
|
|
|
|
string shorten -m6 (set_color blue)s(set_color red)t(set_color --bold brwhite)rin(set_color red)g(set_color yellow)-shorten | string escape
|
|
|
|
# Renders like "strin…" in colors
|
|
|
|
# Note that red sequence that we still pass on because it's width 0.
|
|
|
|
# CHECK: \e\[34ms\e\[31mt\e\[1m\e\[37mrin\e\[31m…
|
|
|
|
|
2023-07-13 10:17:19 +08:00
|
|
|
# See that colors aren't counted in ellipsis
|
|
|
|
string shorten -c (set_color blue)s(set_color red)t(set_color --bold brwhite)rin(set_color red)g -m 8 abcdefghijklmno | string escape
|
|
|
|
# Renders like "abstring" in colors
|
|
|
|
# CHECK: ab\e\[34ms\e\[31mt\e\[1m\e\[37mrin\e\[31mg
|
|
|
|
|
Add string shorten
This is essentially the inverse of `string pad`.
Where that adds characters to get up to the specified width,
this adds an ellipsis to a string if it goes over a specific maximum width.
The char can be given, but defaults to our ellipsis string.
("…" if the locale can handle it and "..." otherwise)
If the ellipsis string is empty, it just truncates.
For arguments given via argv, it goes line-by-line,
because otherwise length makes no sense.
If "--no-newline" is given, it adds an ellipsis instead and removes all subsequent lines.
Like pad and `length --visible`, it goes by visible width,
skipping recognized escape sequences, as those have no influence on width.
The default target width is the shortest of the given widths that is non-zero.
If the ellipsis is already wider than the target width,
we truncate instead. This is safer overall, so we don't e.g. move into a new line.
This is especially important given our default ellipsis might be width 3.
2022-08-16 23:57:19 +08:00
|
|
|
set -l str (set_color blue)s(set_color red)t(set_color --bold brwhite)rin(set_color red)g(set_color yellow)-shorten
|
|
|
|
for i in (seq 1 (string length -V -- $str))
|
|
|
|
set -l len (string shorten -m$i -- $str | string length -V)
|
|
|
|
test $len = $i
|
|
|
|
or echo Oopsie ellipsizing to $i failed
|
|
|
|
end
|
|
|
|
|
|
|
|
string shorten -m4 foobar\nbananarama
|
|
|
|
# CHECK: foo…
|
|
|
|
# CHECK: ban…
|
|
|
|
|
|
|
|
# First line is empty and printed as-is
|
|
|
|
# The other lines are truncated to the width of the first real line.
|
|
|
|
printf '
|
|
|
|
1. line
|
|
|
|
2. another line
|
|
|
|
3. third line' | string shorten
|
|
|
|
# CHECK:
|
|
|
|
# CHECK: 1. line
|
|
|
|
# CHECK: 2. ano…
|
|
|
|
# CHECK: 3. thi…
|
|
|
|
|
|
|
|
printf '
|
|
|
|
1. line
|
|
|
|
2. another line
|
|
|
|
3. third line' | string shorten --left
|
|
|
|
# CHECK:
|
|
|
|
# CHECK: 1. line
|
|
|
|
# CHECK: …r line
|
|
|
|
# CHECK: …d line
|
|
|
|
|
|
|
|
string shorten -m12 -l (set_color blue)s(set_color red)t(set_color --bold brwhite)rin(set_color red)(set_color green)g(set_color yellow)-shorten | string escape
|
|
|
|
# Renders like "…ing-shorten" with g in green and "-shorten" in yellow
|
|
|
|
# Yes, that's a "red" escape before.
|
|
|
|
# CHECK: …in\e\[31m\e\[32mg\e\[33m-shorten
|
|
|
|
|
|
|
|
set -l str (set_color blue)s(set_color red)t(set_color --bold brwhite)rin(set_color red)g(set_color yellow)-shorten
|
|
|
|
for i in (seq 1 (string length -V -- $str))
|
|
|
|
set -l len (string shorten -m$i --left -- $str | string length -V)
|
|
|
|
test $len = $i
|
|
|
|
or echo Oopsie ellipsizing to $i failed
|
|
|
|
end
|
2022-10-05 00:44:21 +08:00
|
|
|
|
|
|
|
string shorten -m0 foo bar asodjsaoidj
|
|
|
|
# CHECK: foo
|
|
|
|
# CHECK: bar
|
|
|
|
# CHECK: asodjsaoidj
|
2023-07-13 10:17:19 +08:00
|
|
|
|
|
|
|
# backspaces are weird
|
|
|
|
string shorten abc ab abcdef(string repeat -n 6 \b) | string escape
|
|
|
|
# CHECK: a…
|
|
|
|
# CHECK: ab
|
|
|
|
# this line has length zero, since backspace removes it all
|
|
|
|
# CHECK: abcdef\b\b\b\b\b\b
|
|
|
|
|
|
|
|
# due to an integer overflow this might truncate the third backspaced one, it should not
|
|
|
|
string shorten abc ab abcdef(string repeat -n 7 \b) | string escape
|
|
|
|
# CHECK: a…
|
|
|
|
# CHECK: ab
|
|
|
|
# this line has length zero, since backspace removes it all
|
|
|
|
# CHECK: abcdef\b\b\b\b\b\b\b
|
|
|
|
|
|
|
|
# due to an integer overflow this might truncate
|
|
|
|
string shorten abc \bab ab abcdef | string escape
|
|
|
|
# CHECK: a…
|
|
|
|
# backspace does not contribute length at the start
|
|
|
|
# CHECK: \bab
|
|
|
|
# CHECK: ab
|
|
|
|
# CHECK: a…
|
|
|
|
|
|
|
|
string shorten abc \babc ab abcdef | string escape
|
|
|
|
# CHECK: a…
|
|
|
|
# CHECK: \ba…
|
|
|
|
# CHECK: ab
|
|
|
|
# CHECK: a…
|
|
|
|
|
|
|
|
# non-printable-escape-chars (in this case bell)
|
|
|
|
string shorten abc ab abcdef(string repeat -n 6 \a) | string escape
|
|
|
|
# CHECK: a…
|
|
|
|
# CHECK: ab
|
|
|
|
# CHECK: a…
|
|
|
|
|
|
|
|
string shorten abc ab abcdef(string repeat -n 7 \a) | string escape
|
|
|
|
# CHECK: a…
|
|
|
|
# CHECK: ab
|
|
|
|
# CHECK: a…
|
|
|
|
|
|
|
|
string shorten abc \aab ab abcdef | string escape
|
|
|
|
# CHECK: a…
|
|
|
|
# non-printables have length 0
|
|
|
|
# CHECK: \cgab
|
|
|
|
# CHECK: ab
|
|
|
|
# CHECK: a…
|
|
|
|
|
|
|
|
string shorten abc \aabc ab abcdef | string escape
|
|
|
|
# CHECK: a…
|
|
|
|
# CHECK: \cga…
|
|
|
|
# CHECK: ab
|
|
|
|
# CHECK: a…
|