mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-12-12 08:33:45 +08:00
8bf8b10f68
See the changelog additions for user-visible changes. Since we enable/disable terminal protocols whenever we pass terminal ownership, tests can no longer run in parallel on the same terminal. For the same reason, readline shortcuts in the gdb REPL will not work anymore. As a remedy, use gdbserver, or lobby for CSI u support in libreadline. Add sleep to some tests, otherwise they fall (both in CI and locally). There are two weird failures on FreeBSD remaining, disable them for now https://github.com/fish-shell/fish-shell/pull/10359/checks?check_run_id=23330096362 Design and implementation borrows heavily from Kakoune. In future, we should try to implement more of the kitty progressive enhancements. Closes #10359
403 lines
9.2 KiB
Fish
403 lines
9.2 KiB
Fish
# RUN: %fish -C "set fish %fish" %s | %filter-ctrlseqs
|
|
# Set term again explicitly to ensure behavior.
|
|
set -gx TERM xterm
|
|
# Read with no vars is not an error
|
|
read
|
|
|
|
# Read with -a and anything other than exactly on var name is an error
|
|
read -a
|
|
#CHECKERR: read: expected 1 arguments; got 0
|
|
read --array v1 v2
|
|
#CHECKERR: read: expected 1 arguments; got 2
|
|
read --list v1
|
|
|
|
# Verify correct behavior of subcommands and splitting of input.
|
|
begin
|
|
count (echo one\ntwo)
|
|
#CHECK: 2
|
|
set -l IFS \t
|
|
count (echo one\ntwo)
|
|
#CHECK: 2
|
|
set -l IFS
|
|
count (echo one\ntwo)
|
|
#CHECK: 1
|
|
echo [(echo -n one\ntwo)]
|
|
#CHECK: [one
|
|
#CHECK: two]
|
|
count (echo one\ntwo\n)
|
|
#CHECK: 1
|
|
echo [(echo -n one\ntwo\n)]
|
|
#CHECK: [one
|
|
#CHECK: two]
|
|
count (echo one\ntwo\n\n)
|
|
#CHECK: 1
|
|
echo [(echo -n one\ntwo\n\n)]
|
|
#CHECK: [one
|
|
#CHECK: two
|
|
#CHECK: ]
|
|
end
|
|
|
|
function print_vars --no-scope-shadowing
|
|
set -l space
|
|
set -l IFS \n # ensure our command substitution works right
|
|
for var in $argv
|
|
echo -n $space (count $$var) \'$$var\'
|
|
set space ''
|
|
end
|
|
echo
|
|
end
|
|
|
|
# Test splitting input
|
|
echo 'hello there' | read -l one two
|
|
print_vars one two
|
|
#CHECK: 1 'hello' 1 'there'
|
|
echo 'hello there' | read -l one
|
|
print_vars one
|
|
#CHECK: 1 'hello there'
|
|
echo '' | read -l one
|
|
print_vars one
|
|
#CHECK: 1 ''
|
|
echo '' | read -l one two
|
|
print_vars one two
|
|
#CHECK: 1 '' 1 ''
|
|
echo test | read -l one two three
|
|
print_vars one two three
|
|
#CHECK: 1 'test' 1 '' 1 ''
|
|
echo 'foo bar baz' | read -l one two three
|
|
print_vars one two three
|
|
#CHECK: 1 'foo' 1 'bar' 1 ' baz'
|
|
echo -n a | read -l one
|
|
echo "$status $one"
|
|
#CHECK: 0 a
|
|
|
|
# Test splitting input with IFS empty
|
|
set -l IFS
|
|
echo hello | read -l one
|
|
print_vars one
|
|
#CHECK: 1 'hello'
|
|
echo hello | read -l one two
|
|
print_vars one two
|
|
#CHECK: 1 'h' 1 'ello'
|
|
echo hello | read -l one two three
|
|
print_vars one two three
|
|
#CHECK: 1 'h' 1 'e' 1 'llo'
|
|
echo '' | read -l one
|
|
print_vars one
|
|
#CHECK: 0
|
|
echo t | read -l one two
|
|
print_vars one two
|
|
#CHECK: 1 't' 0
|
|
echo t | read -l one two three
|
|
print_vars one two three
|
|
#CHECK: 1 't' 0 0
|
|
echo ' t' | read -l one two
|
|
print_vars one two
|
|
#CHECK: 1 ' ' 1 't'
|
|
set -le IFS
|
|
|
|
echo 'hello there' | read -la ary
|
|
print_vars ary
|
|
#CHECK: 2 'hello' 'there'
|
|
echo hello | read -la ary
|
|
print_vars ary
|
|
#CHECK: 1 'hello'
|
|
echo 'this is a bunch of words' | read -la ary
|
|
print_vars ary
|
|
#CHECK: 6 'this' 'is' 'a' 'bunch' 'of' 'words'
|
|
echo ' one two three' | read -la ary
|
|
print_vars ary
|
|
#CHECK: 3 'one' 'two' 'three'
|
|
echo '' | read -la ary
|
|
print_vars ary
|
|
#CHECK: 0
|
|
|
|
set -l IFS
|
|
echo hello | read -la ary
|
|
print_vars ary
|
|
#CHECK: 5 'h' 'e' 'l' 'l' 'o'
|
|
echo h | read -la ary
|
|
print_vars ary
|
|
#CHECK: 1 'h'
|
|
echo '' | read -la ary
|
|
print_vars ary
|
|
#CHECK: 0
|
|
set -le IFS
|
|
|
|
# read -n tests
|
|
echo testing | read -n 3 foo
|
|
echo $foo
|
|
#CHECK: tes
|
|
echo test | read -n 10 foo
|
|
echo $foo
|
|
#CHECK: test
|
|
echo test | read -n 0 foo
|
|
echo $foo
|
|
#CHECK: test
|
|
echo testing | begin
|
|
read -n 3 foo
|
|
read -n 3 bar
|
|
end
|
|
echo $foo
|
|
#CHECK: tes
|
|
echo $bar
|
|
#CHECK: tin
|
|
echo test | read -n 1 foo
|
|
echo $foo
|
|
#CHECK: t
|
|
|
|
# read -z tests
|
|
echo -n testing | read -lz foo
|
|
echo $foo
|
|
#CHECK: testing
|
|
echo -n 'test ing' | read -lz foo
|
|
echo $foo
|
|
#CHECK: test ing
|
|
echo newline | read -lz foo
|
|
echo $foo
|
|
#CHECK: newline
|
|
#CHECK:
|
|
echo -n 'test ing' | read -lz foo bar
|
|
print_vars foo bar
|
|
#CHECK: 1 'test' 1 'ing'
|
|
echo -ne 'test\0ing' | read -lz foo bar
|
|
print_vars foo bar
|
|
#CHECK: 1 'test' 1 ''
|
|
echo -ne 'foo\nbar' | read -lz foo bar
|
|
print_vars foo bar
|
|
#CHECK: 1 'foo' 1 'bar'
|
|
echo -ne 'foo\nbar\0baz\nquux' | while read -lza foo
|
|
print_vars foo
|
|
end
|
|
#CHECK: 2 'foo' 'bar'
|
|
#CHECK: 2 'baz' 'quux'
|
|
|
|
# Chunked read tests
|
|
set -l path /tmp/fish_chunked_read_test.txt
|
|
set -l longstr (seq 1024 | string join ',')
|
|
echo -n $longstr >$path
|
|
read -l longstr2 <$path
|
|
test "$longstr" = "$longstr2"
|
|
and echo "Chunked reads test pass"
|
|
or echo "Chunked reads test failure: long strings don't match!"
|
|
rm $path
|
|
#CHECK: Chunked reads test pass
|
|
|
|
# ==========
|
|
# The following tests verify that `read` correctly handles the limit on the
|
|
# number of bytes consumed.
|
|
#
|
|
set fish_read_limit 8192
|
|
set line abcdefghijklmnopqrstuvwxyz
|
|
|
|
# Ensure the `read` command terminates if asked to read too much data. The var
|
|
# should be empty. We throw away any data we read if it exceeds the limit on
|
|
# what we consider reasonable.
|
|
yes $line | head -c (math "1 + $fish_read_limit") | read --null x
|
|
if test $status -ne 122
|
|
echo reading too much data did not terminate with failure status
|
|
end
|
|
# The read var should be defined but not have any elements when the read
|
|
# aborts due to too much data.
|
|
set -q x
|
|
or echo reading too much data did not define the var
|
|
set -q x[1]
|
|
and echo reading too much data resulted in a var with unexpected data
|
|
|
|
# Ensure the `read` command terminates if asked to read too much data even if
|
|
# given an explicit limit. The var should be empty. We throw away any data we
|
|
# read if it exceeds the limit on what we consider reasonable.
|
|
yes $line | read --null --nchars=(math "$fish_read_limit + 1") x
|
|
if test $status -ne 122
|
|
echo reading too much data did not terminate with failure status
|
|
end
|
|
set -q x
|
|
or echo reading too much data with --nchars did not define the var
|
|
set -q x[1]
|
|
and echo reading too much data with --nchars resulted in a var with unexpected data
|
|
|
|
# Now do the opposite of the previous test and confirm we can read reasonable
|
|
# amounts of data.
|
|
echo $line | read x
|
|
if test $status -ne 0
|
|
echo the read of a reasonable amount of data failed unexpectedly
|
|
end
|
|
set exp_length (string length $x)
|
|
set act_length (string length $line)
|
|
if test $exp_length -ne $act_length
|
|
echo reading a reasonable amount of data failed the length test
|
|
echo expected length $exp_length, actual length $act_length
|
|
end
|
|
|
|
# Confirm we can read exactly up to the limit.
|
|
yes $line | read --null --nchars $fish_read_limit x
|
|
if test $status -ne 0
|
|
echo the read of the max amount of data with --nchars failed unexpectedly
|
|
end
|
|
if test (string length "$x") -ne $fish_read_limit
|
|
echo reading the max amount of data with --nchars failed the length test
|
|
end
|
|
|
|
# Same as previous test but limit the amount of data fed to `read` rather than
|
|
# using the `--nchars` flag.
|
|
yes $line | head -c $fish_read_limit | read --null x
|
|
if test $status -ne 0
|
|
echo the read of the max amount of data failed unexpectedly
|
|
end
|
|
if test (string length "$x") -ne $fish_read_limit
|
|
echo reading with a limited amount of input data failed the length test
|
|
end
|
|
|
|
# Confirm reading non-interactively works -- \#4206 regression
|
|
echo abc\ndef | $fish -i -c 'read a; read b; set --show a; set --show b'
|
|
#CHECK: $a: set in global scope, unexported, with 1 elements
|
|
#CHECK: $a[1]: |abc|
|
|
#CHECK: $b: set in global scope, unexported, with 1 elements
|
|
#CHECK: $b[1]: |def|
|
|
|
|
# Test --delimiter (and $IFS, for now)
|
|
echo a=b | read -l foo bar
|
|
echo $foo
|
|
echo $bar
|
|
#CHECK: a=b
|
|
|
|
# Delimiter =
|
|
echo a=b | read -l -d = foo bar
|
|
echo $foo
|
|
#CHECK: a
|
|
echo $bar
|
|
#CHECK: b
|
|
|
|
# Delimiter empty
|
|
echo a=b | read -l -d '' foo bar baz
|
|
echo $foo
|
|
#CHECK: a
|
|
echo $bar
|
|
#CHECK: =
|
|
echo $baz
|
|
#CHECK: b
|
|
|
|
# IFS empty string
|
|
set -l IFS ''
|
|
echo a=b | read -l foo bar baz
|
|
echo $foo
|
|
#CHECK: a
|
|
echo $bar
|
|
#CHECK: =
|
|
echo $baz
|
|
#CHECK: b
|
|
|
|
# IFS unset
|
|
set -e IFS
|
|
echo a=b | read -l foo bar baz
|
|
echo $foo
|
|
#CHECK: a=b
|
|
echo $bar
|
|
#CHECK:
|
|
echo $baz
|
|
#CHECK:
|
|
|
|
# Delimiter =
|
|
echo a=b | read -l -d = foo bar baz
|
|
echo $foo
|
|
#CHECK: a
|
|
echo $bar
|
|
#CHECK: b
|
|
echo $baz
|
|
#CHECK:
|
|
|
|
# Multi-char delimiters with -d
|
|
echo a...b...c | read -l -d "..." a b c
|
|
echo $a
|
|
#CHECK: a
|
|
echo $b
|
|
#CHECK: b
|
|
echo $c
|
|
#CHECK: c
|
|
# Multi-char delimiters with IFS
|
|
begin
|
|
set -l IFS "..."
|
|
echo a...b...c | read -l a b c
|
|
echo $a
|
|
echo $b
|
|
echo $c
|
|
end
|
|
#CHECK: a
|
|
#CHECK: b
|
|
#CHECK: ..c
|
|
|
|
# At one point, whatever was read was printed _before_ banana
|
|
echo banana (echo sausage | read)
|
|
echo 'a | b' | read -lt a b c
|
|
#CHECK: banana sausage
|
|
|
|
echo a $a
|
|
echo b $b
|
|
echo c $c
|
|
# CHECK: a a
|
|
# CHECK: b |
|
|
# CHECK: c b
|
|
|
|
echo 'a"foo bar"b' | read -lt a b c
|
|
|
|
echo a \'$a\'
|
|
echo b $b
|
|
echo c $c
|
|
# CHECK: a 'afoo barb'
|
|
# CHECK: b
|
|
# CHECK: c
|
|
|
|
function function-scoped-read
|
|
echo foo | read --function skamtebord
|
|
set -S skamtebord
|
|
begin
|
|
echo bar | read skamtebord
|
|
echo baz | read -f craaab
|
|
end
|
|
set -S skamtebord
|
|
set -S craaab
|
|
end
|
|
|
|
function-scoped-read
|
|
# CHECK: $skamtebord: set in local scope, unexported, with 1 elements
|
|
# CHECK: $skamtebord[1]: |foo|
|
|
# CHECK: $skamtebord: set in local scope, unexported, with 1 elements
|
|
# CHECK: $skamtebord[1]: |bar|
|
|
# CHECK: $craaab: set in local scope, unexported, with 1 elements
|
|
# CHECK: $craaab[1]: |baz|
|
|
|
|
echo foo\nbar\nbaz | begin
|
|
read -l foo
|
|
read -l bar
|
|
cat
|
|
# CHECK: baz
|
|
echo $bar
|
|
# CHECK: bar
|
|
end
|
|
|
|
begin
|
|
echo 1
|
|
echo 2
|
|
end | read -l --line foo bar
|
|
echo $foo $bar
|
|
# CHECK: 1 2
|
|
|
|
echo foo | read status
|
|
# CHECKERR: read: status: cannot overwrite read-only variable
|
|
# CHECKERR: {{.*}}read.fish (line {{\d+}}):
|
|
# CHECKERR: echo foo | read status
|
|
# CHECKERR: ^
|
|
# CHECKERR: (Type 'help read' for related documentation)
|
|
echo read $status
|
|
# CHECK: read 2
|
|
|
|
echo ' foo' | read -n 1 -la var
|
|
set -S var
|
|
#CHECK: $var: set in local scope, unexported, with 0 elements
|
|
|
|
echo foo | read -n -1
|
|
# CHECKERR: read: -1: invalid integer
|
|
# CHECKERR: {{.*}}read.fish (line {{\d+}}):
|
|
# CHECKERR: echo foo | read -n -1
|
|
# CHECKERR: ^
|
|
# CHECKERR: (Type 'help read' for related documentation)
|