From a6062c4cdd2d03f7938d6312bd56c99c8b2b56a8 Mon Sep 17 00:00:00 2001 From: wyahiro Date: Thu, 3 Jan 2019 23:03:22 +0900 Subject: [PATCH 0001/1732] improved completion for ant --- share/completions/ant.fish | 33 ++++++++ .../__fish_complete_ant_targets.fish | 76 ++++++++++++++++--- .../functions/__fish_filter_ant_targets.fish | 3 - 3 files changed, 97 insertions(+), 15 deletions(-) delete mode 100644 share/functions/__fish_filter_ant_targets.fish diff --git a/share/completions/ant.fish b/share/completions/ant.fish index a5448c4a6..82b82a7a0 100644 --- a/share/completions/ant.fish +++ b/share/completions/ant.fish @@ -1,3 +1,36 @@ +# Apache Ant (1.9.5) completion for Fish Shell. +# completion for ant targets complete -x -c ant -a "(__fish_complete_ant_targets)" +# Script Options: +complete -f -c ant -l help -l h -d 'print help message and ant help' +complete -f -c ant -l noconfig -d 'suppress sourcing of /etc/ant.conf, $HOME/.ant/ant.conf, and $HOME/.antrc configuration files' +complete -f -c ant -l usejikes -d 'enable use of jikes by default, unless set explicitly in configuration files' +complete -f -c ant -l execdebug -d 'print ant exec line generated by this launch script' +# Options: +complete -f -c ant -o help -s h -d 'print help message and exit' +complete -f -c ant -o projecthelp -s p -d 'print project help information and exit' +complete -f -c ant -o version -d 'print the version information and exit' +complete -f -c ant -o diagnostics -d 'print information that might be helpful to diagnose or report problems and exit' +complete -f -c ant -o quiet -s q -d 'be extra quiet' +complete -f -c ant -o silent -s S -d 'print nothing but task outputs and build failures' +complete -f -c ant -o verbose -s v -d 'be extra verbose' +complete -f -c ant -o debug -s d -d 'print debugging information' +complete -f -c ant -o emacs -s e -d 'produce logging information without adornments' +complete -f -c ant -o noinput -d 'do not allow interactive input' +complete -f -c ant -s D -d 'use value for given property like -D=' +complete -f -c ant -o keep-going -s k -d 'execute all targets that do not depend on failed target(s)' +complete -f -c ant -o nouserlib -d 'Run ant without using the jar files from ${user.home}/.ant/lib' +complete -f -c ant -o noclasspath -d 'Run ant without using CLASSPATH' +complete -f -c ant -o autoproxy -d 'Java1.5+: use the OS proxy settings' +complete -r -c ant -o lib -d 'specifies a path to search for jars and classes' +complete -r -c ant -o logfile -s l -d 'use given file for log' +complete -r -c ant -o logger -d 'the class which is to perform logging' +complete -r -c ant -o listener -d 'add an instance of class as a project listener' +complete -r -c ant -o buildfile -o file -s f -d 'use given buildfile' +complete -r -c ant -o propertyfile -d 'load all properties from file with -D properties taking precedence' +complete -r -c ant -o inputhandler -d 'the class which will handle input requests' +complete -r -c ant -o find -s s -d '(s)earch for buildfile towards the root of the filesystem and use it' +complete -r -c ant -o nice -d 'A niceness value for the main thread: 1 (lowest) to 10 (highest); 5 is the default' +complete -r -c ant -o main -d 'override Ant\'s normal entry point' diff --git a/share/functions/__fish_complete_ant_targets.fish b/share/functions/__fish_complete_ant_targets.fish index e93b855c6..f7324006c 100644 --- a/share/functions/__fish_complete_ant_targets.fish +++ b/share/functions/__fish_complete_ant_targets.fish @@ -1,16 +1,68 @@ function __fish_complete_ant_targets -d "Print list of targets from build.xml and imported files" - set -l buildfile "build.xml" - if test -f $buildfile - # show ant targets - __fish_filter_ant_targets $buildfile - - # find files with buildfile - set files (sed -n "s/^.*]* file=[\"']\([^\"']*\)[\"'].*\$/\1/p" < $buildfile) - - # iterate through files and display their targets - for file in $files - - __fish_filter_ant_targets $file + function __filter_xml_start_tag -d "Filter xml start-tags in a buildfile" + set -l buildfile $argv[1] # full path to buildfile + set -l tag_pattern $argv[2] # regex pattern for tagname + # regex to filter start-tags ignoring newlines and '>' in attr values + # https://www.debuggex.com/r/wRgxHE1yTIgnjfNz + string join ' ' <$buildfile | string match -ar "<(?:$tag_pattern)(?:[^>\"']*?(?:(?:'[^']*?')|(?:\"[^\"]*\"))?)*?>" + end + function __filter_xml_attr_value -d "Filter xml attr value in a start-tag" + set -l tag $argv[1] # start-tag + set -l attr $argv[2] # attr name + # regex to filter attr values ignoring (single|double) quotes in attr values + # https://www.debuggex.com/r/x7lhtLJSP4msleik + string replace -rf "^.*$attr=((?:'(?:.*?)')|(?:\"(?:.*?)\")).*\$" '$1' $tag | string trim -c='"\'' + end + function __get_buildfile -d "Get a buildfile that will be used by ant" + set -l tokens $argv # tokens from 'commandline -co' + set -l prev $tokens[1] + set -l buildfile "build.xml" + for token in $argv[2..-1] + switch $prev + case -buildfile -file -f + set buildfile (eval echo $token) + end + set prev $token + end + # return last one + echo $buildfile + end + function __parse_ant_targets -d "Parse ant targets in the given build file" + set -l buildfile $argv[1] # full path to buildfile + set -l targets (__filter_xml_start_tag $buildfile 'target|extension-point') + for target in $targets + set -l target_name (__filter_xml_attr_value $target 'name') + if [ $status -eq 0 ] + set -l target_description (__filter_xml_attr_value $target 'description') + if [ $status -eq 0 ] + echo $target_name\t$target_description + else + echo $target_name + end + end end end + function __get_ant_targets -d "Get ant targets recursively" + set -l buildfile $argv[1] # full path to buildfile + __parse_ant_targets $buildfile + + set -l basedir (string split -r -m 1 / $buildfile)[1] + set -l imports (__filter_xml_start_tag $buildfile 'import') + for import in $imports + set -l filepath (__filter_xml_attr_value $import 'file') + # Set basedir if $filepath is not a full path + if string match -rvq '^/.*' $filepath + set filename $basedir/$filepath + end + if [ -f $filepath ] + __get_ant_targets $filepath + end + end + end + + set -l tokens (commandline -co) + set -l buildfile (realpath -eq $buildfile (__get_buildfile $tokens)) + if [ $status -eq 0 ] + __get_ant_targets $buildfile + end end diff --git a/share/functions/__fish_filter_ant_targets.fish b/share/functions/__fish_filter_ant_targets.fish deleted file mode 100644 index 242cdb0bc..000000000 --- a/share/functions/__fish_filter_ant_targets.fish +++ /dev/null @@ -1,3 +0,0 @@ -function __fish_filter_ant_targets -d "Display targets within an ant build.xml file" - sed -n "s/^.*]* name=[\"']\([^\"']*\)[\"'].*\$/\1/p" <$argv[1] -end From 48ed82b3f3590e415a955d4a4e97095a3fd377e3 Mon Sep 17 00:00:00 2001 From: wyahiro Date: Thu, 3 Jan 2019 23:33:21 +0900 Subject: [PATCH 0002/1732] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 708f924fc..9a8e0acb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ - nothing yet... - Lots of improvements to completions. - fish_clipboard_* now supports wayland by means of [wl-clipboard](https://github.com/bugaevc/wl-clipboard). - + - Improved completion for `ant`. --- # fish 3.0.0 (released December 28, 2018) From 078907ef9dbe7ca3ea4787ebf1f8ceb5771c14ee Mon Sep 17 00:00:00 2001 From: wyahiro Date: Thu, 3 Jan 2019 23:59:56 +0900 Subject: [PATCH 0003/1732] update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a8e0acb1..c08e1812a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ - nothing yet... - Lots of improvements to completions. - fish_clipboard_* now supports wayland by means of [wl-clipboard](https://github.com/bugaevc/wl-clipboard). - - Improved completion for `ant`. + - Improved completion for `ant` (#5475). --- # fish 3.0.0 (released December 28, 2018) From 480e95147cc375df9967568fbeac7f5c32bf0184 Mon Sep 17 00:00:00 2001 From: wyahiro Date: Sun, 13 Jan 2019 21:36:05 +0900 Subject: [PATCH 0004/1732] use cache file for ant targets --- share/completions/ant.fish | 2 +- .../__fish_complete_ant_targets.fish | 68 ++++++++----------- 2 files changed, 28 insertions(+), 42 deletions(-) diff --git a/share/completions/ant.fish b/share/completions/ant.fish index 82b82a7a0..7436876cb 100644 --- a/share/completions/ant.fish +++ b/share/completions/ant.fish @@ -1,7 +1,7 @@ # Apache Ant (1.9.5) completion for Fish Shell. # completion for ant targets -complete -x -c ant -a "(__fish_complete_ant_targets)" +complete -x -c ant -a "(__fish_complete_ant_targets (commandline -co))" # Script Options: complete -f -c ant -l help -l h -d 'print help message and ant help' diff --git a/share/functions/__fish_complete_ant_targets.fish b/share/functions/__fish_complete_ant_targets.fish index f7324006c..d3013bb7b 100644 --- a/share/functions/__fish_complete_ant_targets.fish +++ b/share/functions/__fish_complete_ant_targets.fish @@ -1,18 +1,4 @@ function __fish_complete_ant_targets -d "Print list of targets from build.xml and imported files" - function __filter_xml_start_tag -d "Filter xml start-tags in a buildfile" - set -l buildfile $argv[1] # full path to buildfile - set -l tag_pattern $argv[2] # regex pattern for tagname - # regex to filter start-tags ignoring newlines and '>' in attr values - # https://www.debuggex.com/r/wRgxHE1yTIgnjfNz - string join ' ' <$buildfile | string match -ar "<(?:$tag_pattern)(?:[^>\"']*?(?:(?:'[^']*?')|(?:\"[^\"]*\"))?)*?>" - end - function __filter_xml_attr_value -d "Filter xml attr value in a start-tag" - set -l tag $argv[1] # start-tag - set -l attr $argv[2] # attr name - # regex to filter attr values ignoring (single|double) quotes in attr values - # https://www.debuggex.com/r/x7lhtLJSP4msleik - string replace -rf "^.*$attr=((?:'(?:.*?)')|(?:\"(?:.*?)\")).*\$" '$1' $tag | string trim -c='"\'' - end function __get_buildfile -d "Get a buildfile that will be used by ant" set -l tokens $argv # tokens from 'commandline -co' set -l prev $tokens[1] @@ -27,42 +13,42 @@ function __fish_complete_ant_targets -d "Print list of targets from build.xml an # return last one echo $buildfile end - function __parse_ant_targets -d "Parse ant targets in the given build file" + function __parse_ant_targets_from_projecthelp -d "Parse ant targets from projecthelp" set -l buildfile $argv[1] # full path to buildfile - set -l targets (__filter_xml_start_tag $buildfile 'target|extension-point') + set -l targets (ant -p -debug -f $buildfile 2> /dev/null | string match -r '^\s\S+.*$' $projecthelp) for target in $targets - set -l target_name (__filter_xml_attr_value $target 'name') - if [ $status -eq 0 ] - set -l target_description (__filter_xml_attr_value $target 'description') - if [ $status -eq 0 ] - echo $target_name\t$target_description - else - echo $target_name - end + set -l tokens (string match -r '^\s([[:graph:]]+)(?:\s+([[:print:]]+))?' "$target") + if [ (count $tokens) -ge 3 ] + echo $tokens[2]\t$tokens[3] + else if [ (count $tokens) -ge 2 ] + echo $tokens[2] end end end - function __get_ant_targets -d "Get ant targets recursively" + function __get_ant_targets_from_projecthelp -d "Get ant targets from projecthelp" set -l buildfile $argv[1] # full path to buildfile - __parse_ant_targets $buildfile - set -l basedir (string split -r -m 1 / $buildfile)[1] - set -l imports (__filter_xml_start_tag $buildfile 'import') - for import in $imports - set -l filepath (__filter_xml_attr_value $import 'file') - # Set basedir if $filepath is not a full path - if string match -rvq '^/.*' $filepath - set filename $basedir/$filepath - end - if [ -f $filepath ] - __get_ant_targets $filepath - end + set -l cache_dir + if [ \( -n $__fish_user_data_dir \) -a \( -d $__fish_user_data_dir \) ] + set cache_dir $__fish_user_data_dir/ant_completions + else + set cache_dir "$HOME/.local/share/fish/ant_completions" end + mkdir -p $cache_dir + + set -l cache_file $cache_dir/(string escape --style=var $buildfile) + if [ ! -s $cache_file ] + # generate cache file if empty + __parse_ant_targets_from_projecthelp $buildfile > $cache_file + end + + cat $cache_file end - set -l tokens (commandline -co) - set -l buildfile (realpath -eq $buildfile (__get_buildfile $tokens)) - if [ $status -eq 0 ] - __get_ant_targets $buildfile + set -l tokens $argv + if not set -l buildfile (realpath -eq $buildfile (__get_buildfile $tokens)) + return 1 # return nothing if buildfile does not exist end + + __get_ant_targets_from_projecthelp $buildfile end From 71f15f70ea90c2fc447b2202ff9e242268c50fee Mon Sep 17 00:00:00 2001 From: wyahiro Date: Mon, 14 Jan 2019 13:08:29 +0900 Subject: [PATCH 0005/1732] Fixed logic for cache file generation --- share/functions/__fish_complete_ant_targets.fish | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/share/functions/__fish_complete_ant_targets.fish b/share/functions/__fish_complete_ant_targets.fish index d3013bb7b..0b50a39da 100644 --- a/share/functions/__fish_complete_ant_targets.fish +++ b/share/functions/__fish_complete_ant_targets.fish @@ -15,8 +15,9 @@ function __fish_complete_ant_targets -d "Print list of targets from build.xml an end function __parse_ant_targets_from_projecthelp -d "Parse ant targets from projecthelp" set -l buildfile $argv[1] # full path to buildfile - set -l targets (ant -p -debug -f $buildfile 2> /dev/null | string match -r '^\s\S+.*$' $projecthelp) + set -l targets (ant -p -debug -f $buildfile 2> /dev/null | string match -r '^\s[[:graph:]].*$') for target in $targets + # Use [[:graph:]] and [[:print:]] to ignore ANSI escape code set -l tokens (string match -r '^\s([[:graph:]]+)(?:\s+([[:print:]]+))?' "$target") if [ (count $tokens) -ge 3 ] echo $tokens[2]\t$tokens[3] @@ -28,16 +29,14 @@ function __fish_complete_ant_targets -d "Print list of targets from build.xml an function __get_ant_targets_from_projecthelp -d "Get ant targets from projecthelp" set -l buildfile $argv[1] # full path to buildfile - set -l cache_dir - if [ \( -n $__fish_user_data_dir \) -a \( -d $__fish_user_data_dir \) ] - set cache_dir $__fish_user_data_dir/ant_completions - else - set cache_dir "$HOME/.local/share/fish/ant_completions" + if [ \( -z "$XDG_CACHE_HOME" \) -o \( ! -d "$XDG_CACHE_HOME" \) ] + set XDG_CACHE_HOME "$HOME/.cache/" end + set -l cache_dir "$XDG_CACHE_HOME/fish/ant_completions" mkdir -p $cache_dir - set -l cache_file $cache_dir/(string escape --style=var $buildfile) - if [ ! -s $cache_file ] + set -l cache_file $cache_dir/(fish_md5 -s $buildfile) + if [ ! -s "$cache_file" ] # generate cache file if empty __parse_ant_targets_from_projecthelp $buildfile > $cache_file end From 2c52c5285d12a10f6fed243e75c6b013fb7ccb89 Mon Sep 17 00:00:00 2001 From: wyahiro Date: Thu, 17 Jan 2019 16:32:57 +0900 Subject: [PATCH 0006/1732] Fix fail back value for XDG_CACHE_HOME --- share/functions/__fish_complete_ant_targets.fish | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/share/functions/__fish_complete_ant_targets.fish b/share/functions/__fish_complete_ant_targets.fish index 0b50a39da..3203b2060 100644 --- a/share/functions/__fish_complete_ant_targets.fish +++ b/share/functions/__fish_complete_ant_targets.fish @@ -30,8 +30,9 @@ function __fish_complete_ant_targets -d "Print list of targets from build.xml an set -l buildfile $argv[1] # full path to buildfile if [ \( -z "$XDG_CACHE_HOME" \) -o \( ! -d "$XDG_CACHE_HOME" \) ] - set XDG_CACHE_HOME "$HOME/.cache/" + set XDG_CACHE_HOME "$HOME/.cache" end + set -l cache_dir "$XDG_CACHE_HOME/fish/ant_completions" mkdir -p $cache_dir From 9a7079190d01c4f831d35c3afd4af61a6dbe61ba Mon Sep 17 00:00:00 2001 From: wyahiro Date: Fri, 18 Jan 2019 10:24:14 +0900 Subject: [PATCH 0007/1732] change validation of buildfile --- share/functions/__fish_complete_ant_targets.fish | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) mode change 100644 => 100755 share/functions/__fish_complete_ant_targets.fish diff --git a/share/functions/__fish_complete_ant_targets.fish b/share/functions/__fish_complete_ant_targets.fish old mode 100644 new mode 100755 index 3203b2060..3c216b044 --- a/share/functions/__fish_complete_ant_targets.fish +++ b/share/functions/__fish_complete_ant_targets.fish @@ -46,7 +46,8 @@ function __fish_complete_ant_targets -d "Print list of targets from build.xml an end set -l tokens $argv - if not set -l buildfile (realpath -eq $buildfile (__get_buildfile $tokens)) + set -l buildfile (realpath -eq $buildfile (__get_buildfile $tokens)) + if [ $status -ne 0 ] return 1 # return nothing if buildfile does not exist end From 65d4f1b74e166250cf1b29386e431058971224a3 Mon Sep 17 00:00:00 2001 From: wyahiro Date: Mon, 21 Jan 2019 16:35:48 +0900 Subject: [PATCH 0008/1732] Format CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36503d94a..5f9070a9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ - fish_clipboard_* now supports wayland by means of [wl-clipboard](https://github.com/bugaevc/wl-clipboard). - mandoc can now be used to format the output from `--help` if nroff is not installed + +======= # fish 3.0.1 ### Fixes and improvements @@ -23,6 +25,7 @@ - exec now behaves properly inside functions (#5449) - while loops now evaluate to the last executed command in the loop body (or zero if the body was empty), matching POSIX semantics. + # fish 3.0.0 (released December 28, 2018) fish 3 is a major release, which introduces some breaking changes alongside improved functionality. Although most existing scripts will continue to work, they should be reviewed against the list contained in the 3.0b1 release notes below. From 0071ad040940baf82c9c8192e76fae9971571d16 Mon Sep 17 00:00:00 2001 From: zabereer Date: Tue, 26 Feb 2019 05:59:46 +0000 Subject: [PATCH 0009/1732] add __fish_status_to_signal.fish and __fish_pipestatus_with_signal.fish --- .../__fish_pipestatus_with_signal.fish | 5 +++++ share/functions/__fish_status_to_signal.fish | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 share/functions/__fish_pipestatus_with_signal.fish create mode 100644 share/functions/__fish_status_to_signal.fish diff --git a/share/functions/__fish_pipestatus_with_signal.fish b/share/functions/__fish_pipestatus_with_signal.fish new file mode 100644 index 000000000..e85d1b79c --- /dev/null +++ b/share/functions/__fish_pipestatus_with_signal.fish @@ -0,0 +1,5 @@ +function __fish_pipestatus_with_signal --description "Print arguments from \$pipestatus replacing values with signal names where appropriate" + for pstat in $argv + echo (__fish_status_to_signal $pstat) + end +end diff --git a/share/functions/__fish_status_to_signal.fish b/share/functions/__fish_status_to_signal.fish new file mode 100644 index 000000000..de07dcb64 --- /dev/null +++ b/share/functions/__fish_status_to_signal.fish @@ -0,0 +1,22 @@ +function __fish_status_to_signal --description "Print signal name from argument (\$status), or just argument" + if test (count $argv) -ne 1 + echo "expected single argument as integer from \$status" >&2 + return 1 + end + + if test $argv[1] -gt 128 + set -l signals SIGHUP SIGINT SIGQUIT SIGILL SIGTRAP SIGABRT SIGBUS \ + SIGFPE SIGKILL SIGUSR1 SIGSEGV SIGUSR2 SIGPIPE SIGALRM \ + SIGTERM SIGSTKFLT SIGCHLD SIGCONT SIGSTOP SIGTSTP \ + SIGTTIN SIGTTOU SIGURG SIGXCPU SIGXFSZ SIGVTALRM \ + SIGPROF SIGWINCH SIGIO SIGPWR SIGSYS + set -l sigix (math $argv[1] - 128) + if test $sigix -le (count $signals) + echo $signals[$sigix] + return 0 + end + end + + echo $argv[1] + return 0 +end From 378b5d7295a1a42fa09fbfcd7df52c8f9338d700 Mon Sep 17 00:00:00 2001 From: zabereer Date: Tue, 26 Feb 2019 18:06:36 +0000 Subject: [PATCH 0010/1732] update classic_status.fish prompt to include $pipestatus --- .../web_config/sample_prompts/classic_status.fish | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/share/tools/web_config/sample_prompts/classic_status.fish b/share/tools/web_config/sample_prompts/classic_status.fish index 4023a717c..c117ab501 100644 --- a/share/tools/web_config/sample_prompts/classic_status.fish +++ b/share/tools/web_config/sample_prompts/classic_status.fish @@ -3,10 +3,23 @@ function fish_prompt --description "Write out the prompt" # Save our status + set -l last_pipestatus $pipestatus set -l last_status $status + # only output $pipestatus if there was a pipe and any part of it had non-zero exit status + # TODO maybe have a common function that returns true if all array elements match a certain value? + if test (count $last_pipestatus) -gt 1 + for pstat in $last_pipestatus + if test $pstat -ne 0 + set -l last_pipestatus_string (string join "|" (__fish_pipestatus_with_signal $last_pipestatus)) + printf "%s[%s]%s " (set_color yellow --bold) $last_pipestatus_string (set_color normal) + break + end + end + end + if test $last_status -ne 0 - printf "%s(%d)%s " (set_color red --bold) $last_status (set_color normal) + printf "%s(%s)%s " (set_color red --bold) (__fish_status_to_signal $last_status) (set_color normal) end set -l color_cwd From a6f91409633ae3e489149b0b4996dc2f10a1030c Mon Sep 17 00:00:00 2001 From: zabereer Date: Wed, 27 Feb 2019 05:39:17 +0000 Subject: [PATCH 0011/1732] remove redundant echo from __fish_pipestatus_with_signal.fish --- share/functions/__fish_pipestatus_with_signal.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/functions/__fish_pipestatus_with_signal.fish b/share/functions/__fish_pipestatus_with_signal.fish index e85d1b79c..b8c0fa35d 100644 --- a/share/functions/__fish_pipestatus_with_signal.fish +++ b/share/functions/__fish_pipestatus_with_signal.fish @@ -1,5 +1,5 @@ function __fish_pipestatus_with_signal --description "Print arguments from \$pipestatus replacing values with signal names where appropriate" for pstat in $argv - echo (__fish_status_to_signal $pstat) + __fish_status_to_signal $pstat end end From 8ebbe67ff1d0b02c55e7fa0ad0bd6b11bd1e7f7c Mon Sep 17 00:00:00 2001 From: zabereer Date: Wed, 27 Feb 2019 06:11:03 +0000 Subject: [PATCH 0012/1732] Use `string match` instead of `for` loop to simplify classic_status.fish --- .../web_config/sample_prompts/classic_status.fish | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/share/tools/web_config/sample_prompts/classic_status.fish b/share/tools/web_config/sample_prompts/classic_status.fish index c117ab501..0618fc9bd 100644 --- a/share/tools/web_config/sample_prompts/classic_status.fish +++ b/share/tools/web_config/sample_prompts/classic_status.fish @@ -7,15 +7,9 @@ function fish_prompt --description "Write out the prompt" set -l last_status $status # only output $pipestatus if there was a pipe and any part of it had non-zero exit status - # TODO maybe have a common function that returns true if all array elements match a certain value? - if test (count $last_pipestatus) -gt 1 - for pstat in $last_pipestatus - if test $pstat -ne 0 - set -l last_pipestatus_string (string join "|" (__fish_pipestatus_with_signal $last_pipestatus)) - printf "%s[%s]%s " (set_color yellow --bold) $last_pipestatus_string (set_color normal) - break - end - end + if test (count $last_pipestatus) -gt 1 && string match -qvr '^0$' $last_pipestatus + set -l last_pipestatus_string (string join "|" (__fish_pipestatus_with_signal $last_pipestatus)) + printf "%s[%s]%s " (set_color yellow --bold) $last_pipestatus_string (set_color normal) end if test $last_status -ne 0 From ead26881f05b496fe7988653b4239a04f988b278 Mon Sep 17 00:00:00 2001 From: zabereer Date: Thu, 28 Feb 2019 06:19:09 +0000 Subject: [PATCH 0013/1732] create __fish_print_pipestatus function to reduce code duplication in other prompts when adding `$pipestatus` --- share/functions/__fish_print_pipestatus.fish | 19 +++++++++++++++++++ .../sample_prompts/classic_status.fish | 6 +----- 2 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 share/functions/__fish_print_pipestatus.fish diff --git a/share/functions/__fish_print_pipestatus.fish b/share/functions/__fish_print_pipestatus.fish new file mode 100644 index 000000000..9110d92f5 --- /dev/null +++ b/share/functions/__fish_print_pipestatus.fish @@ -0,0 +1,19 @@ +function __fish_print_pipestatus --description "Print pipestatus for prompt" + # maybe these could be in global variables similar to __fish_color_status to allow + # users to set the variables to modify the braces/separator/color used + set -l left_brace $argv[1] + set -l right_brace $argv[2] + set -l separator $argv[3] + set -l brace_sep_color $argv[4] + set -l status_color $argv[5] + set -e argv[1 2 3 4 5] + + # only output $pipestatus if there was a pipe and any part of it had non-zero exit status + if set -q argv[2] && string match -qvr '^0$' $argv + set -l sep (set_color normal){$brace_sep_color}{$separator}(set_color normal){$status_color} + set -l last_pipestatus_string (string join "$sep" (__fish_pipestatus_with_signal $argv)) + printf "%s%s%s%s%s%s%s%s%s" $brace_sep_color $left_brace (set_color normal) \ + $status_color $last_pipestatus_string (set_color normal) $brace_sep_color \ + $right_brace (set_color normal) + end +end diff --git a/share/tools/web_config/sample_prompts/classic_status.fish b/share/tools/web_config/sample_prompts/classic_status.fish index 0618fc9bd..b84af5ebf 100644 --- a/share/tools/web_config/sample_prompts/classic_status.fish +++ b/share/tools/web_config/sample_prompts/classic_status.fish @@ -6,11 +6,7 @@ function fish_prompt --description "Write out the prompt" set -l last_pipestatus $pipestatus set -l last_status $status - # only output $pipestatus if there was a pipe and any part of it had non-zero exit status - if test (count $last_pipestatus) -gt 1 && string match -qvr '^0$' $last_pipestatus - set -l last_pipestatus_string (string join "|" (__fish_pipestatus_with_signal $last_pipestatus)) - printf "%s[%s]%s " (set_color yellow --bold) $last_pipestatus_string (set_color normal) - end + __fish_print_pipestatus "[" "] " "|" (set_color yellow) (set_color --bold yellow) $last_pipestatus if test $last_status -ne 0 printf "%s(%s)%s " (set_color red --bold) (__fish_status_to_signal $last_status) (set_color normal) From e157ba131b82f2e788a0656390b94b79acb21a3b Mon Sep 17 00:00:00 2001 From: zabereer Date: Thu, 28 Feb 2019 06:37:56 +0000 Subject: [PATCH 0014/1732] add `$pipestatus` to informative.fish prompt --- share/functions/__fish_print_pipestatus.fish | 6 +++--- share/tools/web_config/sample_prompts/informative.fish | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/share/functions/__fish_print_pipestatus.fish b/share/functions/__fish_print_pipestatus.fish index 9110d92f5..6851d7791 100644 --- a/share/functions/__fish_print_pipestatus.fish +++ b/share/functions/__fish_print_pipestatus.fish @@ -12,8 +12,8 @@ function __fish_print_pipestatus --description "Print pipestatus for prompt" if set -q argv[2] && string match -qvr '^0$' $argv set -l sep (set_color normal){$brace_sep_color}{$separator}(set_color normal){$status_color} set -l last_pipestatus_string (string join "$sep" (__fish_pipestatus_with_signal $argv)) - printf "%s%s%s%s%s%s%s%s%s" $brace_sep_color $left_brace (set_color normal) \ - $status_color $last_pipestatus_string (set_color normal) $brace_sep_color \ - $right_brace (set_color normal) + printf "%s%s%s%s%s%s%s%s%s%s" (set_color normal )$brace_sep_color $left_brace \ + (set_color normal) $status_color $last_pipestatus_string (set_color normal) \ + $brace_sep_color $right_brace (set_color normal) end end diff --git a/share/tools/web_config/sample_prompts/informative.fish b/share/tools/web_config/sample_prompts/informative.fish index 223a9a251..80a0cb3f0 100644 --- a/share/tools/web_config/sample_prompts/informative.fish +++ b/share/tools/web_config/sample_prompts/informative.fish @@ -4,6 +4,7 @@ function fish_prompt --description 'Write out the prompt' #Save the return status of the previous command + set -l last_pipestatus $pipestatus set stat $status if not set -q __fish_prompt_normal @@ -39,8 +40,8 @@ function fish_prompt --description 'Write out the prompt' if not set -q __fish_prompt_cwd set -g __fish_prompt_cwd (set_color $fish_color_cwd) end - - printf '[%s] %s%s@%s %s%s %s(%s)%s \f\r> ' (date "+%H:%M:%S") "$__fish_color_blue" $USER (prompt_hostname) "$__fish_prompt_cwd" "$PWD" "$__fish_color_status" "$stat" "$__fish_prompt_normal" + set -l pipestatus_string (__fish_print_pipestatus "[" "] " "|" (set_color yellow) (set_color --bold yellow) $last_pipestatus) + printf '[%s] %s%s@%s %s%s %s%s(%s)%s \f\r> ' (date "+%H:%M:%S") "$__fish_color_blue" $USER (prompt_hostname) "$__fish_prompt_cwd" "$PWD" "$pipestatus_string" "$__fish_color_status" "$stat" "$__fish_prompt_normal" end end From d5c18350a76d514b3c56cb9a683e30e2f5fe6f19 Mon Sep 17 00:00:00 2001 From: zabereer Date: Fri, 1 Mar 2019 19:55:28 +0000 Subject: [PATCH 0015/1732] use global variables for `$pipestatus` in prompts to allow users to customize the look --- share/functions/__fish_print_pipestatus.fish | 38 ++++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/share/functions/__fish_print_pipestatus.fish b/share/functions/__fish_print_pipestatus.fish index 6851d7791..ecd0ec989 100644 --- a/share/functions/__fish_print_pipestatus.fish +++ b/share/functions/__fish_print_pipestatus.fish @@ -1,19 +1,35 @@ function __fish_print_pipestatus --description "Print pipestatus for prompt" - # maybe these could be in global variables similar to __fish_color_status to allow - # users to set the variables to modify the braces/separator/color used - set -l left_brace $argv[1] - set -l right_brace $argv[2] - set -l separator $argv[3] - set -l brace_sep_color $argv[4] - set -l status_color $argv[5] + + # allow users to customize these variables + if not set -q __fish_prompt_pipestatus_left_brace + set -g __fish_prompt_pipestatus_left_brace $argv[1] + end + + if not set -q __fish_prompt_pipestatus_right_brace + set -g __fish_prompt_pipestatus_right_brace $argv[2] + end + + if not set -q __fish_prompt_pipestatus_separator + set -g __fish_prompt_pipestatus_separator $argv[3] + end + + if not set -q __fish_prompt_pipestatus_brace_sep_color + set -g __fish_prompt_pipestatus_brace_sep_color $argv[4] + end + + if not set -q __fish_prompt_pipestatus_color + set -g __fish_prompt_pipestatus_color $argv[5] + end + set -e argv[1 2 3 4 5] # only output $pipestatus if there was a pipe and any part of it had non-zero exit status if set -q argv[2] && string match -qvr '^0$' $argv - set -l sep (set_color normal){$brace_sep_color}{$separator}(set_color normal){$status_color} + set -l sep (set_color normal){$__fish_prompt_pipestatus_brace_sep_color}{$__fish_prompt_pipestatus_separator}(set_color normal){$__fish_prompt_pipestatus_color} set -l last_pipestatus_string (string join "$sep" (__fish_pipestatus_with_signal $argv)) - printf "%s%s%s%s%s%s%s%s%s%s" (set_color normal )$brace_sep_color $left_brace \ - (set_color normal) $status_color $last_pipestatus_string (set_color normal) \ - $brace_sep_color $right_brace (set_color normal) + printf "%s%s%s%s%s%s%s%s%s%s" (set_color normal) $__fish_prompt_pipestatus_brace_sep_color \ + $__fish_prompt_pipestatus_left_brace (set_color normal) $__fish_prompt_pipestatus_color \ + $last_pipestatus_string (set_color normal) $__fish_prompt_pipestatus_brace_sep_color \ + $__fish_prompt_pipestatus_right_brace (set_color normal) end end From 0923712e3e243cd9e67e9138df7a3e0e611b674b Mon Sep 17 00:00:00 2001 From: zabereer Date: Mon, 4 Mar 2019 18:14:42 +0000 Subject: [PATCH 0016/1732] add `$pipestatus` to informative_vcs.fish prompt --- share/tools/web_config/sample_prompts/informative_vcs.fish | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/share/tools/web_config/sample_prompts/informative_vcs.fish b/share/tools/web_config/sample_prompts/informative_vcs.fish index a9eeeace8..99645fdaa 100644 --- a/share/tools/web_config/sample_prompts/informative_vcs.fish +++ b/share/tools/web_config/sample_prompts/informative_vcs.fish @@ -4,6 +4,7 @@ function fish_prompt --description 'Write out the prompt' + set -l last_pipestatus $pipestatus set -l last_status $status if not set -q __fish_git_prompt_show_informative_status @@ -88,6 +89,9 @@ function fish_prompt --description 'Write out the prompt' printf '%s ' (fish_vcs_prompt) + set -l pipestatus_string (__fish_print_pipestatus "[" "] " "|" (set_color yellow) (set_color --bold yellow) $last_pipestatus) + echo -n "$pipestatus_string" + if not test $last_status -eq 0 set_color $fish_color_error echo -n "[$last_status] " From da2925bad74f53fcf0c2c20d886326a90df4b872 Mon Sep 17 00:00:00 2001 From: zabereer Date: Mon, 4 Mar 2019 18:25:18 +0000 Subject: [PATCH 0017/1732] add `$pipestatus` to classic_vcs.fish prompt --- share/tools/web_config/sample_prompts/classic_vcs.fish | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/share/tools/web_config/sample_prompts/classic_vcs.fish b/share/tools/web_config/sample_prompts/classic_vcs.fish index 01608b958..768e782d3 100644 --- a/share/tools/web_config/sample_prompts/classic_vcs.fish +++ b/share/tools/web_config/sample_prompts/classic_vcs.fish @@ -3,6 +3,7 @@ # vim: set noet: function fish_prompt --description 'Write out the prompt' + set -l last_pipestatus $pipestatus set -l last_status $status set -l normal (set_color normal) @@ -62,9 +63,9 @@ function fish_prompt --description 'Write out the prompt' set suffix '>' end - set -l prompt_status + set -l prompt_status (__fish_print_pipestatus "[" "] " "|" (set_color yellow) (set_color --bold yellow) $last_pipestatus) if test $last_status -ne 0 - set prompt_status ' ' (set_color $fish_color_status) "[$last_status]" "$normal" + set prompt_status " $prompt_status" (set_color $fish_color_status) "[$last_status]" "$normal" end echo -n -s (set_color $fish_color_user) "$USER" $normal @ (set_color $fish_color_host) (prompt_hostname) $normal ' ' (set_color $color_cwd) (prompt_pwd) $normal (fish_vcs_prompt) $normal $prompt_status $suffix " " From d71e39f7562e3b5a9f925b9486dae3bc33058e78 Mon Sep 17 00:00:00 2001 From: zabereer Date: Tue, 5 Mar 2019 18:19:57 +0000 Subject: [PATCH 0018/1732] Revert "use global variables for `$pipestatus` in prompts to allow users to customize the look" This reverts commit d5c18350a76d514b3c56cb9a683e30e2f5fe6f19. --- share/functions/__fish_print_pipestatus.fish | 38 ++++++-------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/share/functions/__fish_print_pipestatus.fish b/share/functions/__fish_print_pipestatus.fish index ecd0ec989..6851d7791 100644 --- a/share/functions/__fish_print_pipestatus.fish +++ b/share/functions/__fish_print_pipestatus.fish @@ -1,35 +1,19 @@ function __fish_print_pipestatus --description "Print pipestatus for prompt" - - # allow users to customize these variables - if not set -q __fish_prompt_pipestatus_left_brace - set -g __fish_prompt_pipestatus_left_brace $argv[1] - end - - if not set -q __fish_prompt_pipestatus_right_brace - set -g __fish_prompt_pipestatus_right_brace $argv[2] - end - - if not set -q __fish_prompt_pipestatus_separator - set -g __fish_prompt_pipestatus_separator $argv[3] - end - - if not set -q __fish_prompt_pipestatus_brace_sep_color - set -g __fish_prompt_pipestatus_brace_sep_color $argv[4] - end - - if not set -q __fish_prompt_pipestatus_color - set -g __fish_prompt_pipestatus_color $argv[5] - end - + # maybe these could be in global variables similar to __fish_color_status to allow + # users to set the variables to modify the braces/separator/color used + set -l left_brace $argv[1] + set -l right_brace $argv[2] + set -l separator $argv[3] + set -l brace_sep_color $argv[4] + set -l status_color $argv[5] set -e argv[1 2 3 4 5] # only output $pipestatus if there was a pipe and any part of it had non-zero exit status if set -q argv[2] && string match -qvr '^0$' $argv - set -l sep (set_color normal){$__fish_prompt_pipestatus_brace_sep_color}{$__fish_prompt_pipestatus_separator}(set_color normal){$__fish_prompt_pipestatus_color} + set -l sep (set_color normal){$brace_sep_color}{$separator}(set_color normal){$status_color} set -l last_pipestatus_string (string join "$sep" (__fish_pipestatus_with_signal $argv)) - printf "%s%s%s%s%s%s%s%s%s%s" (set_color normal) $__fish_prompt_pipestatus_brace_sep_color \ - $__fish_prompt_pipestatus_left_brace (set_color normal) $__fish_prompt_pipestatus_color \ - $last_pipestatus_string (set_color normal) $__fish_prompt_pipestatus_brace_sep_color \ - $__fish_prompt_pipestatus_right_brace (set_color normal) + printf "%s%s%s%s%s%s%s%s%s%s" (set_color normal )$brace_sep_color $left_brace \ + (set_color normal) $status_color $last_pipestatus_string (set_color normal) \ + $brace_sep_color $right_brace (set_color normal) end end From a634356bcca3845e5445d7a13e963d06b28bdc74 Mon Sep 17 00:00:00 2001 From: zabereer Date: Tue, 5 Mar 2019 18:25:16 +0000 Subject: [PATCH 0019/1732] remove redundant comment from __fish_print_pipestatus.fish --- share/functions/__fish_print_pipestatus.fish | 2 -- 1 file changed, 2 deletions(-) diff --git a/share/functions/__fish_print_pipestatus.fish b/share/functions/__fish_print_pipestatus.fish index 6851d7791..1cec49653 100644 --- a/share/functions/__fish_print_pipestatus.fish +++ b/share/functions/__fish_print_pipestatus.fish @@ -1,6 +1,4 @@ function __fish_print_pipestatus --description "Print pipestatus for prompt" - # maybe these could be in global variables similar to __fish_color_status to allow - # users to set the variables to modify the braces/separator/color used set -l left_brace $argv[1] set -l right_brace $argv[2] set -l separator $argv[3] From c633c06e11adace516cd8202916106f590cf1b05 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 6 Mar 2019 22:07:03 +0100 Subject: [PATCH 0020/1732] Guess emoji width via system wcwidth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since Unicode 9, the width of some characters changed to 2. Depending on the system, it might have support for it, or it might not. Instead of hardcoding specific glibc etc versions, we check what the system wcwidth says to "😃", U+1F603 "Grinning Face With Big Eyes". The intention is to, in most cases, make setting $fish_emoji_width unnecessary, but since it sets the "guessed_emoji_width", that variable still takes precedence if it is set. Unfortunately this approach has some caveats: - It relies on the locale being set to a unicode-supporting one. (C.UTF-8 is unfortunately not standard, so we can't use it) - It relies on the terminal's wcwidth having unicode9 support IFF the system wcwidth does. This is like #5722, but at runtime. The additional caveat is that we don't try to achieve a unicode locale, but since we re-run the heuristic when the locale changes (and we try to get a unicode locale), we should still often get the correct value. Plus if you use a C locale and your terminal still displays emoji, you've misconfigured your system. Fixes #5722. --- src/env.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/env.cpp b/src/env.cpp index 56da4dd20..b30ec18ed 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -561,16 +561,22 @@ static void guess_emoji_width() { version = strtod(narrow_version.c_str(), NULL); } - // iTerm2 defaults to Unicode 8 sizes. - // See https://gitlab.com/gnachman/iterm2/wikis/unicodeversionswitching if (term == L"Apple_Terminal" && version >= 400) { // Apple Terminal on High Sierra g_guessed_fish_emoji_width = 2; debug(2, "default emoji width: 2 for %ls", term.c_str()); - } else { + } else if (term == L"iTerm.app") { + // iTerm2 defaults to Unicode 8 sizes. + // See https://gitlab.com/gnachman/iterm2/wikis/unicodeversionswitching g_guessed_fish_emoji_width = 1; debug(2, "default emoji width: 1"); + } else { + // Default to whatever system wcwidth says to U+1F603, + // but only if it's at least 1. + int w = wcwidth(L'😃'); + g_guessed_fish_emoji_width = w > 0 ? w : 1; + debug(2, "default emoji width: %d", g_guessed_fish_emoji_width); } } @@ -849,6 +855,8 @@ static void handle_locale_change(const wcstring &op, const wcstring &var_name, e UNUSED(op); UNUSED(var_name); init_locale(vars); + // We need to re-guess emoji width because the locale might have changed to a multibyte one. + guess_emoji_width(); } static void handle_curses_change(const wcstring &op, const wcstring &var_name, env_stack_t &vars) { From 91e70e38e76f94e77106c61eec841ffb22cc509d Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Wed, 6 Mar 2019 13:52:20 -0800 Subject: [PATCH 0021/1732] Handle TERM_PROGRAM_VERSION with junk after the number. We only care about the major version number. Fixes #5725 --- share/functions/__fish_config_interactive.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/functions/__fish_config_interactive.fish b/share/functions/__fish_config_interactive.fish index 23ec79d64..a204b31d8 100644 --- a/share/functions/__fish_config_interactive.fish +++ b/share/functions/__fish_config_interactive.fish @@ -263,7 +263,7 @@ function __fish_config_interactive -d "Initializations that should be performed # Notify terminals when $PWD changes (issue #906). # VTE based terminals, Terminal.app, and iTerm.app (TODO) support this. - if test 0"$VTE_VERSION" -ge 3405 -o "$TERM_PROGRAM" = "Apple_Terminal" -a 0"$TERM_PROGRAM_VERSION" -ge 309 + if test 0"$VTE_VERSION" -ge 3405 -o "$TERM_PROGRAM" = "Apple_Terminal" -a (string match -r '\d+' 0"$TERM_PROGRAM_VERSION") -ge 309 function __update_cwd_osc --on-variable PWD --description 'Notify capable terminals when $PWD changes' if status --is-command-substitution || set -q INSIDE_EMACS return From 2b0b3d3193dcecde7b0c0b9ef4d30183a0b2b53c Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 7 Mar 2019 10:00:39 +0100 Subject: [PATCH 0022/1732] Outputter_t: Handle C locale like everything else This tried to skip conversion if the locale had MB_CUR_MAX == 1, but in doing so it just entered an infinite recursion (because writestr(wchar_t*) called writestr(wchar_t*)). Instead, just let wcstombs handle it. Fixes #5724. --- src/output.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/output.cpp b/src/output.cpp index d89a08d98..ce44afb77 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -395,12 +395,6 @@ int outputter_t::writech(wint_t ch) { void outputter_t::writestr(const wchar_t *str) { assert(str && "Empty input string"); - if (MB_CUR_MAX == 1) { - // Single-byte locale (C/POSIX/ISO-8859). - this->writestr(str); - return; - } - size_t len = wcstombs(0, str, 0); // figure amount of space needed if (len == (size_t)-1) { debug(1, L"Tried to print invalid wide character string"); From 1cd5b2f4e100cc18d70d3e37aca747a61ca42f3f Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 7 Mar 2019 10:02:39 +0100 Subject: [PATCH 0023/1732] Pass string length instead of recomputing This called `writestr(char*)`, which then just called `writestr(char*, strlen(char*))`, when it had the string length right there! --- src/output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output.cpp b/src/output.cpp index ce44afb77..581964101 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -410,7 +410,7 @@ void outputter_t::writestr(const wchar_t *str) { buffer = new char[len]; } wcstombs(buffer, str, len); - this->writestr(buffer); + this->writestr(buffer, len); if (buffer != static_buffer) delete[] buffer; } From b5b0e6804487ce912209ee5d418dd6ca3019bd92 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 7 Mar 2019 14:02:26 +0100 Subject: [PATCH 0024/1732] functions/seq: Stop using bc in the fallback Just to remove the dependency - performance is probably about the same. This is used, AFAICT, exclusively on OpenBSD (not Free or Net). CC @zanchey. --- share/functions/seq.fish | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/share/functions/seq.fish b/share/functions/seq.fish index 74104b81b..fe1eb5bd2 100644 --- a/share/functions/seq.fish +++ b/share/functions/seq.fish @@ -39,10 +39,18 @@ if not command -sq seq end end - if [ $step -ge 0 ] - echo "for( i=$from; i<=$to ; i+=$step ) i;" | bc + if test $step -ge 0 + set -l i $from + while test $i -le $to + echo $i + set i (math $i + $step) + end else - echo "for( i=$from; i>=$to ; i+=$step ) i;" | bc + set -l i $from + while test $i -ge $to + echo $i + set i (math $i + $step) + end end end end From e35a30de0a61e5d847c03cb0b166878a6837a730 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 7 Mar 2019 12:00:09 -0800 Subject: [PATCH 0025/1732] Add NSAppleEventsUsageDescription This is required to send Apple Events when built against the 10.14 SDK. Fixes #5727 --- osx/CMakeMacAppInfo.plist.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osx/CMakeMacAppInfo.plist.in b/osx/CMakeMacAppInfo.plist.in index 212143cfa..695625441 100644 --- a/osx/CMakeMacAppInfo.plist.in +++ b/osx/CMakeMacAppInfo.plist.in @@ -24,6 +24,8 @@ public.app-category.productivity LSMinimumSystemVersion 10.6 + NSAppleEventsUsageDescription + A Terminal window with the fish shell running in it will be opened. LSUIElement NSHumanReadableCopyright From bd5232e0e2cee2a79e05e0db1fd08aa7303ad1bc Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 7 Mar 2019 14:06:06 +0100 Subject: [PATCH 0026/1732] functions/seq: Fix negative numbers 25d83ed0d7104a2d95819463f835c5bced1ef864 (included in 3.0.0) added a `string` check that did not use `--`, so negative numbers were interpreted as options. Apparently nobody is using this. (Again, this is for the `seq` fallback used on OpenBSD) --- share/functions/seq.fish | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/share/functions/seq.fish b/share/functions/seq.fish index fe1eb5bd2..100b71722 100644 --- a/share/functions/seq.fish +++ b/share/functions/seq.fish @@ -33,7 +33,7 @@ if not command -sq seq end for i in $from $step $to - if not string match -rq '^-?[0-9]*([0-9]*|\.[0-9]+)$' $i + if not string match -rq -- '^-?[0-9]*([0-9]*|\.[0-9]+)$' $i printf (_ "%s: '%s' is not a number\n") seq $i return 1 end @@ -43,13 +43,13 @@ if not command -sq seq set -l i $from while test $i -le $to echo $i - set i (math $i + $step) + set i (math -- $i + $step) end else set -l i $from while test $i -ge $to echo $i - set i (math $i + $step) + set i (math -- $i + $step) end end end From 49ba7f8c01d3a7048c491c6899a78e9f5720e121 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 7 Mar 2019 14:30:01 +0100 Subject: [PATCH 0027/1732] Update CHANGELOG --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5a33add6..7a4063bc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,6 @@ ### Interactive improvements - Major improvements in performance and functionality to the 'sorin' sample prompt (#5411). -- Added completions for: - - nothing yet... -- Lots of improvements to completions. - fish_clipboard_* now supports wayland by means of [wl-clipboard](https://github.com/bugaevc/wl-clipboard). - mandoc can now be used to format the output from `--help` if nroff is not installed - New color options for the pager have been added (#5524). @@ -23,12 +20,16 @@ - The `path_helper` on macOS now only runs in login shells, matching the bash implementation. - `math` now accepts `--scale=max` for the maximum scale (#5579). - The `forward-bigword` binding now interacts correctly with autosuggestions (#5336) +- Fish now tries to guess if the system supports Unicode 9 (and displays emoji as wide), hopefully making setting $fish_emoji_width superfluous in most cases (#5722). +- Lots of improvements to completions. - Added completions for - `cf` - `bosh` + - `vagrant` ### For distributors and developers - The autotools-based build system and legacy Xcode build systems have been removed, leaving only the CMake build system. All distributors and developers must migrate to the CMake build. +- The doxygen-based documenation system has been removed and replaced with one based on sphinx. All distributors and developers must migrate to that. --- From 62526a3ac8e1b189d04032d7b997c5dd6968de75 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 8 Mar 2019 16:03:08 +0100 Subject: [PATCH 0028/1732] completions/git: Fix relative paths for older git If the first file presented was in the current directory, this would error out. Fixes #5728. [ci skip] --- share/completions/git.fish | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/share/completions/git.fish b/share/completions/git.fish index 067143253..3edea1aa2 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -272,7 +272,6 @@ function __fish_git_files # Cache the previous relative path because these are sorted, so we can reuse it # often for files in the same directory. set -l previous - set -l previousfile # Note that we can't use space as a delimiter between status and filename, because # the status can contain spaces - " M" is different from "M ". command git $git_opt status --porcelain -z $status_opt \ @@ -356,8 +355,14 @@ function __fish_git_files # Computing relative path by hand. set -l abs (string split / -- $relfile) # If it's in the same directory, we just need to change the filename. - if test "$abs[1..-2]" = "$previousfile[1..-2]" - set previous[-1] $abs[-1] + if test "$abs[1..-2]" = "$previous[1..-2]" + # If we didn't have a previous file, and the current file is in the current directory, + # this would error out. + # + # See #5728. + set -q previous[1] + and set previous[-1] $abs[-1] + or set previous $abs else set -l pwd_list $_pwd_list # Remove common prefix From 7ececa4c69e549613859026db19477e5cc6b5155 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 9 Mar 2019 07:11:43 -0800 Subject: [PATCH 0029/1732] dmesg completions for all the platforms + tweaks for Linux: shorter descriptions, suppress file completions + Add correct completions for macOS, NetBSD, FreeBSD, OpenBSD, DragonFly + Solaris dmesg has no options, so complete nothing there --- share/completions/dmesg.fish | 69 ++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/share/completions/dmesg.fish b/share/completions/dmesg.fish index 0b17de138..aa71bbdc8 100644 --- a/share/completions/dmesg.fish +++ b/share/completions/dmesg.fish @@ -1,20 +1,51 @@ -set -l levels '( __fish_complete_list , "echo emerg\nalert\ncrit\nerr\nwarn\nnotice\ninfo\ndebug" )' -complete -c dmesg -s C -l clear -d 'Clear the kernel ring buffer' -complete -c dmesg -s c -l read-clear -d 'Read and clear all messages' -complete -c dmesg -s D -l console-off -d 'Disable printing messages to console' -complete -c dmesg -s d -l show-delta -d 'Show time delta between printed messages' -complete -c dmesg -s E -l console-on -d 'Enable printing messages to console' -complete -c dmesg -s F -l file -d 'Use the file instead of the kernel log buffer' -complete -c dmesg -s f -l facility -d 'Restrict output to defined facilities' -xa '( __fish_complete_list , "echo kern\nuser\nmail\ndaemon\nauth\nsyslog\nlpr\nnews" )' -complete -c dmesg -s h -l help -d 'Display this help and exit' -complete -c dmesg -s k -l kernel -d 'Display kernel messages' -complete -c dmesg -s l -l level -d 'Restrict output to defined levels' -xa $levels -complete -c dmesg -s n -l console-level -d 'Set level of messages printed to console' -xa $levels -complete -c dmesg -s r -l raw -d 'Print the raw message buffer' -complete -c dmesg -s s -l buffer-size -d 'Buffer size to query the kernel ring buffer' -x -complete -c dmesg -s T -l ctime -d 'Show human readable timestamp ' -complete -c dmesg -s t -l notime -d 'Don\'t print messages timestamp' -complete -c dmesg -s u -l userspace -d 'Display userspace messages' -complete -c dmesg -s V -l version -d 'Output version information and exit' -complete -c dmesg -s x -l decode -d 'Decode facility and level to readable string' +complete -c dmesg -f -d 'Display system message buffer' +switch (uname -s) + # + # Solaris + # + case SunOS + exit 1 # no options, we are done + # + # Loonix dmesg + # + case Linux + set -l levels '( __fish_complete_list , "echo emerg\nalert\ncrit\nerr\nwarn\nnotice\ninfo\ndebug" )' + complete -c dmesg -s C -l clear -f -d'Clear kernel ring buffer' + complete -c dmesg -s c -l read-clear -f -d'Read & clear all msgs' + complete -c dmesg -s D -l console-off -f -d'Disable writing to console' + complete -c dmesg -s d -l show-delta -f -d'Show timestamp deltas' + complete -c dmesg -s E -l console-on -f -d'Enable writing to console' + complete -c dmesg -s F -l file -r -d'Use file instead of log buffer' + complete -c dmesg -s f -l facility -x -d'Only print for given facilities' -a '( __fish_complete_list , "echo kern\nuser\nmail\ndaemon\nauth\nsyslog\nlpr\nnews" )' + complete -c dmesg -s h -l help -f -d'Display help' + complete -c dmesg -s k -l kernel -f -d'Print kernel messages' + complete -c dmesg -s l -l level -x -d'Restrict output to given levels' -a $levels + complete -c dmesg -s n -l console-level -x -d'Adjust threshold to print to console' -a $levels + complete -c dmesg -s r -l raw -f -d'Print raw message buffer' + complete -c dmesg -s s -l buffer-size -x -d'Buffer size to query kernel' + complete -c dmesg -s T -l ctime -f -d'Human-readable timestamps' + complete -c dmesg -s t -l notime -f -d'Don\'t print timestamps' + complete -c dmesg -s u -l userspace -f -d'Print userspace messages' + complete -c dmesg -s V -l version -f -d'Show dmesg version' + complete -c dmesg -s x -l decode -f -d'Decode facility & level numbers' + exit 0 # done + # + # unique options specific BSDs have + # + case NetBSD + complete -c dmesg -s d -f -d'show timestamp deltas' + complete -c dmesg -s T -f -d'human-readable timestamps' + complete -c dmesg -s t -f -d'don\'t print timestamps' + case OpenBSD + complete -c dmesg -s S -f -d'display console message buffer-size' + case FreeBSD DragonFly + complete -c dmesg -s a -f -d'print all data in the message buffer' + complete -c dmesg -s c -f -d'clear kernel buffer after printing' +end + +# +# common BSD dmesg options (macOS only does these two) +# +complete -c dmesg -s M -r -d'get namelist values from given core' +complete -c dmesg -s N -r -d'get namelist from given kernel' From 5938f02db1123008f8ddf9e1d14fb51f31613b0f Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 9 Mar 2019 07:41:46 -0800 Subject: [PATCH 0030/1732] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a4063bc7..4d10fabb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,9 @@ ## Deprecations - The vcs-prompt functions have been renamed to names without double-underscore, so __fish_git_prompt is now fish_git_prompt, __fish_vcs_prompt is now fish_vcs_prompt, __fish_hg_prompt is now fish_hg_prompt and __fish_svn_prompt is now fish_svn_prompt. Shims at the old names have been added, and the variables have kept their old names (#5586). -## Notable fixes and improvements +## Notable Fixes and improvements - Add `$pipestatus` support +- macOS Mojave: fish.app can actually run (#5727), 10.14.4's Terminal.app no longer causes an error on launch (#5725) - `string split0` now returns 0 if it split something (#5701). ### Syntax changes and new commands From 3ac1c29f79dd5255bcc553a44e4ecccd3e2b9c1e Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 9 Mar 2019 07:54:50 -0800 Subject: [PATCH 0031/1732] cp completions: shorten descriptions Enough to fit two pager columns into a 80-wide terminal. --- share/completions/cp.fish | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/share/completions/cp.fish b/share/completions/cp.fish index e81ec8a7f..181b44bfc 100644 --- a/share/completions/cp.fish +++ b/share/completions/cp.fish @@ -41,27 +41,27 @@ else # BSD/macOS else complete -c cp -s R -d "Copy directories recursively" end - complete -c cp -s H -d "with -R: Follow symlinks in cp arguments" - complete -c cp -s L -d "with -R: Follow all symlinks" - complete -c cp -s P -d "with -R: Don't follow symlinks (default)" + complete -c cp -s H -d "-R: Follow symlink arguments" + complete -c cp -s L -d "-R: Follow all symlinks" + complete -c cp -s P -d "-R: Don't follow symlinks (default)" - complete -c cp -s f -d "Replace destination without confirmation" + complete -c cp -s f -d "Don't confirm to overwrite" complete -c cp -s i -d "Prompt before overwrite" not contains "$uname" SunOS OpenBSD NetBSD - and complete -c cp -s n -d "Don't overwrite existing files" + and complete -c cp -s n -d "Don't overwrite existing" - complete -c cp -s p -d "Preserve attributes of source file" + complete -c cp -s p -d "Preserve attributes of source" if [ "$uname" = SunOS ] exit 0 end - complete -c cp -s v -d "Print file names as files are copied" + complete -c cp -s v -d "Print filenames as they're copied" if [ "$uname" = OpenBSD ] exit 0 end complete -c cp -s a -d "Archive mode (-pPR)" if [ "$uname" = Darwin ] complete -c cp -s c -d "Clone using clonefile(2)" - complete -c cp -s X -d "Do not copy xattrs or resource forks" + complete -c cp -s X -d "Omit xattrs, resource forks" exit 0 end complete -c cp -s l -d "Hard link instead of copying" @@ -69,7 +69,7 @@ else # BSD/macOS complete -c cp -s N -d "Don't copy file flags" exit 0 end - complete -c cp -s x -d "Don't traverse file system mount points" + complete -c cp -s x -d "Don't traverse mount points" if [ "$uname" = FreeBSD ] complete -c cp -s s -d "Symlink instead of copying" end From 9b1fb6938e0e82ffea181e844540d1a426d22217 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 9 Mar 2019 17:57:49 +0100 Subject: [PATCH 0032/1732] Add __fish_anypython helper function This just finds the first usable python and echos it, so it can then be used. We have a few places where we use it and I'm about to add some more. --- share/functions/__fish_anypython.fish | 10 ++++++++++ share/functions/fish_config.fish | 8 ++------ share/functions/fish_update_completions.fish | 8 ++------ 3 files changed, 14 insertions(+), 12 deletions(-) create mode 100644 share/functions/__fish_anypython.fish diff --git a/share/functions/__fish_anypython.fish b/share/functions/__fish_anypython.fish new file mode 100644 index 000000000..3a3819864 --- /dev/null +++ b/share/functions/__fish_anypython.fish @@ -0,0 +1,10 @@ +function __fish_anypython + # Try python3 first, because that's usually faster and generally nicer. + for py in python3 python2 python + command -sq $py + and echo $py + and return 0 + end + # We have no python. + return 1 +end diff --git a/share/functions/fish_config.fish b/share/functions/fish_config.fish index d4ef02c9a..aa05fa0f0 100644 --- a/share/functions/fish_config.fish +++ b/share/functions/fish_config.fish @@ -1,11 +1,7 @@ function fish_config --description "Launch fish's web based configuration" set -lx __fish_bin_dir $__fish_bin_dir - if command -sq python3 - python3 "$__fish_data_dir/tools/web_config/webconfig.py" $argv - else if command -sq python2 - python2 "$__fish_data_dir/tools/web_config/webconfig.py" $argv - else if command -sq python - python "$__fish_data_dir/tools/web_config/webconfig.py" $argv + if set -l python (__fish_anypython) + $python "$__fish_data_dir/tools/web_config/webconfig.py" $argv else echo (set_color $fish_color_error)Cannot launch the web configuration tool:(set_color normal) echo (set_color -o)fish_config(set_color normal) requires Python. diff --git a/share/functions/fish_update_completions.fish b/share/functions/fish_update_completions.fish index 96b55c59d..cf0151669 100644 --- a/share/functions/fish_update_completions.fish +++ b/share/functions/fish_update_completions.fish @@ -2,12 +2,8 @@ function fish_update_completions --description "Update man-page based completion # Don't write .pyc files, use the manpath, clean up old completions # display progress. set -l update_args -B $__fish_data_dir/tools/create_manpage_completions.py --manpath --cleanup-in ~/.config/fish/generated_completions --progress $argv - if command -qs python3 - python3 $update_args - else if command -qs python2 - python2 $update_args - else if command -qs python - python $update_args + if set -l python (__fish_anypython) + $python $update_args else printf "%s\n" (_ "python executable not found") return 1 From b0e9405b115d8c3951cb3801131166dc03fb48e9 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 9 Mar 2019 18:00:52 +0100 Subject: [PATCH 0033/1732] Read json via python Apparently that's actually faster than jq, and it's more likely to be installed. Also it should convince the arch packager to remove the jq dependency. The indentation is weird, though. [ci skip] --- share/completions/bower.fish | 12 +++++++++--- share/completions/npm.fish | 15 ++++++++++++--- share/completions/yarn.fish | 15 ++++++++++----- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/share/completions/bower.fish b/share/completions/bower.fish index d4c45c949..e459a5c23 100644 --- a/share/completions/bower.fish +++ b/share/completions/bower.fish @@ -44,13 +44,19 @@ function __bower_matching_pkgs bower search (commandline -ct) | string match -r "\S+[^\s]" | string match -v "Search" end -# Output of `bower list` is a) slow, b) convoluted. Use `jq` instead. +# Output of `bower list` is a) slow, b) convoluted. Use `python` or `jq` instead. function __bower_list_installed - if not type -q jq + if not test -e bower.json return 1 end - if not test -e bower.json + if set -l python (__fish_anypython) + $python -c 'import json, sys; data = json.load(sys.stdin); +for k,v in data["dependencies"].items(): print(k + "\t" + v[:18])' bower.json 2>/dev/null + return + end + + if not type -q jq return 1 end diff --git a/share/completions/npm.fish b/share/completions/npm.fish index 8fdb03d1d..607215086 100644 --- a/share/completions/npm.fish +++ b/share/completions/npm.fish @@ -84,10 +84,19 @@ function __fish_parse_npm_run_completions end function __fish_npm_run - # Like above, only try to call npm if there's a command by that name to facilitate aliases that call nvm. - if command -sq jq; and test -e package.json - jq -r '.scripts | to_entries[] | .key,.value' /dev/null + else if command -sq jq; and test -e package.json + jq -r '.scripts | to_entries | map("\(.key)\t\(.value | tostring | .[0:20])") | .[]' package.json else if command -sq npm + # Like above, only try to call npm if there's a command by that name to facilitate aliases that call nvm. command npm run | string match -r -v '^[^ ]|^$' | string trim | __fish_parse_npm_run_completions end end diff --git a/share/completions/yarn.fish b/share/completions/yarn.fish index d9549e071..be3ab0e11 100644 --- a/share/completions/yarn.fish +++ b/share/completions/yarn.fish @@ -71,11 +71,16 @@ complete -f -c yarn -n '__fish_use_subcommand' -a remove complete -f -c yarn -n '__fish_use_subcommand' -a run function __fish_yarn_run - if test -e package.json; and type -q jq - jq -r '.scripts | to_entries | map("\(.key)\t\(.value | tostring | .[0:20])") | .[]' package.json - else if type -q jq - command yarn run --json 2> /dev/null | jq -r '.data.hints? | to_entries | map("\(.key)\t\(.value | tostring |.[0:20])") | .[]' - end + if test -e package.json; and set -l python (__fish_anypython) + # Warning: That weird indentation is necessary, because python. + $python -c 'import json, sys; data = json.load(sys.stdin); +for k,v in data["scripts"].items(): print(k + "\t" + v[:18])' /dev/null + else if test -e package.json; and type -q jq + jq -r '.scripts | to_entries | map("\(.key)\t\(.value | tostring | .[0:20])") | .[]' package.json + else if type -q jq + # Yarn is quite slow and still requires `jq` because the normal format is unusable. + command yarn run --json 2> /dev/null | jq -r '.data.hints? | to_entries | map("\(.key)\t\(.value | tostring |.[0:20])") | .[]' + end end # Scripts can be used like normal subcommands, or with `yarn run SCRIPT`. From bf926fd6c46888c2ed9054546267920f03968882 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 9 Mar 2019 18:03:19 +0100 Subject: [PATCH 0034/1732] completions/yarn: Don't offer files for `yarn run` Pretty sure that, like npm, that's not valid. [ci skip] --- share/completions/yarn.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/completions/yarn.fish b/share/completions/yarn.fish index be3ab0e11..eed79e7fe 100644 --- a/share/completions/yarn.fish +++ b/share/completions/yarn.fish @@ -84,7 +84,7 @@ for k,v in data["scripts"].items(): print(k + "\t" + v[:18])' /d end # Scripts can be used like normal subcommands, or with `yarn run SCRIPT`. -complete -c yarn -n '__fish_use_subcommand; or __fish_seen_subcommand_from run' -a "(__fish_yarn_run)" +complete -c yarn -n '__fish_use_subcommand; or __fish_seen_subcommand_from run' -xa "(__fish_yarn_run)" complete -f -c yarn -n '__fish_use_subcommand' -a tag complete -f -c yarn -n '__fish_seen_subcommand_from tag' -a 'add rm ls' From ba1249763b410325f5083d9ed851a28a43d26b9b Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 9 Mar 2019 18:30:17 +0100 Subject: [PATCH 0035/1732] functions/__fish_npm_helper: Use python for json [ci skip] --- share/functions/fish_npm_helper.fish | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/share/functions/fish_npm_helper.fish b/share/functions/fish_npm_helper.fish index bcbe42d7b..3ba7872b9 100644 --- a/share/functions/fish_npm_helper.fish +++ b/share/functions/fish_npm_helper.fish @@ -12,7 +12,7 @@ function __yarn_helper_installed set -l old (commandline) commandline -r "" echo \nfish: Run `$argv[1] all-the-package-names` to gain intelligent \ - package completion > /dev/stderr + package completion >&2 commandline -f repaint commandline -r $old set -g __fish_yarn_pkg_info_shown 1 @@ -57,7 +57,10 @@ function __yarn_installed_packages return 1 end - if type -q jq + if set -l python (__fish_anypython) + $python -c 'import json, sys; data = json.load(sys.stdin); +print("\n".join(data["dependencies"])); print("\n".join(data["devDependencies"]))' < $package_json 2>/dev/null + else if type -q jq jq -r '.dependencies as $a1 | .devDependencies as $a2 | ($a1 + $a2) | to_entries[] | .key' $package_json else set -l depsFound 0 From eaf496c1d44f9f2753182efe3fa0d853510bfef0 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 9 Mar 2019 13:39:51 -0800 Subject: [PATCH 0036/1732] seq.fish: use gseq if available. Apparently if you install gnu coreutils on OpenBSD, the tools are g-prefixed. So we definitely want to just alias that rather than provide our lousy shell script implementation. --- share/functions/seq.fish | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/share/functions/seq.fish b/share/functions/seq.fish index 100b71722..e574a65c5 100644 --- a/share/functions/seq.fish +++ b/share/functions/seq.fish @@ -1,10 +1,18 @@ - # If seq is not installed, then define a function that invokes __fish_fallback_seq +# If seq is not installed, then define a function that invokes __fish_fallback_seq # We can't call type here because that also calls seq if not command -sq seq - # No seq command - function seq --description "Print sequences of numbers" - __fish_fallback_seq $argv + if command -sq gseq + # No seq provided by the OS, but GNU coreutils was apparently installed, fantastic + function seq --description "Print sequences of numbers (gseq)" + gseq $argv + end + exit + else + # No seq command + function seq --description "Print sequences of numbers" + __fish_fallback_seq $argv + end end function __fish_fallback_seq --description "Fallback implementation of the seq command" From c1859b567840b910fde47356ca08082c8411ed7d Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 9 Mar 2019 14:52:08 -0800 Subject: [PATCH 0037/1732] `date` completions: show correct options for different BSDs, macOS Also prevents file completions where they are not approprite, and additionally shortened the descriptions to fit in two pager columns in an 80-wide terminal for some platforms. --- share/completions/date.fish | 51 +++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/share/completions/date.fish b/share/completions/date.fish index d033932d8..ed1a0f043 100644 --- a/share/completions/date.fish +++ b/share/completions/date.fish @@ -1,22 +1,41 @@ +complete -c date -f -d "display or set date and time" if date --version > /dev/null 2>/dev/null complete -c date -s d -l date -d "Display date described by string" -x complete -c date -s f -l file -d "Display date for each line in file" -r - complete -c date -s I -l iso-8601 -d "Output in ISO 8601 format" -x -a "date hours minutes seconds" + complete -c date -s I -l iso-8601 -d "Output in ISO-8601 format" -x -a "date hours minutes seconds" complete -c date -s s -l set -d "Set time" -x - complete -c date -s R -l rfc-2822 -d "Output RFC-2822 compliant date string" - complete -c date -s r -l reference -d "Display the last modification time of file" -r - complete -c date -s u -l utc -d "Print or set Coordinated Universal Time" - complete -c date -l universal -d "Print or set Coordinated Universal Time" - complete -c date -s h -l help -d "Display help and exit" - complete -c date -s v -l version -d "Display version and exit" -else # OS X - complete -c date -s d -d 'Set the kernel\'s value for daylight saving time' -x - complete -c date -s f -d 'Use format string to parse the date provided rather than default format' - complete -c date -s j -d 'Do no try to set the date' - complete -c date -s n -d 'Set the time for current machine only in the local group' - complete -c date -s r -d 'Print date and time represented by SEC since Epoch' -x - complete -c date -s t -d 'Set system\'s value for MINUTES west of GMT' - complete -c date -s u -d 'Display or set the date int UTC time' - complete -c date -s v -d 'Adjust the time component backward(-)/forward(+) according to VAL' -x + complete -c date -s R -l rfc-2822 -d "Output RFC-2822 date string" + complete -c date -s r -l reference -d "Display last modification time of file" -r + complete -c date -s u -l utc -d "Print/set UTC time" -f + complete -c date -l universal -d "Print/set UTC time" -f + complete -c date -s h -l help -d "Display help and exit" -f + complete -c date -s v -l version -d "Display version and exit" -f +else + complete -c date -s u -d 'Display or set UTC time' -f + complete -c date -s j -d "Don't actually set the clock" -f + complete -c date -s d -d "Set system's value for DST" -x + + set -l uname (uname -s) + + test "$uname" != OpenBSD + and complete -c date -s n -d 'Set clock for local machine only' -f + + switch $uname + case FreeBSD Darwin DragonFly + # only -u is actually POSIX. Rest are BSD extensions: + complete -c date -s r -d "Show file mtime, or format seconds" -r + complete -c date -s v -d 'Adjust clock +/- by time specified' -f + case NetBSD OpenBSD + complete -c date -s a -d "Change clock slowly with adjtime" -x + complete -c date -s r -d "Show date given seconds since epoch" -x + if test "$uname" = NetBSD + complete -c date -s d -d "Parse human-described date-time and show result" -x + exit + end + complete -c date -s z -d "Specify timezone for output" -x + end + + complete -c date -s t -d "Set system's minutes west of GMT" -x + complete -c date -s f -d 'Use format string to parse date' -f end From 3e8c05e32b295a23e066a8408cab48e88b218270 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 9 Mar 2019 15:02:25 -0800 Subject: [PATCH 0038/1732] cat, mv, rm completions: shorten descriptions --- share/completions/cat.fish | 28 ++++++++++++++-------------- share/completions/mv.fish | 28 ++++++++++++++-------------- share/completions/rm.fish | 33 +++++++++++++++------------------ 3 files changed, 43 insertions(+), 46 deletions(-) diff --git a/share/completions/cat.fish b/share/completions/cat.fish index 2a7bce379..8e9bf016d 100644 --- a/share/completions/cat.fish +++ b/share/completions/cat.fish @@ -1,21 +1,21 @@ if cat --version 2>/dev/null > /dev/null # GNU - complete -c cat -s A -l show-all -d "Escape all non-printing characters" - complete -c cat -s b -l number-nonblank -d "Number nonblank lines" - complete -c cat -s e -d "Escape non-printing characters except tab" - complete -c cat -s E -l show-ends -d "Display \$ at end of line" - complete -c cat -s n -l number -d "Number all lines" - complete -c cat -s s -l squeeze-blank -d "Never more than single blank line" - complete -c cat -s t -d "Escape non-printing characters except newline" + complete -c cat -s A -l show-all -d "Escape all unprintables" + complete -c cat -s b -l number-nonblank -d "Number non-blank lines" + complete -c cat -s e -d "Escape unprintables except \\t" + complete -c cat -s E -l show-ends -d "Display \$ at line end" + complete -c cat -s n -l number -d "Enumerate lines" + complete -c cat -s s -l squeeze-blank -d "Never >1 blank line" + complete -c cat -s t -d "Escape unprintables except \\n" complete -c cat -s T -l show-tabs -d "Escape tab" - complete -c cat -s v -d "Escape non-printing except newline and tab" + complete -c cat -s v -d "Escape unprintables except '\\n' and \\t" complete -c cat -l help -d "Display help and exit" complete -c cat -l version -d "Display version and exit" else # OS X - complete -c cat -s b -d "Number non-blank lines" - complete -c cat -s e -d "Display non-printing characters, and `\$' at the end of each line" - complete -c cat -s n -d "Number all lines" - complete -c cat -s s -d "Single spaced output by squeezing adjacent empty lines" - complete -c cat -s t -d "Display non-printing characters, and tab characters as `^I'" + complete -c cat -s b -d "Specify # of non-blank lines" + complete -c cat -s e -d "Show unprintables, end lines with \$" + complete -c cat -s n -d "Enumerate lines" + complete -c cat -s s -d "Squeeze away >1 blank lines" + complete -c cat -s t -d "Show unprintables; tab as '^I'" complete -c cat -s u -d "Disable output buffering" - complete -c cat -s v -d "Display non-printing characters so they're visible." + complete -c cat -s v -d "Escape non-printing chars" end \ No newline at end of file diff --git a/share/completions/mv.fish b/share/completions/mv.fish index 24a116307..e8eb6f40d 100644 --- a/share/completions/mv.fish +++ b/share/completions/mv.fish @@ -13,21 +13,21 @@ if mv --version >/dev/null 2>/dev/null simple\t'Make simple backups' never\t'Make simple backups'" complete -c mv -s b -d "Backup each existing destination file" - complete -c mv -s f -l force -d "Don't prompt before overwriting" - complete -c mv -s i -l interactive -d "Prompt before overwriting" - complete -c mv -s n -l no-clobber -d "Don't overwrite existing files" + complete -c mv -s f -l force -d "Don't prompt to overwrite" + complete -c mv -s i -l interactive -d "Prompt to overwrite" + complete -c mv -s n -l no-clobber -d "Don't overwrite existing" # --reply has been deprecated for over a decade, and now GNU mv does not accept this option. # Better to use -f instead of --reply=yes. # complete -c mv -l reply -x -a "yes no query" -d "Answer for overwrite questions" - complete -c mv -l strip-trailing-slashes -d "Remove trailing slashes from source args" + complete -c mv -l strip-trailing-slashes -d "Remove trailing '/' from source args" complete -c mv -s S -l suffix -x -d "Override default backup suffix" - complete -c mv -s t -l target-directory -d "Move all source args into DIRECTORY" \ - -x -a "(__fish_complete_directories (commandline -ct) 'DIRECTORY')" + complete -c mv -s t -l target-directory -d "Move all source args into DIR" \ + -x -a "(__fish_complete_directories (commandline -ct) 'Directory')" complete -c mv -s T -l no-target-directory -d "Treat DEST as a normal file" - complete -c mv -s u -l update -d "Don't overwrite newer files" - complete -c mv -s v -l verbose -d "Print each file as it is moved" + complete -c mv -s u -l update -d "Don't overwrite newer" + complete -c mv -s v -l verbose -d "Print filenames as it goes" test "$uname" = Linux - and complete -c mv -s Z -l context -d "Sets SELinux context to default" + and complete -c mv -s Z -l context -d "Set SELinux context to default" complete -c mv -l help -d "Print help and exit" complete -c mv -l version -d "Print version and exit" @@ -41,22 +41,22 @@ else #[posix][ext] # solaris: mv [-fi][ ] src dst # POSIX options - complete -c mv -s f -d "Don't prompt before overwriting" - complete -c mv -s i -d "Prompt before overwriting existing files" + complete -c mv -s f -d "Don't prompt to overwrite" + complete -c mv -s i -d "Prompt to overwrite existing" test uname = SunOS # -fi and exit 0 # Extensions - complete -c mv -s v -d "Print each file as it is moved" + complete -c mv -s v -d "Print filenames as it goes" contains "$uname" NetBSD OpenBSD # -fiv and exit 0 - complete -c mv -s n -d "Don't overwrite existing files" + complete -c mv -s n -d "Don't overwrite existing" test "$uname" = Darwin # -fivn and exit 0 - complete -c mv -s h -d "If target is a link to a directory, don't follow it" + complete -c mv -s h -d "Don't follow target if it links to a dir" end diff --git a/share/completions/rm.fish b/share/completions/rm.fish index f085ebaa8..5ca66833d 100644 --- a/share/completions/rm.fish +++ b/share/completions/rm.fish @@ -1,14 +1,14 @@ #Completions for rm if rm --version >/dev/null 2>/dev/null # GNU - complete -c rm -s d -l directory -d "Unlink directory (Only by superuser)" - complete -c rm -s f -l force -d "Never prompt before removal" - complete -c rm -s i -l interactive -d "Prompt before removal" - complete -c rm -s I -d "Prompt before removing more than three files" - complete -c rm -s r -l recursive -d "Recursively remove subdirectories" - complete -c rm -s R -d "Recursively remove subdirectories" + complete -c rm -s d -l directory -d "Unlink directories" + complete -c rm -s f -l force -d "Never prompt for removal" + complete -c rm -s i -l interactive -d "Prompt for removal" + complete -c rm -s I -d "Prompt to remove >3 files" + complete -c rm -s r -l recursive -d "Recursively remove subdirs" + complete -c rm -s R -d "Recursively remove subdirs" complete -c rm -s v -l verbose -d "Explain what is done" - complete -c rm -s h -l help -d "Display help and exit" - complete -c rm -l version -d "Display version and exit" + complete -c rm -s h -l help -d "Display help" + complete -c rm -l version -d "Display rm version" else set -l uname (uname -s) # solaris: rm [-fi ] file ... @@ -18,24 +18,21 @@ else # freebsd: rm [-fidPRrvWxI] file ... # dragonfly: rm [-fidPRrvWxI] file ... - complete -c rm -s f -d "Never prompt before removal" - complete -c rm -s i -d "Prompt before removal" + complete -c rm -s f -d "Never prompt for removal" + complete -c rm -s i -d "Prompt for removal" test "$uname" = SunOS and exit 0 - complete -c rm -s d -d "Attempt to remove directories as well" + complete -c rm -s d -d "Remove directories as well" complete -c rm -s P -d "Overwrite before removal" - complete -c rm -s R -d "Recursively remove subdirectories" - complete -c rm -s r -d "Recursively remove subdirectories" + complete -c rm -s R -s r -d "Recursively remove subdirs" complete -c rm -s v -d "Explain what is done" test "$uname" = OpenBSD and exit 0 - complete -c rm -s W -d "Undelete the named files" + complete -c rm -s W -d "Undelete given filenames" test "$uname" = Darwin and exit 0 - complete -c rm -s x -d "Do not traverse filesystem mount points" + complete -c rm -s x -d "Don't traverse mount points" test "$uname" = NetBSD and exit 0 - complete -c rm -s I -d "Like -i, but only if 3 or more files affected" + complete -c rm -s I -d "Prompt to remove >=3 files" end - - From 2ae6e5a5858571d52ec6fedc568627661c596f53 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Mon, 11 Mar 2019 14:53:26 -0700 Subject: [PATCH 0039/1732] Explicitly handle all enum values in more switch statements This addresses a few places where -Wswitch-enum showed one or two missing case's for enum values. It did uncover and fix one apparent oversight: $ function asd -p 100 echo foo end $ functions --handlers-type exit Event exit asd It looks like this should be showing a PID before 'asd' just like job_exit handlers show the job id. It was falling through to default: which just printed the function name. $ functions --handlers-type exit Event exit 100 asd --- src/builtin_functions.cpp | 1 + src/builtin_math.cpp | 2 +- src/common.h | 17 +++++++++++++++-- src/event.cpp | 8 ++++++-- src/tokenizer.cpp | 5 ++++- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/builtin_functions.cpp b/src/builtin_functions.cpp index 860f675e7..071d1cad2 100644 --- a/src/builtin_functions.cpp +++ b/src/builtin_functions.cpp @@ -176,6 +176,7 @@ static wcstring functions_def(const wcstring &name) { append_format(out, L" --on-event %ls", d.str_param1.c_str()); break; } + case event_type_t::any: default: { DIE("unexpected next->type"); break; diff --git a/src/builtin_math.cpp b/src/builtin_math.cpp index 506f80a5c..a98ea5b74 100644 --- a/src/builtin_math.cpp +++ b/src/builtin_math.cpp @@ -131,9 +131,9 @@ static const wchar_t *math_get_arg(int *argidx, wchar_t **argv, wcstring *storag static wcstring math_describe_error(te_error_t& error) { if (error.position == 0) return L"NO ERROR?!?"; - assert(error.type != TE_ERROR_NONE && L"Error has no position"); switch(error.type) { + case TE_ERROR_NONE: DIE("Error has no position"); case TE_ERROR_UNKNOWN_VARIABLE: return _(L"Unknown variable"); case TE_ERROR_MISSING_CLOSING_PAREN: return _(L"Missing closing parenthesis"); case TE_ERROR_MISSING_OPENING_PAREN: return _(L"Missing opening parenthesis"); diff --git a/src/common.h b/src/common.h index d99524cd4..6007b4317 100644 --- a/src/common.h +++ b/src/common.h @@ -429,7 +429,15 @@ static inline bool match_type_requires_full_replacement(fuzzy_match_type_t t) { case fuzzy_match_prefix: { return false; } - default: { return true; } + case fuzzy_match_case_insensitive: + case fuzzy_match_prefix_case_insensitive: + case fuzzy_match_substring: + case fuzzy_match_substring_case_insensitive: + case fuzzy_match_subsequence_insertions_only: + case fuzzy_match_none: + { + return true; + } } } @@ -442,7 +450,12 @@ static inline bool match_type_shares_prefix(fuzzy_match_type_t t) { case fuzzy_match_prefix_case_insensitive: { return true; } - default: { return false; } + case fuzzy_match_substring: + case fuzzy_match_substring_case_insensitive: + case fuzzy_match_subsequence_insertions_only: + case fuzzy_match_none: { + return false; + } } } diff --git a/src/event.cpp b/src/event.cpp index f04afefc0..79bbdd693 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -120,7 +120,8 @@ static bool handler_matches(const event_handler_t &classv, const event_t &instan case event_type_t::generic: { return classv.desc.str_param1 == instance.desc.str_param1; } - default: { + case event_type_t::any: { + default: DIE("unexpected classv.type"); return false; } @@ -165,7 +166,7 @@ wcstring event_get_desc(const event_t &evt) { -ed.param1.pid); } } - assert(0 && "Unreachable"); + DIE("Unreachable"); } case event_type_t::job_exit: { @@ -182,6 +183,7 @@ wcstring event_get_desc(const event_t &evt) { case event_type_t::generic: { return format_string(_(L"handler for generic event '%ls'"), ed.str_param1.c_str()); } + case event_type_t::any: { DIE("Unreachable"); } default: DIE("Unknown event type"); } @@ -409,6 +411,7 @@ void event_print(io_streams_t &streams, maybe_t type_filter) { streams.out.append_format(L"%ls %ls\n", sig2wcs(evt->desc.param1.signal), evt->function_name.c_str()); break; + case event_type_t::exit: case event_type_t::job_exit: streams.out.append_format(L"%d %ls\n", evt->desc.param1, evt->function_name.c_str()); @@ -418,6 +421,7 @@ void event_print(io_streams_t &streams, maybe_t type_filter) { streams.out.append_format(L"%ls %ls\n", evt->desc.str_param1.c_str(), evt->function_name.c_str()); break; + case event_type_t::any: DIE("Unreachable"); default: streams.out.append_format(L"%ls\n", evt->function_name.c_str()); break; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index fd997a361..38ec77029 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -408,7 +408,10 @@ int oflags_for_redirection_type(redirection_type_t type) { case redirection_type_t::input: { return O_RDONLY; } - default: { return -1; } + case redirection_type_t::fd: + default: { + return -1; + } } } From 66887ca4bc94f99001bed1623780998b3bf52748 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Tue, 12 Mar 2019 09:44:57 -0700 Subject: [PATCH 0040/1732] Fix OpenSUSE build They treat -Wreturn-type as a critical thing apparently. --- src/common.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/common.h b/src/common.h index 6007b4317..7c4f84c79 100644 --- a/src/common.h +++ b/src/common.h @@ -434,10 +434,13 @@ static inline bool match_type_requires_full_replacement(fuzzy_match_type_t t) { case fuzzy_match_substring: case fuzzy_match_substring_case_insensitive: case fuzzy_match_subsequence_insertions_only: - case fuzzy_match_none: - { + case fuzzy_match_none: { return true; } + default: { + DIE("Unreachable"); + return false; + } } } @@ -456,6 +459,10 @@ static inline bool match_type_shares_prefix(fuzzy_match_type_t t) { case fuzzy_match_none: { return false; } + default: { + DIE("Unreachabe"); + return false; + } } } From 8a0d794337046f023474ff47b33e34b814bfeeb8 Mon Sep 17 00:00:00 2001 From: hyperfekt Date: Tue, 12 Mar 2019 09:01:05 +0100 Subject: [PATCH 0041/1732] fish_git_prompt: optionally show stash state in informative mode --- CHANGELOG.md | 1 + share/functions/fish_git_prompt.fish | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d10fabb4..0099e2300 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - `cf` - `bosh` - `vagrant` +- The git prompt in informative mode now shows the number of stashes if enabled. ### For distributors and developers - The autotools-based build system and legacy Xcode build systems have been removed, leaving only the CMake build system. All distributors and developers must migrate to the CMake build. diff --git a/share/functions/fish_git_prompt.fish b/share/functions/fish_git_prompt.fish index cb96b31eb..6f9657d1f 100644 --- a/share/functions/fish_git_prompt.fish +++ b/share/functions/fish_git_prompt.fish @@ -102,6 +102,7 @@ # invalidstate (✖) # stagedstate (●) # untrackedfiles (…) +# stashstate (⚑) # cleanstate (✔) # # @@ -401,7 +402,7 @@ function fish_git_prompt --description "Prompt function for Git" and test "$dirty" != false and test "$untracked" != false end - set informative_status "$space"(__fish_git_prompt_informative_status) + set informative_status "$space"(__fish_git_prompt_informative_status $git_dir) else # This has to be set explicitly. if test "$dirty" = true @@ -517,6 +518,9 @@ function __fish_git_prompt_dirty --description "fish_git_prompt helper, tells wh end set -g ___fish_git_prompt_status_order stagedstate invalidstate dirtystate untrackedfiles +if set -q __fish_git_prompt_showstashstate + set -a ___fish_git_prompt_status_order stashstate +end function __fish_git_prompt_informative_status @@ -530,11 +534,16 @@ function __fish_git_prompt_informative_status set -l invalidstate (count (string match -r "U" -- $stagedFiles)) set -l stagedstate (math $x - $invalidstate) set -l untrackedfiles (command git ls-files --others --exclude-standard | wc -l | string trim) + set -l stashstate 0 + set -l stashfile "$argv[1]/logs/refs/stash" + if set -q __fish_git_prompt_showstashstate; and test -e "$stashfile" + set stashstate (wc -l $stashfile | string match -r '\d+') + end set -l info # If `math` fails for some reason, assume the state is clean - it's the simpler path - set -l state (math $dirtystate + $invalidstate + $stagedstate + $untrackedfiles 2>/dev/null) + set -l state (math $dirtystate + $invalidstate + $stagedstate + $untrackedfiles + $stashstate 2>/dev/null) if test -z "$state" or test "$state" = 0 set info $___fish_git_prompt_color_cleanstate$___fish_git_prompt_char_cleanstate$___fish_git_prompt_color_cleanstate_done @@ -686,7 +695,7 @@ function __fish_git_prompt_validate_chars --description "fish_git_prompt helper, __fish_git_prompt_set_char __fish_git_prompt_char_dirtystate '*' '✚' __fish_git_prompt_set_char __fish_git_prompt_char_invalidstate '#' '✖' __fish_git_prompt_set_char __fish_git_prompt_char_stagedstate '+' '●' - __fish_git_prompt_set_char __fish_git_prompt_char_stashstate '$' + __fish_git_prompt_set_char __fish_git_prompt_char_stashstate '$' '⚑' __fish_git_prompt_set_char __fish_git_prompt_char_stateseparator ' ' '|' __fish_git_prompt_set_char __fish_git_prompt_char_untrackedfiles '%' '…' __fish_git_prompt_set_char __fish_git_prompt_char_upstream_ahead '>' '↑' @@ -778,7 +787,7 @@ function __fish_git_prompt_repaint $varargs --description "Event handler, repain if status --is-interactive if test $argv[3] = __fish_git_prompt_show_informative_status # Clear characters that have different defaults with/without informative status - for name in cleanstate dirtystate invalidstate stagedstate stateseparator untrackedfiles upstream_ahead upstream_behind + for name in cleanstate dirtystate invalidstate stagedstate stashstate stateseparator untrackedfiles upstream_ahead upstream_behind set -e ___fish_git_prompt_char_$name end end From bfb61879cdebe7df77ebaf4a41f688d29f47411e Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 12 Mar 2019 18:49:08 +0100 Subject: [PATCH 0042/1732] Do create installation directories that already exist Reverts 71329a250b09dfacaca48fb69c69fe59eeb0c15a. That tried to fix problems with pkgconfig by not recreating it. Instead, use the function we already have for not trying too hard to create a directory. Fixes #5735. --- cmake/Install.cmake | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cmake/Install.cmake b/cmake/Install.cmake index be7d10b23..f1537344a 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -53,9 +53,7 @@ ENDIF() # Define a function to help us create directories. FUNCTION(FISH_CREATE_DIRS) FOREACH(dir ${ARGV}) - IF(NOT EXISTS ${CMAKE_INSTALL_PREFIX}/${dir}) - INSTALL(DIRECTORY DESTINATION ${dir}) - ENDIF() + INSTALL(DIRECTORY DESTINATION ${dir}) ENDFOREACH(dir) ENDFUNCTION(FISH_CREATE_DIRS) @@ -113,9 +111,9 @@ INSTALL(FILES share/config.fish # -$v $(INSTALL) -m 755 -d $(DESTDIR)$(extra_completionsdir) # -$v $(INSTALL) -m 755 -d $(DESTDIR)$(extra_functionsdir) # -$v $(INSTALL) -m 755 -d $(DESTDIR)$(extra_confdir) -FISH_CREATE_DIRS(${rel_datadir}/pkgconfig) # Don't try too hard to create these directories as they may be outside our writeable area # https://github.com/Homebrew/homebrew-core/pull/2813 +FISH_TRY_CREATE_DIRS(${rel_datadir}/pkgconfig) FISH_TRY_CREATE_DIRS(${extra_completionsdir} ${extra_functionsdir} ${extra_confdir}) # @echo "Installing pkgconfig file" From ecfe4acd0c224c02d57f962fd62b8adb8c9e2a35 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 12 Mar 2019 20:25:04 +0100 Subject: [PATCH 0043/1732] complete: Do fuzzy match for --do-complete This only did prefix matching, which is generally less useful. All existing users _should_ be okay with this since they want to provide completions. Fixes #5467. Fixes #2318. --- CHANGELOG.md | 1 + src/builtin_complete.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0099e2300..2e4244899 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - `math` now accepts `--scale=max` for the maximum scale (#5579). - The `forward-bigword` binding now interacts correctly with autosuggestions (#5336) - Fish now tries to guess if the system supports Unicode 9 (and displays emoji as wide), hopefully making setting $fish_emoji_width superfluous in most cases (#5722). +- `complete --do-complete` now also does fuzzy matches (#5467). - Lots of improvements to completions. - Added completions for - `cf` diff --git a/src/builtin_complete.cpp b/src/builtin_complete.cpp index 2a01fcd26..1af41f394 100644 --- a/src/builtin_complete.cpp +++ b/src/builtin_complete.cpp @@ -318,7 +318,7 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) { recursion_level++; std::vector comp; - complete(do_complete_param, &comp, COMPLETION_REQUEST_DEFAULT, parser.vars()); + complete(do_complete_param, &comp, COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_FUZZY_MATCH, parser.vars()); for (size_t i = 0; i < comp.size(); i++) { const completion_t &next = comp.at(i); From d5ac239f680e3e3b32d28e87067662614af7db64 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Tue, 12 Mar 2019 14:06:01 -0700 Subject: [PATCH 0044/1732] This commit changes wchar.h includes to cwchar, and uses std:: for everything it provides. --- src/autoload.cpp | 2 +- src/builtin.cpp | 12 ++--- src/builtin_argparse.cpp | 6 +-- src/builtin_commandline.cpp | 12 ++--- src/builtin_commandline.h | 2 +- src/builtin_complete.cpp | 8 +-- src/builtin_complete.h | 2 +- src/builtin_contains.cpp | 4 +- src/builtin_fg.cpp | 4 +- src/builtin_functions.cpp | 4 +- src/builtin_history.cpp | 4 +- src/builtin_jobs.cpp | 2 +- src/builtin_jobs.h | 2 +- src/builtin_math.cpp | 4 +- src/builtin_printf.cpp | 10 ++-- src/builtin_printf.h | 2 +- src/builtin_random.cpp | 4 +- src/builtin_read.cpp | 6 +-- src/builtin_realpath.cpp | 2 +- src/builtin_set.cpp | 10 ++-- src/builtin_set.h | 2 +- src/builtin_set_color.h | 2 +- src/builtin_source.cpp | 4 +- src/builtin_status.cpp | 10 ++-- src/builtin_string.cpp | 16 +++--- src/builtin_string.h | 2 +- src/builtin_test.cpp | 6 +-- src/builtin_ulimit.h | 2 +- src/builtin_wait.cpp | 4 +- src/color.cpp | 2 +- src/common.cpp | 40 +++++++------- src/common.h | 6 +-- src/complete.cpp | 12 ++--- src/env.cpp | 20 +++---- src/env_universal_common.cpp | 6 +-- src/event.cpp | 4 +- src/expand.cpp | 8 +-- src/fallback.cpp | 8 +-- src/fallback.h | 4 +- src/fish.cpp | 8 +-- src/fish_indent.cpp | 26 ++++----- src/fish_key_reader.cpp | 70 ++++++++++++------------ src/fish_tests.cpp | 102 +++++++++++++++++------------------ src/function.cpp | 6 +-- src/future_feature_flags.cpp | 8 +-- src/highlight.cpp | 20 +++---- src/history.cpp | 4 +- src/input.cpp | 4 +- src/input_common.cpp | 6 +-- src/intern.cpp | 6 +-- src/io.cpp | 20 +++---- src/io.h | 2 +- src/iothread.cpp | 2 +- src/lru.h | 2 +- src/output.cpp | 8 +-- src/pager.cpp | 4 +- src/parse_execution.cpp | 6 +-- src/parse_tree.cpp | 12 ++--- src/parse_util.cpp | 22 ++++---- src/parser.cpp | 12 ++--- src/path.cpp | 2 +- src/postfork.cpp | 2 +- src/proc.cpp | 12 ++--- src/reader.cpp | 34 ++++++------ src/screen.cpp | 10 ++-- src/screen.h | 2 +- src/tokenizer.cpp | 8 +-- src/util.cpp | 4 +- src/wcstringutil.cpp | 2 +- src/wgetopt.cpp | 36 ++++++------- src/wildcard.cpp | 18 +++---- src/wutil.cpp | 18 +++---- 72 files changed, 379 insertions(+), 379 deletions(-) diff --git a/src/autoload.cpp b/src/autoload.cpp index 9f13bb8b2..95827dc2c 100644 --- a/src/autoload.cpp +++ b/src/autoload.cpp @@ -26,7 +26,7 @@ static const int kAutoloadStalenessInterval = 15; file_access_attempt_t access_file(const wcstring &path, int mode) { - // fwprintf(stderr, L"Touch %ls\n", path.c_str()); + // std::fwprintf(stderr, L"Touch %ls\n", path.c_str()); file_access_attempt_t result = {}; struct stat statbuf; if (wstat(path, &statbuf)) { diff --git a/src/builtin.cpp b/src/builtin.cpp index 9473c9e94..be3c98fbe 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -76,11 +76,11 @@ #include "wutil.h" // IWYU pragma: keep bool builtin_data_t::operator<(const wcstring &other) const { - return wcscmp(this->name, other.c_str()) < 0; + return std::wcscmp(this->name, other.c_str()) < 0; } bool builtin_data_t::operator<(const builtin_data_t *other) const { - return wcscmp(this->name, other->name) < 0; + return std::wcscmp(this->name, other->name) < 0; } /// Counts the number of arguments in the specified null-terminated array @@ -215,7 +215,7 @@ void builtin_print_help(parser_t &parser, io_streams_t &streams, const wchar_t * // First move down 4 lines. pos = str; for (i = 0; (i < 4) && pos && *pos; i++) { - pos = wcschr(pos + 1, L'\n'); + pos = std::wcschr(pos + 1, L'\n'); } if (pos && *pos) { @@ -311,7 +311,7 @@ static int builtin_count(parser_t &parser, io_streams_t &streams, wchar_t **argv /// This function handles both the 'continue' and the 'break' builtins that are used for loop /// control. static int builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar_t **argv) { - int is_break = (wcscmp(argv[0], L"break") == 0); + int is_break = (std::wcscmp(argv[0], L"break") == 0); int argc = builtin_count_args(argv); if (argc != 1) { @@ -482,7 +482,7 @@ void builtin_init() { for (size_t i = 0; i < BUILTIN_COUNT; i++) { const wchar_t *name = builtin_datas[i].name; intern_static(name); - assert((i == 0 || wcscmp(builtin_datas[i - 1].name, name) < 0) && + assert((i == 0 || std::wcscmp(builtin_datas[i - 1].name, name) < 0) && "builtins are not sorted alphabetically"); } } diff --git a/src/builtin_argparse.cpp b/src/builtin_argparse.cpp index c4b88736e..1e87a03a4 100644 --- a/src/builtin_argparse.cpp +++ b/src/builtin_argparse.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -316,7 +316,7 @@ static int collect_option_specs(argparse_cmd_opts_t &opts, int *optind, int argc wchar_t *cmd = argv[0]; while (true) { - if (wcscmp(L"--", argv[*optind]) == 0) { + if (std::wcscmp(L"--", argv[*optind]) == 0) { ++*optind; break; } @@ -401,7 +401,7 @@ static int parse_cmd_opts(argparse_cmd_opts_t &opts, int *optind, //!OCLINT(hig if (opts.print_help) return STATUS_CMD_OK; - if (argc == w.woptind || wcscmp(L"--", argv[w.woptind - 1]) == 0) { + if (argc == w.woptind || std::wcscmp(L"--", argv[w.woptind - 1]) == 0) { // The user didn't specify any option specs. streams.err.append_format(_(L"%ls: No option specs were provided\n"), cmd); return STATUS_INVALID_ARGS; diff --git a/src/builtin_commandline.cpp b/src/builtin_commandline.cpp index 5890fb1c0..de6cd8126 100644 --- a/src/builtin_commandline.cpp +++ b/src/builtin_commandline.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "builtin.h" #include "common.h" @@ -86,7 +86,7 @@ static void replace_part(const wchar_t *begin, const wchar_t *end, const wchar_t switch (append_mode) { case REPLACE_MODE: { out.append(insert); - out_pos = wcslen(insert) + (begin - buff); + out_pos = std::wcslen(insert) + (begin - buff); break; } case APPEND_MODE: { @@ -99,7 +99,7 @@ static void replace_part(const wchar_t *begin, const wchar_t *end, const wchar_t out.append(begin, cursor); out.append(insert); out.append(begin + cursor, end - begin - cursor); - out_pos += wcslen(insert); + out_pos += std::wcslen(insert); break; } default: { @@ -125,7 +125,7 @@ static void write_part(const wchar_t *begin, const wchar_t *end, int cut_at_curs size_t pos = cursor_pos - (begin - buffer); if (tokenize) { - // fwprintf( stderr, L"Subshell: %ls, end char %lc\n", buff, *end ); + // std::fwprintf( stderr, L"Subshell: %ls, end char %lc\n", buff, *end ); wcstring out; wcstring buff(begin, end - begin); tokenizer_t tok(buff.c_str(), TOK_ACCEPT_UNFINISHED); @@ -267,7 +267,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) } case 'I': { current_buffer = w.woptarg; - current_cursor_pos = wcslen(w.woptarg); + current_cursor_pos = std::wcslen(w.woptarg); break; } case 'C': { @@ -424,7 +424,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) switch (buffer_part) { case STRING_MODE: { begin = current_buffer; - end = begin + wcslen(begin); + end = begin + std::wcslen(begin); break; } case PROCESS_MODE: { diff --git a/src/builtin_commandline.h b/src/builtin_commandline.h index a8cbd9568..4fa8ef083 100644 --- a/src/builtin_commandline.h +++ b/src/builtin_commandline.h @@ -2,7 +2,7 @@ #ifndef FISH_BUILTIN_COMMANDLINE_H #define FISH_BUILTIN_COMMANDLINE_H -#include +#include #include class parser_t; diff --git a/src/builtin_complete.cpp b/src/builtin_complete.cpp index 1af41f394..438a33bab 100644 --- a/src/builtin_complete.cpp +++ b/src/builtin_complete.cpp @@ -2,7 +2,7 @@ #include "config.h" // IWYU pragma: keep #include -#include +#include #include #include @@ -49,7 +49,7 @@ static void builtin_complete_add2(const wchar_t *cmd, int cmd_type, const wchar_ comp, desc, flags); } - if (old_opt.empty() && gnu_opt.empty() && wcslen(short_opt) == 0) { + if (old_opt.empty() && gnu_opt.empty() && std::wcslen(short_opt) == 0) { complete_add(cmd, cmd_type, wcstring(), option_type_args_only, result_mode, condition, comp, desc, flags); } @@ -274,7 +274,7 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) { return STATUS_INVALID_ARGS; } - if (condition && wcslen(condition)) { + if (condition && std::wcslen(condition)) { const wcstring condition_string = condition; parse_error_list_t errors; if (parse_util_detect_errors(condition_string, &errors, @@ -289,7 +289,7 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) { } } - if (comp && wcslen(comp)) { + if (comp && std::wcslen(comp)) { wcstring prefix; prefix.append(cmd); prefix.append(L": "); diff --git a/src/builtin_complete.h b/src/builtin_complete.h index 96d667cba..7cbaccd5b 100644 --- a/src/builtin_complete.h +++ b/src/builtin_complete.h @@ -2,7 +2,7 @@ #ifndef FISH_BUILTIN_COMPLETE_H #define FISH_BUILTIN_COMPLETE_H -#include +#include #include diff --git a/src/builtin_contains.cpp b/src/builtin_contains.cpp index 18d067a5c..2589f2dce 100644 --- a/src/builtin_contains.cpp +++ b/src/builtin_contains.cpp @@ -2,7 +2,7 @@ #include "config.h" // IWYU pragma: keep #include -#include +#include #include "builtin.h" #include "builtin_contains.h" @@ -75,7 +75,7 @@ int builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t **argv) { streams.err.append_format(_(L"%ls: Key not specified\n"), cmd); } else { for (int i = optind + 1; i < argc; i++) { - if (!wcscmp(needle, argv[i])) { + if (!std::wcscmp(needle, argv[i])) { if (opts.print_index) streams.out.append_format(L"%d\n", i - optind); return STATUS_CMD_OK; } diff --git a/src/builtin_fg.cpp b/src/builtin_fg.cpp index 605a1301a..a89f45866 100644 --- a/src/builtin_fg.cpp +++ b/src/builtin_fg.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "builtin.h" #include "builtin_fg.h" @@ -99,7 +99,7 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { } else { // If we aren't redirecting, send output to real stderr, since stuff in sb_err won't get // printed until the command finishes. - fwprintf(stderr, FG_MSG, j->job_id, j->command_wcstr()); + std::fwprintf(stderr, FG_MSG, j->job_id, j->command_wcstr()); } const wcstring ft = tok_first(j->command()); diff --git a/src/builtin_functions.cpp b/src/builtin_functions.cpp index 071d1cad2..c9d02753b 100644 --- a/src/builtin_functions.cpp +++ b/src/builtin_functions.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -247,7 +247,7 @@ static int report_function_metadata(const wchar_t *funcname, bool verbose, io_st } if (metadata_as_comments) { - if (wcscmp(path, L"stdin")) { + if (std::wcscmp(path, L"stdin")) { streams.out.append_format(L"# Defined in %ls @ line %d\n", path, line_number); } } else { diff --git a/src/builtin_history.cpp b/src/builtin_history.cpp index bd0a49fa0..583657ae9 100644 --- a/src/builtin_history.cpp +++ b/src/builtin_history.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -67,7 +67,7 @@ static bool set_hist_cmd(wchar_t *const cmd, hist_cmd_t *hist_cmd, hist_cmd_t su wchar_t err_text[1024]; const wchar_t *subcmd_str1 = enum_to_str(*hist_cmd, hist_enum_map); const wchar_t *subcmd_str2 = enum_to_str(sub_cmd, hist_enum_map); - swprintf(err_text, sizeof(err_text) / sizeof(wchar_t), + std::swprintf(err_text, sizeof(err_text) / sizeof(wchar_t), _(L"you cannot do both '%ls' and '%ls' in the same invocation"), subcmd_str1, subcmd_str2); streams.err.append_format(BUILTIN_ERR_COMBO2, cmd, err_text); diff --git a/src/builtin_jobs.cpp b/src/builtin_jobs.cpp index f57ed101b..6d9857992 100644 --- a/src/builtin_jobs.cpp +++ b/src/builtin_jobs.cpp @@ -40,7 +40,7 @@ static int cpu_use(const job_t *j) { double t1 = 1000000.0 * p->last_time.tv_sec + p->last_time.tv_usec; double t2 = 1000000.0 * t.tv_sec + t.tv_usec; - // fwprintf( stderr, L"t1 %f t2 %f p1 %d p2 %d\n", t1, t2, jiffies, p->last_jiffies ); + // std::fwprintf( stderr, L"t1 %f t2 %f p1 %d p2 %d\n", t1, t2, jiffies, p->last_jiffies ); u += ((double)(jiffies - p->last_jiffies)) / (t2 - t1); } return u * 1000000; diff --git a/src/builtin_jobs.h b/src/builtin_jobs.h index 5c37043ac..7f6babbf9 100644 --- a/src/builtin_jobs.h +++ b/src/builtin_jobs.h @@ -2,7 +2,7 @@ #ifndef FISH_BUILTIN_JOBS_H #define FISH_BUILTIN_JOBS_H -#include +#include #include diff --git a/src/builtin_math.cpp b/src/builtin_math.cpp index a98ea5b74..a1fb48d25 100644 --- a/src/builtin_math.cpp +++ b/src/builtin_math.cpp @@ -49,7 +49,7 @@ static int parse_cmd_opts(math_cmd_opts_t &opts, int *optind, //!OCLINT(high nc switch (opt) { case 's': { // "max" is the special value that tells us to pick the maximum scale. - if (wcscmp(w.woptarg, L"max") == 0) { + if (std::wcscmp(w.woptarg, L"max") == 0) { opts.scale = 15; } else { opts.scale = fish_wcstoi(w.woptarg); @@ -162,7 +162,7 @@ static wcstring format_double(double v, const math_cmd_opts_t &opts) { while (ret.back() == L'0') { ret.pop_back(); } - if (!wcschr(digits, ret.back())) { + if (!std::wcschr(digits, ret.back())) { ret.pop_back(); } } diff --git a/src/builtin_printf.cpp b/src/builtin_printf.cpp index 6921f4097..1bcf05cc8 100644 --- a/src/builtin_printf.cpp +++ b/src/builtin_printf.cpp @@ -59,7 +59,7 @@ #include #include #include -#include +#include #include #include "builtin.h" @@ -255,17 +255,17 @@ static T raw_string_to_scalar_type(const wchar_t *s, wchar_t **end); // #626 template <> intmax_t raw_string_to_scalar_type(const wchar_t *s, wchar_t **end) { - return wcstoll(s, end, 0); + return std::wcstoll(s, end, 0); } template <> uintmax_t raw_string_to_scalar_type(const wchar_t *s, wchar_t **end) { - return wcstoull(s, end, 0); + return std::wcstoull(s, end, 0); } template <> long double raw_string_to_scalar_type(const wchar_t *s, wchar_t **end) { - double val = wcstod(s, end); + double val = std::wcstod(s, end); if (**end == L'\0') return val; // The conversion using the user's locale failed. That may be due to the string not being a // valid floating point value. It could also be due to the locale using different separator @@ -358,7 +358,7 @@ long builtin_printf_state_t::print_esc(const wchar_t *escstart, bool octal_0) { ++esc_length, ++p) esc_value = esc_value * 8 + octal_to_bin(*p); this->append_output(ENCODE_DIRECT_BASE + esc_value % 256); - } else if (*p && wcschr(L"\"\\abcefnrtv", *p)) { + } else if (*p && std::wcschr(L"\"\\abcefnrtv", *p)) { print_esc_char(*p++); } else if (*p == L'u' || *p == L'U') { wchar_t esc_char = *p; diff --git a/src/builtin_printf.h b/src/builtin_printf.h index 1f9d44d58..b0608cbb5 100644 --- a/src/builtin_printf.h +++ b/src/builtin_printf.h @@ -2,7 +2,7 @@ #ifndef FISH_BUILTIN_PRINTF_H #define FISH_BUILTIN_PRINTF_H -#include +#include #include diff --git a/src/builtin_random.cpp b/src/builtin_random.cpp index c8bbc7a1f..617082e51 100644 --- a/src/builtin_random.cpp +++ b/src/builtin_random.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -45,7 +45,7 @@ int builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv) { long long start, end; unsigned long long step; bool choice = false; - if (arg_count >= 1 && !wcscmp(argv[optind], L"choice")) { + if (arg_count >= 1 && !std::wcscmp(argv[optind], L"choice")) { if (arg_count == 1) { streams.err.append_format(L"%ls: nothing to choose from\n", cmd); return STATUS_INVALID_ARGS; diff --git a/src/builtin_read.cpp b/src/builtin_read.cpp index fe4b842ae..523fb2d9e 100644 --- a/src/builtin_read.cpp +++ b/src/builtin_read.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -222,7 +222,7 @@ static int read_interactive(wcstring &buff, int nchars, bool shell, bool silent, reader_set_exit_on_interrupt(true); reader_set_silent_status(silent); - reader_set_buffer(commandline, wcslen(commandline)); + reader_set_buffer(commandline, std::wcslen(commandline)); proc_push_interactive(1); event_fire_generic(L"fish_prompt"); @@ -317,7 +317,7 @@ static int read_one_char_at_a_time(int fd, wcstring &buff, int nchars, bool spli res = (unsigned char)b; finished = true; } else { - size_t sz = mbrtowc(&res, &b, 1, &state); + size_t sz = std::mbrtowc(&res, &b, 1, &state); if (sz == (size_t)-1) { memset(&state, 0, sizeof(state)); } else if (sz != (size_t)-2) { diff --git a/src/builtin_realpath.cpp b/src/builtin_realpath.cpp index 89a1dab56..552eae5c1 100644 --- a/src/builtin_realpath.cpp +++ b/src/builtin_realpath.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "builtin.h" #include "builtin_realpath.h" diff --git a/src/builtin_set.cpp b/src/builtin_set.cpp index e538689ca..c57b1d60f 100644 --- a/src/builtin_set.cpp +++ b/src/builtin_set.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -275,7 +275,7 @@ static bool validate_path_warning_on_colons(const wchar_t *cmd, continue; } - const wchar_t *colon = wcschr(dir.c_str(), L':'); + const wchar_t *colon = std::wcschr(dir.c_str(), L':'); bool looks_like_colon_sep = colon && colon[1]; if (!looks_like_colon_sep && any_success) { // Once we have one valid entry, skip the remaining ones unless we might warn. @@ -297,7 +297,7 @@ static bool validate_path_warning_on_colons(const wchar_t *cmd, streams.err.append_format(BUILTIN_SET_PATH_ERROR, cmd, key, dir.c_str(), strerror(errno)); streams.err.append_format(BUILTIN_SET_PATH_HINT, cmd, key, key, - wcschr(dir.c_str(), L':') + 1); + std::wcschr(dir.c_str(), L':') + 1); } } return any_success; @@ -365,7 +365,7 @@ static int env_set_reporting_errors(const wchar_t *cmd, const wchar_t *key, int /// is modified to omit the index expression leaving just the var name. static int parse_index(std::vector &indexes, wchar_t *src, int scope, io_streams_t &streams, const environment_t &vars) { - wchar_t *p = wcschr(src, L'['); + wchar_t *p = std::wcschr(src, L'['); if (!p) return 0; // no slices so nothing for us to do *p = L'\0'; // split the var name from the indexes/slices p++; @@ -609,7 +609,7 @@ static int builtin_set_show(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, continue; } - if (wcschr(arg, L'[')) { + if (std::wcschr(arg, L'[')) { streams.err.append_format( _(L"%ls: `set --show` does not allow slices with the var names\n"), cmd); builtin_print_help(parser, streams, cmd, streams.err); diff --git a/src/builtin_set.h b/src/builtin_set.h index 134fea28b..af930ad23 100644 --- a/src/builtin_set.h +++ b/src/builtin_set.h @@ -2,7 +2,7 @@ #ifndef FISH_BUILTIN_SET_H #define FISH_BUILTIN_SET_H -#include +#include #include diff --git a/src/builtin_set_color.h b/src/builtin_set_color.h index 65647018a..f35d57936 100644 --- a/src/builtin_set_color.h +++ b/src/builtin_set_color.h @@ -2,7 +2,7 @@ #ifndef FISH_BUILTIN_SET_COLOR_H #define FISH_BUILTIN_SET_COLOR_H -#include +#include #include diff --git a/src/builtin_source.cpp b/src/builtin_source.cpp index 8784b0603..442e81784 100644 --- a/src/builtin_source.cpp +++ b/src/builtin_source.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "builtin.h" #include "builtin_source.h" @@ -39,7 +39,7 @@ int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) { struct stat buf; const wchar_t *fn, *fn_intern; - if (argc == optind || wcscmp(argv[optind], L"-") == 0) { + if (argc == optind || std::wcscmp(argv[optind], L"-") == 0) { // Either a bare `source` which means to implicitly read from stdin or an explicit `-`. if (argc == optind && isatty(streams.stdin_fd)) { // Don't implicitly read from the terminal. diff --git a/src/builtin_status.cpp b/src/builtin_status.cpp index 9a6b66c26..0f59405cd 100644 --- a/src/builtin_status.cpp +++ b/src/builtin_status.cpp @@ -2,7 +2,7 @@ #include "config.h" // IWYU pragma: keep #include -#include +#include #include @@ -77,11 +77,11 @@ const enum_map status_enum_map[] = { enum { TEST_FEATURE_ON, TEST_FEATURE_OFF, TEST_FEATURE_NOT_RECOGNIZED }; int job_control_str_to_mode(const wchar_t *mode, wchar_t *cmd, io_streams_t &streams) { - if (wcscmp(mode, L"full") == 0) { + if (std::wcscmp(mode, L"full") == 0) { return JOB_CONTROL_ALL; - } else if (wcscmp(mode, L"interactive") == 0) { + } else if (std::wcscmp(mode, L"interactive") == 0) { return JOB_CONTROL_INTERACTIVE; - } else if (wcscmp(mode, L"none") == 0) { + } else if (std::wcscmp(mode, L"none") == 0) { return JOB_CONTROL_NONE; } streams.err.append_format(L"%ls: Invalid job control mode '%ls'\n", cmd, mode); @@ -127,7 +127,7 @@ static bool set_status_cmd(wchar_t *const cmd, status_cmd_opts_t &opts, status_c wchar_t err_text[1024]; const wchar_t *subcmd_str1 = enum_to_str(opts.status_cmd, status_enum_map); const wchar_t *subcmd_str2 = enum_to_str(sub_cmd, status_enum_map); - swprintf(err_text, sizeof(err_text) / sizeof(wchar_t), + std::swprintf(err_text, sizeof(err_text) / sizeof(wchar_t), _(L"you cannot do both '%ls' and '%ls' in the same invocation"), subcmd_str1, subcmd_str2); streams.err.append_format(BUILTIN_ERR_COMBO2, cmd, err_text); diff --git a/src/builtin_string.cpp b/src/builtin_string.cpp index 8b44f452e..a62392299 100644 --- a/src/builtin_string.cpp +++ b/src/builtin_string.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include @@ -189,13 +189,13 @@ static int handle_flag_1(wchar_t **argv, parser_t &parser, io_streams_t &streams const wchar_t *cmd = argv[0]; if (opts->style_valid) { - if (wcscmp(w.woptarg, L"script") == 0) { + if (std::wcscmp(w.woptarg, L"script") == 0) { opts->escape_style = STRING_STYLE_SCRIPT; - } else if (wcscmp(w.woptarg, L"url") == 0) { + } else if (std::wcscmp(w.woptarg, L"url") == 0) { opts->escape_style = STRING_STYLE_URL; - } else if (wcscmp(w.woptarg, L"var") == 0) { + } else if (std::wcscmp(w.woptarg, L"var") == 0) { opts->escape_style = STRING_STYLE_VAR; - } else if (wcscmp(w.woptarg, L"regex") == 0) { + } else if (std::wcscmp(w.woptarg, L"regex") == 0) { opts->escape_style = STRING_STYLE_REGEX; } else { string_error(streams, _(L"%ls: Invalid escape style '%ls'\n"), cmd, w.woptarg); @@ -949,7 +949,7 @@ bool literal_replacer_t::replace_matches(const wcstring &arg) { replacement_occurred = true; result = arg; } else { - auto &cmp_func = opts.ignore_case ? wcsncasecmp : wcsncmp; + auto &cmp_func = opts.ignore_case ? wcsncasecmp : std::wcsncmp; const wchar_t *cur = arg.c_str(); const wchar_t *end = cur + arg.size(); while (cur < end) { @@ -1311,13 +1311,13 @@ int builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv) { return STATUS_INVALID_ARGS; } - if (wcscmp(argv[1], L"-h") == 0 || wcscmp(argv[1], L"--help") == 0) { + if (std::wcscmp(argv[1], L"-h") == 0 || std::wcscmp(argv[1], L"--help") == 0) { builtin_print_help(parser, streams, L"string", streams.out); return STATUS_CMD_OK; } const string_subcommand *subcmd = &string_subcommands[0]; - while (subcmd->name != 0 && wcscmp(subcmd->name, argv[1]) != 0) { + while (subcmd->name != 0 && std::wcscmp(subcmd->name, argv[1]) != 0) { subcmd++; } if (!subcmd->handler) { diff --git a/src/builtin_string.h b/src/builtin_string.h index 0f530c641..22dcfb28e 100644 --- a/src/builtin_string.h +++ b/src/builtin_string.h @@ -2,7 +2,7 @@ #ifndef FISH_BUILTIN_STRING_H #define FISH_BUILTIN_STRING_H -#include +#include #include diff --git a/src/builtin_test.cpp b/src/builtin_test.cpp index 327b0ea79..b49fa7bb6 100644 --- a/src/builtin_test.cpp +++ b/src/builtin_test.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include @@ -817,7 +817,7 @@ int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) { // Whether we are invoked with bracket '[' or not. wchar_t *program_name = argv[0]; - const bool is_bracket = !wcscmp(program_name, L"["); + const bool is_bracket = !std::wcscmp(program_name, L"["); size_t argc = 0; while (argv[argc + 1]) argc++; @@ -825,7 +825,7 @@ int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) { // If we're bracket, the last argument ought to be ]; we ignore it. Note that argc is the number // of arguments after the command name; thus argv[argc] is the last argument. if (is_bracket) { - if (!wcscmp(argv[argc], L"]")) { + if (!std::wcscmp(argv[argc], L"]")) { // Ignore the closing bracket from now on. argc--; } else { diff --git a/src/builtin_ulimit.h b/src/builtin_ulimit.h index 1676b5a35..54de72642 100644 --- a/src/builtin_ulimit.h +++ b/src/builtin_ulimit.h @@ -2,7 +2,7 @@ #ifndef FISH_BUILTIN_ULIMIT_H #define FISH_BUILTIN_ULIMIT_H -#include +#include #include diff --git a/src/builtin_wait.cpp b/src/builtin_wait.cpp index 2c596a2bd..b517f7a78 100644 --- a/src/builtin_wait.cpp +++ b/src/builtin_wait.cpp @@ -134,11 +134,11 @@ static bool iswnumeric(const wchar_t *n) { /// See if the process described by \c proc matches the commandline \c cmd. static bool match_pid(const wcstring &cmd, const wchar_t *proc) { // Don't wait for itself - if (wcscmp(proc, L"wait") == 0) return false; + if (std::wcscmp(proc, L"wait") == 0) return false; // Get the command to match against. We're only interested in the last path component. const wcstring base_cmd = wbasename(cmd); - return wcscmp(proc, base_cmd.c_str()) == 0; + return std::wcscmp(proc, base_cmd.c_str()) == 0; } /// It should search the job list for something matching the given proc. diff --git a/src/color.cpp b/src/color.cpp index 4cad60450..4dd60ef46 100644 --- a/src/color.cpp +++ b/src/color.cpp @@ -4,7 +4,7 @@ #include #include #include -#include // IWYU pragma: keep +#include // IWYU pragma: keep #include "color.h" #include "common.h" diff --git a/src/common.cpp b/src/common.cpp index ac8705ff8..ba7da173d 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #ifdef HAVE_EXECINFO_H #include @@ -231,7 +231,7 @@ demangled_backtrace(int max_frames, int skip_levels) { // if this check is not done. // // Hack to avoid showing backtraces in the tester. - // if (program_name && !wcscmp(program_name, L"(ignore)")) return; + // if (program_name && !std::wcscmp(program_name, L"(ignore)")) return; debug_shared(msg_level, L"Backtrace:"); std::vector bt = demangled_backtrace(frame_count, skip_levels + 2); @@ -254,7 +254,7 @@ int fgetws2(wcstring *s, FILE *f) { while (1) { errno = 0; - c = fgetwc(f); + c = std::fgetwc(f); if (errno == EILSEQ || errno == EINTR) { continue; } @@ -309,17 +309,17 @@ static wcstring str2wcs_internal(const char *in, const size_t in_len) { wchar_t wc = 0; if ((in[in_pos] & 0xF8) == 0xF8) { - // Protect against broken mbrtowc() implementations which attempt to encode UTF-8 + // Protect against broken std::mbrtowc() implementations which attempt to encode UTF-8 // sequences longer than four bytes (e.g., OS X Snow Leopard). use_encode_direct = true; } else if (sizeof(wchar_t) == 2 && //!OCLINT(constant if expression) (in[in_pos] & 0xF8) == 0xF0) { // Assume we are in a UTF-16 environment (e.g., Cygwin) using a UTF-8 encoding. // The bits set check will be true for a four byte UTF-8 sequence that requires - // two UTF-16 chars. Something that doesn't work with our simple use of mbrtowc(). + // two UTF-16 chars. Something that doesn't work with our simple use of std::mbrtowc(). use_encode_direct = true; } else { - ret = mbrtowc(&wc, &in[in_pos], in_len - in_pos, &state); + ret = std::mbrtowc(&wc, &in[in_pos], in_len - in_pos, &state); // Determine whether to encode this character with our crazy scheme. if (wc >= ENCODE_DIRECT_BASE && wc < ENCODE_DIRECT_BASE + 256) { use_encode_direct = true; @@ -398,7 +398,7 @@ char *wcs2str(const wchar_t *in, size_t len) { return out; } -char *wcs2str(const wchar_t *in) { return wcs2str(in, wcslen(in)); } +char *wcs2str(const wchar_t *in) { return wcs2str(in, std::wcslen(in)); } char *wcs2str(const wcstring &in) { return wcs2str(in.c_str(), in.length()); } /// This function is distinguished from wcs2str_internal in that it allows embedded null bytes. @@ -424,7 +424,7 @@ std::string wcs2string(const wcstring &input) { result.append(converted, 1); } else { memset(converted, 0, sizeof converted); - size_t len = wcrtomb(converted, wc, &state); + size_t len = std::wcrtomb(converted, wc, &state); if (len == (size_t)-1) { debug(1, L"Wide character U+%4X has no narrow representation", wc); memset(&state, 0, sizeof(state)); @@ -464,7 +464,7 @@ static char *wcs2str_internal(const wchar_t *in, char *out) { out[out_pos++] = (unsigned char)in[in_pos]; } } else { - size_t len = wcrtomb(&out[out_pos], in[in_pos], &state); + size_t len = std::wcrtomb(&out[out_pos], in[in_pos], &state); if (len == (size_t)-1) { debug(1, L"Wide character U+%4X has no narrow representation", in[in_pos]); memset(&state, 0, sizeof(state)); @@ -484,7 +484,7 @@ static bool can_be_encoded(wchar_t wc) { char converted[MB_LEN_MAX]; mbstate_t state = {}; - return wcrtomb(converted, wc, &state) != (size_t)-1; + return std::wcrtomb(converted, wc, &state) != (size_t)-1; } wcstring format_string(const wchar_t *format, ...) { @@ -528,7 +528,7 @@ void append_formatv(wcstring &target, const wchar_t *format, va_list va_orig) { // Try printing. va_list va; va_copy(va, va_orig); - status = vswprintf(buff, size / sizeof(wchar_t), format, va); + status = std::vswprintf(buff, size / sizeof(wchar_t), format, va); va_end(va); } @@ -647,16 +647,16 @@ ssize_t read_loop(int fd, void *buff, size_t count) { /// like `debug()`. It is only intended to supress diagnostic noise from testing things like the /// fish parser where we expect a lot of diagnostic messages due to testing error conditions. bool should_suppress_stderr_for_tests() { - return program_name && !wcscmp(program_name, TESTS_PROGRAM_NAME); + return program_name && !std::wcscmp(program_name, TESTS_PROGRAM_NAME); } static void debug_shared(const wchar_t level, const wcstring &msg) { pid_t current_pid; if (!is_forked_child()) { - fwprintf(stderr, L"<%lc> %ls: %ls\n", (unsigned long)level, program_name, msg.c_str()); + std::fwprintf(stderr, L"<%lc> %ls: %ls\n", (unsigned long)level, program_name, msg.c_str()); } else { current_pid = getpid(); - fwprintf(stderr, L"<%lc> %ls: %d: %ls\n", (unsigned long)level, program_name, current_pid, + std::fwprintf(stderr, L"<%lc> %ls: %d: %ls\n", (unsigned long)level, program_name, current_pid, msg.c_str()); } } @@ -810,7 +810,7 @@ wcstring reformat_for_screen(const wcstring &msg) { int tok_width = 0; // Tokenize on whitespace, and also calculate the width of the token. - while (*pos && (!wcschr(L" \n\r\t", *pos))) { + while (*pos && (!std::wcschr(L" \n\r\t", *pos))) { // Check is token is wider than one line. If so we mark it as an overflow and break // the token. if ((tok_width + fish_wcwidth(*pos)) > (screen_width - 1)) { @@ -1178,7 +1178,7 @@ wcstring escape_string(const wchar_t *in, escape_flags_t flags, escape_string_st switch (style) { case STRING_STYLE_SCRIPT: { - escape_string_script(in, wcslen(in), result, flags); + escape_string_script(in, std::wcslen(in), result, flags); break; } case STRING_STYLE_URL: { @@ -1493,10 +1493,10 @@ static bool unescape_string_internal(const wchar_t *const input, const size_t in // Note that this only recognizes %self if the string is literally %self. // %self/foo will NOT match this. if (unescape_special && input_position == 0 && - !wcscmp(input, PROCESS_EXPAND_SELF_STR)) { + !std::wcscmp(input, PROCESS_EXPAND_SELF_STR)) { to_append_or_none = PROCESS_EXPAND_SELF; input_position += - wcslen(PROCESS_EXPAND_SELF_STR) - 1; // skip over 'self' part. + std::wcslen(PROCESS_EXPAND_SELF_STR) - 1; // skip over 'self' part. } break; } @@ -1691,7 +1691,7 @@ bool unescape_string(const wchar_t *input, wcstring *output, unescape_flags_t es bool success = false; switch (style) { case STRING_STYLE_SCRIPT: { - success = unescape_string_internal(input, wcslen(input), output, escape_special); + success = unescape_string_internal(input, std::wcslen(input), output, escape_special); break; } case STRING_STYLE_URL: { @@ -1884,7 +1884,7 @@ bool string_suffixes_string(const wcstring &proposed_suffix, const wcstring &val } bool string_suffixes_string(const wchar_t *proposed_suffix, const wcstring &value) { - size_t suffix_size = wcslen(proposed_suffix); + size_t suffix_size = std::wcslen(proposed_suffix); return suffix_size <= value.size() && value.compare(value.size() - suffix_size, suffix_size, proposed_suffix) == 0; } diff --git a/src/common.h b/src/common.h index 7c4f84c79..c927e0c11 100644 --- a/src/common.h +++ b/src/common.h @@ -272,7 +272,7 @@ inline bool is_whitespace(const wchar_t *input) { return is_whitespace(wcstring( [[noreturn]] void __fish_assert(const char *msg, const char *file, size_t line, int error); -/// Shorthand for wgettext call in situations where a C-style string is needed (e.g., fwprintf()). +/// Shorthand for wgettext call in situations where a C-style string is needed (e.g., std::fwprintf()). #define _(wstr) wgettext(wstr).c_str() /// Noop, used to tell xgettext that a string should be translated. Use this when a string cannot be @@ -555,7 +555,7 @@ inline bool bool_from_string(const std::string &x) { } } -inline bool bool_from_string(const wcstring &x) { return !x.empty() && wcschr(L"YTyt1", x.at(0)); } +inline bool bool_from_string(const wcstring &x) { return !x.empty() && std::wcschr(L"YTyt1", x.at(0)); } wchar_t **make_null_terminated_array(const wcstring_list_t &lst); char **make_null_terminated_array(const std::vector &lst); @@ -933,7 +933,7 @@ static T str_to_enum(const wchar_t *name, const enum_map map[], int len) { while (left < right) { size_t mid = left + (right - left) / 2; - int cmp = wcscmp(name, map[mid].str); + int cmp = std::wcscmp(name, map[mid].str); if (cmp < 0) { right = mid; // name was smaller than mid } else if (cmp > 0) { diff --git a/src/complete.cpp b/src/complete.cpp index b0ae97cc1..30bab6506 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -203,7 +203,7 @@ static complete_flags_t resolve_auto_space(const wcstring &comp, complete_flags_ if (flags & COMPLETE_AUTO_SPACE) { new_flags &= ~COMPLETE_AUTO_SPACE; size_t len = comp.size(); - if (len > 0 && (wcschr(L"/=@:", comp.at(len - 1)) != 0)) new_flags |= COMPLETE_NO_SPACE; + if (len > 0 && (std::wcschr(L"/=@:", comp.at(len - 1)) != 0)) new_flags |= COMPLETE_NO_SPACE; } return new_flags; } @@ -402,7 +402,7 @@ void append_completion(std::vector *completions, wcstring comp, wc /// after a completion run to make sure that there are no stale completions. bool completer_t::condition_test(const wcstring &condition) { if (condition.empty()) { - // fwprintf( stderr, L"No condition specified\n" ); + // std::fwprintf( stderr, L"No condition specified\n" ); return true; } @@ -1238,10 +1238,10 @@ bool completer_t::try_complete_user(const wcstring &str) { const wchar_t *cmd = str.c_str(); const wchar_t *first_char = cmd; - if (*first_char != L'~' || wcschr(first_char, L'/')) return false; + if (*first_char != L'~' || std::wcschr(first_char, L'/')) return false; const wchar_t *user_name = first_char + 1; - const wchar_t *name_end = wcschr(user_name, L'~'); + const wchar_t *name_end = std::wcschr(user_name, L'~'); if (name_end) return false; double start_time = timef(); @@ -1260,7 +1260,7 @@ bool completer_t::try_complete_user(const wcstring &str) { } const wcstring pw_name_str = str2wcstring(pw->pw_name); const wchar_t *pw_name = pw_name_str.c_str(); - if (wcsncmp(user_name, pw_name, name_len) == 0) { + if (std::wcsncmp(user_name, pw_name, name_len) == 0) { wcstring desc = format_string(COMPLETE_USER_DESC, pw_name); // Append a user name append_completion(&this->completions, &pw_name[name_len], desc, COMPLETE_NO_SPACE); diff --git a/src/env.cpp b/src/env.cpp index b30ec18ed..13d95763e 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #if HAVE_CURSES_H #include @@ -308,7 +308,7 @@ using string_set_t = const wchar_t *const[]; template bool string_set_contains(const T &set, const wchar_t *val) { for (const wchar_t *entry : set) { - if (!wcscmp(val, entry)) return true; + if (!std::wcscmp(val, entry)) return true; } return false; } @@ -319,7 +319,7 @@ static bool is_read_only(const wchar_t *val) { L"PWD", L"SHLVL", L"history", L"pipestatus", L"status", L"version", L"FISH_VERSION", L"fish_pid", L"hostname", L"_", L"fish_private_mode"}; return string_set_contains(env_read_only, val) || - (in_private_mode() && wcscmp(L"fish_history", val) == 0); + (in_private_mode() && std::wcscmp(L"fish_history", val) == 0); } static bool is_read_only(const wcstring &val) { return is_read_only(val.c_str()); } @@ -443,15 +443,15 @@ static bool does_term_support_setting_title(const environment_t &vars) { const wcstring term_str = term_var->as_string(); const wchar_t *term = term_str.c_str(); bool recognized = contains(title_terms, term_var->as_string()); - if (!recognized) recognized = !wcsncmp(term, L"xterm-", wcslen(L"xterm-")); - if (!recognized) recognized = !wcsncmp(term, L"screen-", wcslen(L"screen-")); - if (!recognized) recognized = !wcsncmp(term, L"tmux-", wcslen(L"tmux-")); + if (!recognized) recognized = !std::wcsncmp(term, L"xterm-", std::wcslen(L"xterm-")); + if (!recognized) recognized = !std::wcsncmp(term, L"screen-", std::wcslen(L"screen-")); + if (!recognized) recognized = !std::wcsncmp(term, L"tmux-", std::wcslen(L"tmux-")); if (!recognized) { - if (wcscmp(term, L"linux") == 0) return false; - if (wcscmp(term, L"dumb") == 0) return false; + if (std::wcscmp(term, L"linux") == 0) return false; + if (std::wcscmp(term, L"dumb") == 0) return false; // NetBSD - if (wcscmp(term, L"vt100") == 0) return false; - if (wcscmp(term, L"wsvt25") == 0) return false; + if (std::wcscmp(term, L"vt100") == 0) return false; + if (std::wcscmp(term, L"wsvt25") == 0) return false; char buf[PATH_MAX]; int retval = ttyname_r(STDIN_FILENO, buf, PATH_MAX); diff --git a/src/env_universal_common.cpp b/src/env_universal_common.cpp index 7fd8bf1e9..f30cbad56 100644 --- a/src/env_universal_common.cpp +++ b/src/env_universal_common.cpp @@ -28,7 +28,7 @@ #include // IWYU pragma: keep #include // IWYU pragma: keep #include -#include +#include #include #include @@ -136,7 +136,7 @@ static bool match(const wchar_t **inout_cursor, const char *cmd) { static bool is_universal_safe_to_encode_directly(wchar_t c) { if (c < 32 || c > 128) return false; - return iswalnum(c) || wcschr(L"/_", c); + return iswalnum(c) || std::wcschr(L"/_", c); } /// Escape specified string. @@ -850,7 +850,7 @@ static const wchar_t *skip_spaces(const wchar_t *str) { bool env_universal_t::populate_1_variable(const wchar_t *input, env_var_t::env_var_flags_t flags, var_table_t *vars, wcstring *storage) { const wchar_t *str = skip_spaces(input); - const wchar_t *colon = wcschr(str, L':'); + const wchar_t *colon = std::wcschr(str, L':'); if (!colon) return false; // Parse out the value into storage, and decode it into a variable. diff --git a/src/event.cpp b/src/event.cpp index 79bbdd693..d2ae1959a 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -191,11 +191,11 @@ wcstring event_get_desc(const event_t &evt) { #if 0 static void show_all_handlers(void) { - fwprintf(stdout, L"event handlers:\n"); + std::fwprintf(stdout, L"event handlers:\n"); for (event_list_t::const_iterator iter = events.begin(); iter != events.end(); ++iter) { const event_t *foo = *iter; wcstring tmp = event_get_desc(foo); - fwprintf(stdout, L" handler now %ls\n", tmp.c_str()); + std::fwprintf(stdout, L" handler now %ls\n", tmp.c_str()); } } #endif diff --git a/src/expand.cpp b/src/expand.cpp index 77ed98c1b..4c7532fc8 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #ifdef HAVE_SYS_SYSCTL_H @@ -74,7 +74,7 @@ static bool expand_is_clean(const wcstring &in) { if (in.empty()) return true; // Test characters that have a special meaning in the first character position. - if (wcschr(UNCLEAN_FIRST, in.at(0)) != NULL) return false; + if (std::wcschr(UNCLEAN_FIRST, in.at(0)) != NULL) return false; // Test characters that have a special meaning in any character position. return in.find_first_of(UNCLEAN) == wcstring::npos; @@ -572,7 +572,7 @@ static expand_error_t expand_braces(const wcstring &instr, expand_flags_t flags, } length_preceding_braces = (brace_begin - in); - length_following_braces = wcslen(brace_end) - 1; + length_following_braces = std::wcslen(brace_end) - 1; tot_len = length_preceding_braces + length_following_braces; item_begin = brace_begin + 1; for (const wchar_t *pos = (brace_begin + 1); true; pos++) { @@ -1218,7 +1218,7 @@ maybe_t expand_abbreviation(const wcstring &src) { std::map get_abbreviations() { // TODO: try to make this cheaper const auto &vars = env_stack_t::principal(); - const size_t fish_abbr_len = wcslen(L"_fish_abbr_"); + const size_t fish_abbr_len = std::wcslen(L"_fish_abbr_"); auto names = vars.get_names(0); std::map result; for (const wcstring &name : names) { diff --git a/src/fallback.cpp b/src/fallback.cpp index 485c93b51..f028e3f05 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -18,7 +18,7 @@ #include // IWYU pragma: keep #include // IWYU pragma: keep #include -#include +#include #include #include #if HAVE_GETTEXT @@ -37,7 +37,7 @@ #include #endif #include // IWYU pragma: keep -#include // IWYU pragma: keep +#include // IWYU pragma: keep #include "common.h" // IWYU pragma: keep #include "fallback.h" // IWYU pragma: keep @@ -75,7 +75,7 @@ int fish_mkstemp_cloexec(char *name_template) { /// are not referenced in this file. // cppcheck-suppress unusedFunction [[gnu::unused]] static wchar_t *wcsdup_fallback(const wchar_t *in) { - size_t len = wcslen(in); + size_t len = std::wcslen(in); wchar_t *out = (wchar_t *)malloc(sizeof(wchar_t) * (len + 1)); if (out == 0) { return 0; @@ -397,7 +397,7 @@ int flock(int fd, int op) { // thread-specific locale. double fish_compat::wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc) { locale_t prev_locale = uselocale(loc); - double ret = wcstod(enptr, endptr); + double ret = std::wcstod(enptr, endptr); uselocale(prev_locale); return ret; } diff --git a/src/fallback.h b/src/fallback.h index 93745df55..50796cad6 100644 --- a/src/fallback.h +++ b/src/fallback.h @@ -10,7 +10,7 @@ // between the weak linking of `wcsdup` and `wcscasecmp` via `#define`s below and the declarations // in . At least on OS X if we don't do this we get compilation errors do to the macro // substitution if wchar.h is included after this header. -#include // IWYU pragma: keep +#include // IWYU pragma: keep /// The column width of ambiguous East Asian characters. extern int g_fish_ambiguous_width; @@ -137,7 +137,7 @@ wchar_t *wcsndup(const wchar_t *in, size_t c); #ifndef HAVE_WCSLCPY /// Copy src to string dst of size siz. At most siz-1 characters will be copied. Always NUL -/// terminates (unless siz == 0). Returns wcslen(src); if retval >= siz, truncation occurred. +/// terminates (unless siz == 0). Returns std::wcslen(src); if retval >= siz, truncation occurred. /// /// This is the OpenBSD strlcpy function, modified for wide characters, and renamed to reflect this /// change. diff --git a/src/fish.cpp b/src/fish.cpp index 236c28a1b..4ec0ab190 100644 --- a/src/fish.cpp +++ b/src/fish.cpp @@ -30,7 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA #include #include #include -#include +#include #include #include @@ -250,7 +250,7 @@ static int fish_parse_opt(int argc, char **argv, fish_cmd_opts_t *opts) { if (tmp >= 0 && tmp <= 10 && !*end && !errno) { debug_level = (int)tmp; } else { - fwprintf(stderr, _(L"Invalid value '%s' for debug-level flag"), optarg); + std::fwprintf(stderr, _(L"Invalid value '%s' for debug-level flag"), optarg); exit(1); } break; @@ -285,7 +285,7 @@ static int fish_parse_opt(int argc, char **argv, fish_cmd_opts_t *opts) { break; } case 'v': { - fwprintf(stdout, _(L"%s, version %s\n"), PACKAGE_NAME, get_fish_version()); + std::fwprintf(stdout, _(L"%s, version %s\n"), PACKAGE_NAME, get_fish_version()); exit(0); break; } @@ -299,7 +299,7 @@ static int fish_parse_opt(int argc, char **argv, fish_cmd_opts_t *opts) { if (tmp > 0 && tmp <= 128 && !*end && !errno) { debug_stack_frames = (int)tmp; } else { - fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag"), optarg); + std::fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag"), optarg); exit(1); } break; diff --git a/src/fish_indent.cpp b/src/fish_indent.cpp index 26c67e014..61633dc10 100644 --- a/src/fish_indent.cpp +++ b/src/fish_indent.cpp @@ -24,9 +24,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA #include #include #include -#include #include +#include #include #include #include @@ -55,7 +55,7 @@ static int ret = 0; static wcstring read_file(FILE *f) { wcstring result; while (1) { - wint_t c = fgetwc(f); + wint_t c = std::fgetwc(f); if (c == WEOF) { if (ferror(f)) { @@ -157,7 +157,7 @@ static void dump_node(indent_t node_indent, const parse_node_t &node, const wcst nextc_str[1] = L'c'; nextc_str[2] = nextc + '@'; } - fwprintf(stderr, L"{off %4u, len %4u, indent %2u, kw %ls, %ls} [%ls|%ls|%ls]\n", + std::fwprintf(stderr, L"{off %4u, len %4u, indent %2u, kw %ls, %ls} [%ls|%ls|%ls]\n", node.source_start, node.source_length, node_indent, keyword_description(node.keyword), token_type_description(node.type), prevc_str, source_txt.c_str(), nextc_str); } @@ -252,7 +252,7 @@ static wcstring prettify(const wcstring &src, bool do_indent) { if (dump_parse_tree) { const wcstring dump = parse_dump_tree(parse_tree, src); - fwprintf(stderr, L"%ls\n", dump.c_str()); + std::fwprintf(stderr, L"%ls\n", dump.c_str()); } // We may have a forest of disconnected trees on a parse failure. We have to handle all nodes @@ -442,7 +442,7 @@ int main(int argc, char *argv[]) { break; } case 'v': { - fwprintf(stderr, _(L"%ls, version %s\n"), program_name, get_fish_version()); + std::fwprintf(stderr, _(L"%ls, version %s\n"), program_name, get_fish_version()); exit(0); break; } @@ -472,7 +472,7 @@ int main(int argc, char *argv[]) { if (tmp >= 0 && tmp <= 10 && !*end && !errno) { debug_level = (int)tmp; } else { - fwprintf(stderr, _(L"Invalid value '%s' for debug-level flag"), optarg); + std::fwprintf(stderr, _(L"Invalid value '%s' for debug-level flag"), optarg); exit(1); } break; @@ -487,7 +487,7 @@ int main(int argc, char *argv[]) { if (tmp > 0 && tmp <= 128 && !*end && !errno) { debug_stack_frames = (int)tmp; } else { - fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag"), optarg); + std::fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag"), optarg); exit(1); } break; @@ -506,7 +506,7 @@ int main(int argc, char *argv[]) { wcstring src; if (argc == 0) { if (output_type == output_type_file) { - fwprintf(stderr, _(L"Expected file path to read/write for -w:\n\n $ %ls -w foo.fish\n"), + std::fwprintf(stderr, _(L"Expected file path to read/write for -w:\n\n $ %ls -w foo.fish\n"), program_name); exit(1); } @@ -518,11 +518,11 @@ int main(int argc, char *argv[]) { fclose(fh); output_location = *argv; } else { - fwprintf(stderr, _(L"Opening \"%s\" failed: %s\n"), *argv, strerror(errno)); + std::fwprintf(stderr, _(L"Opening \"%s\" failed: %s\n"), *argv, strerror(errno)); exit(1); } } else { - fwprintf(stderr, _(L"Too many arguments\n")); + std::fwprintf(stderr, _(L"Too many arguments\n")); exit(1); } @@ -544,11 +544,11 @@ int main(int argc, char *argv[]) { case output_type_file: { FILE *fh = fopen(output_location, "w"); if (fh) { - fputws(output_wtext.c_str(), fh); + std::fputws(output_wtext.c_str(), fh); fclose(fh); exit(0); } else { - fwprintf(stderr, _(L"Opening \"%s\" failed: %s\n"), output_location, + std::fwprintf(stderr, _(L"Opening \"%s\" failed: %s\n"), output_location, strerror(errno)); exit(1); } @@ -564,6 +564,6 @@ int main(int argc, char *argv[]) { } } - fputws(str2wcstring(colored_output).c_str(), stdout); + std::fputws(str2wcstring(colored_output).c_str(), stdout); return ret; } diff --git a/src/fish_key_reader.cpp b/src/fish_key_reader.cpp index 28a432096..fba073944 100644 --- a/src/fish_key_reader.cpp +++ b/src/fish_key_reader.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include @@ -54,12 +54,12 @@ static bool should_exit(wchar_t wc) { recent_chars[3] = c; if (c == shell_modes.c_cc[VINTR]) { if (recent_chars[2] == shell_modes.c_cc[VINTR]) return true; - fwprintf(stderr, L"Press [ctrl-%c] again to exit\n", shell_modes.c_cc[VINTR] + 0x40); + std::fwprintf(stderr, L"Press [ctrl-%c] again to exit\n", shell_modes.c_cc[VINTR] + 0x40); return false; } if (c == shell_modes.c_cc[VEOF]) { if (recent_chars[2] == shell_modes.c_cc[VEOF]) return true; - fwprintf(stderr, L"Press [ctrl-%c] again to exit\n", shell_modes.c_cc[VEOF] + 0x40); + std::fwprintf(stderr, L"Press [ctrl-%c] again to exit\n", shell_modes.c_cc[VEOF] + 0x40); return false; } return memcmp(recent_chars, "exit", 4) == 0 || memcmp(recent_chars, "quit", 4) == 0; @@ -93,41 +93,41 @@ static char *sequence_name(wchar_t wc) { /// Return true if the character must be escaped when used in the sequence of chars to be bound in /// a `bind` command. -static bool must_escape(wchar_t wc) { return wcschr(L"[]()<>{}*\\?$#;&|'\"", wc) != NULL; } +static bool must_escape(wchar_t wc) { return std::wcschr(L"[]()<>{}*\\?$#;&|'\"", wc) != NULL; } static void ctrl_to_symbol(wchar_t *buf, int buf_len, wchar_t wc, bool bind_friendly) { if (ctrl_symbolic_names[wc]) { if (bind_friendly) { - swprintf(buf, buf_len, L"%ls", ctrl_symbolic_names[wc]); + std::swprintf(buf, buf_len, L"%ls", ctrl_symbolic_names[wc]); } else { - swprintf(buf, buf_len, L"\\c%c (or %ls)", wc + 0x40, ctrl_symbolic_names[wc]); + std::swprintf(buf, buf_len, L"\\c%c (or %ls)", wc + 0x40, ctrl_symbolic_names[wc]); } } else { - swprintf(buf, buf_len, L"\\c%c", wc + 0x40); + std::swprintf(buf, buf_len, L"\\c%c", wc + 0x40); } } static void space_to_symbol(wchar_t *buf, int buf_len, wchar_t wc, bool bind_friendly) { if (bind_friendly) { - swprintf(buf, buf_len, L"\\x%X", wc); + std::swprintf(buf, buf_len, L"\\x%X", wc); } else { - swprintf(buf, buf_len, L"\\x%X (aka \"space\")", wc); + std::swprintf(buf, buf_len, L"\\x%X (aka \"space\")", wc); } } static void del_to_symbol(wchar_t *buf, int buf_len, wchar_t wc, bool bind_friendly) { if (bind_friendly) { - swprintf(buf, buf_len, L"\\x%X", wc); + std::swprintf(buf, buf_len, L"\\x%X", wc); } else { - swprintf(buf, buf_len, L"\\x%X (aka \"del\")", wc); + std::swprintf(buf, buf_len, L"\\x%X (aka \"del\")", wc); } } static void ascii_printable_to_symbol(wchar_t *buf, int buf_len, wchar_t wc, bool bind_friendly) { if (bind_friendly && must_escape(wc)) { - swprintf(buf, buf_len, L"\\%c", wc); + std::swprintf(buf, buf_len, L"\\%c", wc); } else { - swprintf(buf, buf_len, L"%c", wc); + std::swprintf(buf, buf_len, L"%c", wc); } } @@ -145,9 +145,9 @@ static wchar_t *char_to_symbol(wchar_t wc, bool bind_friendly) { } else if (wc < 0x80) { // ASCII characters that are not control characters ascii_printable_to_symbol(buf, sizeof(buf) / sizeof(*buf), wc, bind_friendly); } else if (wc <= 0xFFFF) { // BMP Unicode chararacter - swprintf(buf, sizeof(buf) / sizeof(*buf), L"\\u%04X", wc); + std::swprintf(buf, sizeof(buf) / sizeof(*buf), L"\\u%04X", wc); } else { // Non-BMP Unicode chararacter - swprintf(buf, sizeof(buf) / sizeof(*buf), L"\\U%06X", wc); + std::swprintf(buf, sizeof(buf) / sizeof(*buf), L"\\U%06X", wc); } return buf; @@ -159,23 +159,23 @@ static void add_char_to_bind_command(wchar_t wc, std::vector &bind_char static void output_bind_command(std::vector &bind_chars) { if (bind_chars.size()) { - fputws(L"bind ", stdout); + std::fputws(L"bind ", stdout); for (size_t i = 0; i < bind_chars.size(); i++) { - fputws(char_to_symbol(bind_chars[i], true), stdout); + std::fputws(char_to_symbol(bind_chars[i], true), stdout); } - fputws(L" 'do something'\n", stdout); + std::fputws(L" 'do something'\n", stdout); bind_chars.clear(); } } static void output_info_about_char(wchar_t wc) { - fwprintf(stderr, L"hex: %4X char: %ls\n", wc, char_to_symbol(wc, false)); + std::fwprintf(stderr, L"hex: %4X char: %ls\n", wc, char_to_symbol(wc, false)); } static bool output_matching_key_name(wchar_t wc) { char *name = sequence_name(wc); if (name) { - fwprintf(stdout, L"bind -k %s 'do something'\n", name); + std::fwprintf(stdout, L"bind -k %s 'do something'\n", name); free(name); return true; } @@ -187,11 +187,11 @@ static double output_elapsed_time(double prev_tstamp, bool first_char_seen) { double now = timef(); long long int delta_tstamp_us = 1000000 * (now - prev_tstamp); - if (delta_tstamp_us >= 200000 && first_char_seen) fputwc(L'\n', stderr); + if (delta_tstamp_us >= 200000 && first_char_seen) std::fputwc(L'\n', stderr); if (delta_tstamp_us >= 1000000) { - fwprintf(stderr, L" "); + std::fwprintf(stderr, L" "); } else { - fwprintf(stderr, L"(%3lld.%03lld ms) ", delta_tstamp_us / 1000, delta_tstamp_us % 1000); + std::fwprintf(stderr, L"(%3lld.%03lld ms) ", delta_tstamp_us / 1000, delta_tstamp_us % 1000); } return now; } @@ -202,7 +202,7 @@ static void process_input(bool continuous_mode) { double prev_tstamp = 0.0; std::vector bind_chars; - fwprintf(stderr, L"Press a key\n\n"); + std::fwprintf(stderr, L"Press a key\n\n"); while (keep_running) { wchar_t wc; if (reader_test_and_clear_interrupted()) { @@ -226,7 +226,7 @@ static void process_input(bool continuous_mode) { } if (should_exit(wc)) { - fwprintf(stderr, L"\nExiting at your request.\n"); + std::fwprintf(stderr, L"\nExiting at your request.\n"); break; } @@ -238,7 +238,7 @@ static void process_input(bool continuous_mode) { /// Otherwise just report receipt of the signal. static struct sigaction old_sigactions[32]; static void signal_handler(int signo, siginfo_t *siginfo, void *siginfo_arg) { - fwprintf(stdout, _(L"signal #%d (%ls) received\n"), signo, sig2wcs(signo)); + std::fwprintf(stdout, _(L"signal #%d (%ls) received\n"), signo, sig2wcs(signo)); if (signo == SIGHUP || signo == SIGTERM || signo == SIGABRT || signo == SIGSEGV) { keep_running = false; } @@ -288,11 +288,11 @@ static void setup_and_process_keys(bool continuous_mode) { install_our_signal_handlers(); if (continuous_mode) { - fwprintf(stderr, L"\n"); - fwprintf(stderr, L"To terminate this program type \"exit\" or \"quit\" in this window,\n"); - fwprintf(stderr, L"or press [ctrl-%c] or [ctrl-%c] twice in a row.\n", + std::fwprintf(stderr, L"\n"); + std::fwprintf(stderr, L"To terminate this program type \"exit\" or \"quit\" in this window,\n"); + std::fwprintf(stderr, L"or press [ctrl-%c] or [ctrl-%c] twice in a row.\n", shell_modes.c_cc[VINTR] + 0x40, shell_modes.c_cc[VEOF] + 0x40); - fwprintf(stderr, L"\n"); + std::fwprintf(stderr, L"\n"); } process_input(continuous_mode); @@ -308,7 +308,7 @@ static bool parse_debug_level_flag() { if (tmp >= 0 && tmp <= 10 && !*end && !errno) { debug_level = (int)tmp; } else { - fwprintf(stderr, _(L"Invalid value '%s' for debug-level flag\n"), optarg); + std::fwprintf(stderr, _(L"Invalid value '%s' for debug-level flag\n"), optarg); return false; } @@ -322,7 +322,7 @@ static bool parse_debug_frames_flag() { if (tmp > 0 && tmp <= 128 && !*end && !errno) { debug_stack_frames = (int)tmp; } else { - fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag\n"), optarg); + std::fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag\n"), optarg); return false; } @@ -359,7 +359,7 @@ static bool parse_flags(int argc, char **argv, bool *continuous_mode) { break; } case 'v': { - fwprintf(stdout, L"%s\n", get_fish_version()); + std::fwprintf(stdout, L"%s\n", get_fish_version()); return false; } default: { @@ -374,7 +374,7 @@ static bool parse_flags(int argc, char **argv, bool *continuous_mode) { argc -= optind; if (argc != 0) { - fwprintf(stderr, L"Expected no arguments, got %d\n", argc); + std::fwprintf(stderr, L"Expected no arguments, got %d\n", argc); return false; } @@ -388,7 +388,7 @@ int main(int argc, char **argv) { if (!parse_flags(argc, argv, &continuous_mode)) return 1; if (!isatty(STDIN_FILENO)) { - fwprintf(stderr, L"Stdin must be attached to a tty.\n"); + std::fwprintf(stderr, L"Stdin must be attached to a tty.\n"); return 1; } diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 0e24c3c17..9059cf101 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -114,9 +114,9 @@ static int err_count = 0; static void say(const wchar_t *fmt, ...) { va_list va; va_start(va, fmt); - vfwprintf(stdout, fmt, va); + std::vfwprintf(stdout, fmt, va); va_end(va); - fwprintf(stdout, L"\n"); + std::fwprintf(stdout, L"\n"); } /// Print formatted error string. @@ -130,18 +130,18 @@ static void err(const wchar_t *blah, ...) { // Show errors in red. if (colorize) { - fputws(L"\x1B[31m", stdout); + std::fputws(L"\x1B[31m", stdout); } - fwprintf(stdout, L"Error: "); - vfwprintf(stdout, blah, va); + std::fwprintf(stdout, L"Error: "); + std::vfwprintf(stdout, blah, va); va_end(va); // Return to normal color. if (colorize) { - fputws(L"\x1B[0m", stdout); + std::fputws(L"\x1B[0m", stdout); } - fwprintf(stdout, L"\n"); + std::fwprintf(stdout, L"\n"); } /// Joins a wcstring_list_t via commas. @@ -459,8 +459,8 @@ static void test_format() { wchar_t wbuf1[128], wbuf2[128]; format_long_safe(wbuf1, j); - swprintf(wbuf2, 128, L"%d", j); - do_test(!wcscmp(wbuf1, wbuf2)); + std::swprintf(wbuf2, 128, L"%d", j); + do_test(!std::wcscmp(wbuf1, wbuf2)); } long q = LONG_MIN; @@ -599,12 +599,12 @@ static void test_tokenizer() { while (t.next(&token)) { if (i >= sizeof types / sizeof *types) { err(L"Too many tokens returned from tokenizer"); - fwprintf(stdout, L"Got excess token type %ld\n", (long)token.type); + std::fwprintf(stdout, L"Got excess token type %ld\n", (long)token.type); break; } if (types[i] != token.type) { err(L"Tokenization error:"); - fwprintf(stdout, + std::fwprintf(stdout, L"Token number %zu of string \n'%ls'\n, expected type %ld, got token type " L"%ld\n", i + 1, str, (long)types[i], (long)token.type); @@ -1132,29 +1132,29 @@ static void test_parse_util_cmdsubst_extent() { const wchar_t *begin = NULL, *end = NULL; parse_util_cmdsubst_extent(a, 0, &begin, &end); - if (begin != a || end != begin + wcslen(begin)) { + if (begin != a || end != begin + std::wcslen(begin)) { err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); } parse_util_cmdsubst_extent(a, 1, &begin, &end); - if (begin != a || end != begin + wcslen(begin)) { + if (begin != a || end != begin + std::wcslen(begin)) { err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); } parse_util_cmdsubst_extent(a, 2, &begin, &end); - if (begin != a || end != begin + wcslen(begin)) { + if (begin != a || end != begin + std::wcslen(begin)) { err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); } parse_util_cmdsubst_extent(a, 3, &begin, &end); - if (begin != a || end != begin + wcslen(begin)) { + if (begin != a || end != begin + std::wcslen(begin)) { err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); } parse_util_cmdsubst_extent(a, 8, &begin, &end); - if (begin != a + wcslen(L"echo (")) { + if (begin != a + std::wcslen(L"echo (")) { err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); } parse_util_cmdsubst_extent(a, 17, &begin, &end); - if (begin != a + wcslen(L"echo (echo (")) { + if (begin != a + std::wcslen(L"echo (echo (")) { err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); } } @@ -1864,43 +1864,43 @@ static void test_abbreviations() { if (!expanded) err(L"Command not expanded on line %ld", (long)__LINE__); expanded = - reader_expand_abbreviation_in_command(L"gc somebranch", wcslen(L"gc"), vars, &result); + reader_expand_abbreviation_in_command(L"gc somebranch", std::wcslen(L"gc"), vars, &result); if (!expanded) err(L"gc not expanded"); if (result != L"git checkout somebranch") err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str()); // Space separation. expanded = - reader_expand_abbreviation_in_command(L"gx somebranch", wcslen(L"gc"), vars, &result); + reader_expand_abbreviation_in_command(L"gx somebranch", std::wcslen(L"gc"), vars, &result); if (!expanded) err(L"gx not expanded"); if (result != L"git checkout somebranch") err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str()); expanded = reader_expand_abbreviation_in_command(L"echo hi ; gc somebranch", - wcslen(L"echo hi ; g"), vars, &result); + std::wcslen(L"echo hi ; g"), vars, &result); if (!expanded) err(L"gc not expanded on line %ld", (long)__LINE__); if (result != L"echo hi ; git checkout somebranch") err(L"gc incorrectly expanded on line %ld", (long)__LINE__); expanded = reader_expand_abbreviation_in_command( - L"echo (echo (echo (echo (gc ", wcslen(L"echo (echo (echo (echo (gc"), vars, &result); + L"echo (echo (echo (echo (gc ", std::wcslen(L"echo (echo (echo (echo (gc"), vars, &result); if (!expanded) err(L"gc not expanded on line %ld", (long)__LINE__); if (result != L"echo (echo (echo (echo (git checkout ") err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str()); // If commands should be expanded. - expanded = reader_expand_abbreviation_in_command(L"if gc", wcslen(L"if gc"), vars, &result); + expanded = reader_expand_abbreviation_in_command(L"if gc", std::wcslen(L"if gc"), vars, &result); if (!expanded) err(L"gc not expanded on line %ld", (long)__LINE__); if (result != L"if git checkout") err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str()); // Others should not be. - expanded = reader_expand_abbreviation_in_command(L"of gc", wcslen(L"of gc"), vars, &result); + expanded = reader_expand_abbreviation_in_command(L"of gc", std::wcslen(L"of gc"), vars, &result); if (expanded) err(L"gc incorrectly expanded on line %ld", (long)__LINE__); // Others should not be. expanded = - reader_expand_abbreviation_in_command(L"command gc", wcslen(L"command gc"), vars, &result); + reader_expand_abbreviation_in_command(L"command gc", std::wcslen(L"command gc"), vars, &result); if (expanded) err(L"gc incorrectly expanded on line %ld", (long)__LINE__); vars.pop(); @@ -2042,10 +2042,10 @@ struct pager_layout_testcase_t { wcstring text = sd.line(0).to_string(); if (text != expected) { - fwprintf(stderr, L"width %zu got %zu<%ls>, expected %zu<%ls>\n", this->width, + std::fwprintf(stderr, L"width %zu got %zu<%ls>, expected %zu<%ls>\n", this->width, text.length(), text.c_str(), expected.length(), expected.c_str()); for (size_t i = 0; i < std::max(text.length(), expected.length()); i++) { - fwprintf(stderr, L"i %zu got <%lx> expected <%lx>\n", i, + std::fwprintf(stderr, L"i %zu got <%lx> expected <%lx>\n", i, i >= text.length() ? 0xffff : text[i], i >= expected.length() ? 0xffff : expected[i]); } @@ -2137,7 +2137,7 @@ static void test_1_word_motion(word_motion_t motion, move_word_style_t style, size_t char_idx = (motion == word_motion_left ? idx - 1 : idx); wchar_t wc = command.at(char_idx); bool will_stop = !sm.consume_char(wc); - // fwprintf(stdout, L"idx %lu, looking at %lu (%c): %d\n", idx, char_idx, (char)wc, + // std::fwprintf(stdout, L"idx %lu, looking at %lu (%c): %d\n", idx, char_idx, (char)wc, // will_stop); bool expected_stop = (stops.count(idx) > 0); if (will_stop != expected_stop) { @@ -2384,7 +2384,7 @@ static void test_wcstod() { auto tod_test = [](const wchar_t *a, const char *b) { char *narrow_end = nullptr; wchar_t *wide_end = nullptr; - double val1 = wcstod(a, &wide_end); + double val1 = std::wcstod(a, &wide_end); double val2 = strtod(b, &narrow_end); do_test((std::isnan(val1) && std::isnan(val2)) || fabs(val1 - val2) <= __DBL_EPSILON__); do_test(wide_end - a == narrow_end - b); @@ -2699,7 +2699,7 @@ static void test_1_completion(wcstring line, const wcstring &completion, complet wcstring result = completion_apply_to_command_line(completion, flags, line, &cursor_pos, append_only); if (result != expected) { - fwprintf(stderr, L"line %ld: %ls + %ls -> [%ls], expected [%ls]\n", source_line, + std::fwprintf(stderr, L"line %ld: %ls + %ls -> [%ls], expected [%ls]\n", source_line, line.c_str(), completion.c_str(), result.c_str(), expected.c_str()); } do_test(result == expected); @@ -2743,12 +2743,12 @@ static void perform_one_autosuggestion_cd_test(const wcstring &command, const wc bool expects_error = (expected == L""); if (comps.empty() && !expects_error) { - fwprintf(stderr, L"line %ld: autosuggest_suggest_special() failed for command %ls\n", line, + std::fwprintf(stderr, L"line %ld: autosuggest_suggest_special() failed for command %ls\n", line, command.c_str()); do_test_from(!comps.empty(), line); return; } else if (!comps.empty() && expects_error) { - fwprintf(stderr, + std::fwprintf(stderr, L"line %ld: autosuggest_suggest_special() was expected to fail but did not, " L"for command %ls\n", line, command.c_str()); @@ -2760,12 +2760,12 @@ static void perform_one_autosuggestion_cd_test(const wcstring &command, const wc const completion_t &suggestion = comps.at(0); if (suggestion.completion != expected) { - fwprintf( + std::fwprintf( stderr, L"line %ld: complete() for cd returned the wrong expected string for command %ls\n", line, command.c_str()); - fwprintf(stderr, L" actual: %ls\n", suggestion.completion.c_str()); - fwprintf(stderr, L"expected: %ls\n", expected.c_str()); + std::fwprintf(stderr, L" actual: %ls\n", suggestion.completion.c_str()); + std::fwprintf(stderr, L"expected: %ls\n", expected.c_str()); do_test_from(suggestion.completion == expected, line); } } @@ -2779,12 +2779,12 @@ static void perform_one_completion_cd_test(const wcstring &command, const wcstri bool expects_error = (expected == L""); if (comps.empty() && !expects_error) { - fwprintf(stderr, L"line %ld: autosuggest_suggest_special() failed for command %ls\n", line, + std::fwprintf(stderr, L"line %ld: autosuggest_suggest_special() failed for command %ls\n", line, command.c_str()); do_test_from(!comps.empty(), line); return; } else if (!comps.empty() && expects_error) { - fwprintf(stderr, + std::fwprintf(stderr, L"line %ld: autosuggest_suggest_special() was expected to fail but did not, " L"for command %ls\n", line, command.c_str()); @@ -2796,12 +2796,12 @@ static void perform_one_completion_cd_test(const wcstring &command, const wcstri const completion_t &suggestion = comps.at(0); if (suggestion.completion != expected) { - fwprintf(stderr, + std::fwprintf(stderr, L"line %ld: complete() for cd tab completion returned the wrong expected " L"string for command %ls\n", line, command.c_str()); - fwprintf(stderr, L" actual: %ls\n", suggestion.completion.c_str()); - fwprintf(stderr, L"expected: %ls\n", expected.c_str()); + std::fwprintf(stderr, L" actual: %ls\n", suggestion.completion.c_str()); + std::fwprintf(stderr, L"expected: %ls\n", expected.c_str()); do_test_from(suggestion.completion == expected, line); } } @@ -2918,9 +2918,9 @@ static void perform_one_autosuggestion_should_ignore_test(const wcstring &comman do_test(comps.empty()); if (!comps.empty()) { const wcstring &suggestion = comps.front().completion; - fwprintf(stderr, L"line %ld: complete() expected to return nothing for %ls\n", line, + std::fwprintf(stderr, L"line %ld: complete() expected to return nothing for %ls\n", line, command.c_str()); - fwprintf(stderr, L" instead got: %ls\n", suggestion.c_str()); + std::fwprintf(stderr, L" instead got: %ls\n", suggestion.c_str()); } } @@ -3862,7 +3862,7 @@ void history_tests_t::test_history_speed(void) if (stop >= end) break; } - fwprintf(stdout, L"%lu items - %.2f msec per item\n", (unsigned long)count, + std::fwprintf(stdout, L"%lu items - %.2f msec per item\n", (unsigned long)count, (stop - start) * 1E6 / count); hist->clear(); } @@ -3945,7 +3945,7 @@ static void test_new_parser_fuzzing() { bool log_it = true; unsigned long max_len = 5; for (unsigned long len = 0; len < max_len; len++) { - if (log_it) fwprintf(stderr, L"%lu / %lu...", len, max_len); + if (log_it) std::fwprintf(stderr, L"%lu / %lu...", len, max_len); // We wish to look at all permutations of 4 elements of 'fuzzes' (with replacement). // Construct an int and keep incrementing it. @@ -3954,7 +3954,7 @@ static void test_new_parser_fuzzing() { &src)) { parse_tree_from_string(src, parse_flag_continue_after_error, &node_tree, &errors); } - if (log_it) fwprintf(stderr, L"done (%lu)\n", permutation); + if (log_it) std::fwprintf(stderr, L"done (%lu)\n", permutation); } double end = timef(); if (log_it) say(L"All fuzzed in %f seconds!", end - start); @@ -4136,9 +4136,9 @@ static void test_new_parser_errors() { static wcstring_list_t separate_by_format_specifiers(const wchar_t *format) { wcstring_list_t result; const wchar_t *cursor = format; - const wchar_t *end = format + wcslen(format); + const wchar_t *end = format + std::wcslen(format); while (cursor < end) { - const wchar_t *next_specifier = wcschr(cursor, '%'); + const wchar_t *next_specifier = std::wcschr(cursor, '%'); if (next_specifier == NULL) { next_specifier = end; } @@ -4157,7 +4157,7 @@ static wcstring_list_t separate_by_format_specifiers(const wchar_t *format) { cursor++; // Flag - if (wcschr(L"#0- +'", *cursor)) cursor++; + if (std::wcschr(L"#0- +'", *cursor)) cursor++; // Minimum field width while (iswdigit(*cursor)) cursor++; // Precision @@ -4166,9 +4166,9 @@ static wcstring_list_t separate_by_format_specifiers(const wchar_t *format) { while (iswdigit(*cursor)) cursor++; } // Length modifier - if (!wcsncmp(cursor, L"ll", 2) || !wcsncmp(cursor, L"hh", 2)) { + if (!std::wcsncmp(cursor, L"ll", 2) || !std::wcsncmp(cursor, L"hh", 2)) { cursor += 2; - } else if (wcschr(L"hljtzqL", *cursor)) { + } else if (std::wcschr(L"hljtzqL", *cursor)) { cursor++; } // The format specifier itself. We allow any character except NUL. @@ -5177,7 +5177,7 @@ int main(int argc, char **argv) { exit(-1); } if (!strcmp(wd, "/")) { - fwprintf(stderr, + std::fwprintf(stderr, L"Unable to find 'tests' directory, which should contain file test.fish\n"); exit(EXIT_FAILURE); } diff --git a/src/function.cpp b/src/function.cpp index bffa0d8cf..1f43efd54 100644 --- a/src/function.cpp +++ b/src/function.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -122,8 +122,8 @@ static void autoload_names(std::unordered_set &names, int get_hidden) const wchar_t *suffix; if (!get_hidden && fn[0] == L'_') continue; - suffix = wcsrchr(fn, L'.'); - if (suffix && (wcscmp(suffix, L".fish") == 0)) { + suffix = std::wcsrchr(fn, L'.'); + if (suffix && (std::wcscmp(suffix, L".fish") == 0)) { wcstring name(fn, suffix - fn); names.insert(name); } diff --git a/src/future_feature_flags.cpp b/src/future_feature_flags.cpp index 2cafa4533..4feca703b 100644 --- a/src/future_feature_flags.cpp +++ b/src/future_feature_flags.cpp @@ -1,6 +1,6 @@ #include "config.h" // IWYU pragma: keep -#include +#include #include "future_feature_flags.h" /// The set of features applying to this instance. @@ -18,7 +18,7 @@ const features_t::metadata_t features_t::metadata[features_t::flag_count] = { const struct features_t::metadata_t *features_t::metadata_for(const wchar_t *name) { assert(name && "null flag name"); for (const auto &md : metadata) { - if (!wcscmp(name, md.name)) return &md; + if (!std::wcscmp(name, md.name)) return &md; } return nullptr; } @@ -38,7 +38,7 @@ void features_t::set_from_string(const wcstring &str) { // A "no-" prefix inverts the sense. if (string_prefixes_string(L"no-", name)) { value = false; - name += 3; // wcslen(L"no-") + name += 3; // std::wcslen(L"no-") } // Look for a feature with this name. If we don't find it, assume it's a group name and set // all features whose group contain it. Do nothing even if the string is unrecognized; this @@ -49,7 +49,7 @@ void features_t::set_from_string(const wcstring &str) { this->set(md->flag, value); } else { for (const metadata_t &md : metadata) { - if (wcsstr(md.groups, name) || !wcscmp(name, L"all")) { + if (std::wcsstr(md.groups, name) || !std::wcscmp(name, L"all")) { this->set(md.flag, value); } } diff --git a/src/highlight.cpp b/src/highlight.cpp index 1f18e49b6..d45426024 100644 --- a/src/highlight.cpp +++ b/src/highlight.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -532,7 +532,7 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base // Hacky support for %self which must be an unquoted literal argument. if (buffstr == PROCESS_EXPAND_SELF_STR) { - std::fill_n(colors, wcslen(PROCESS_EXPAND_SELF_STR), highlight_role_t::operat); + std::fill_n(colors, std::wcslen(PROCESS_EXPAND_SELF_STR), highlight_role_t::operat); return; } @@ -554,7 +554,7 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base if (escaped_char == L'\0') { fill_end = in_pos; fill_color = highlight_role_t::error; - } else if (wcschr(L"~%", escaped_char)) { + } else if (std::wcschr(L"~%", escaped_char)) { if (in_pos == 1) { fill_end = in_pos + 1; } @@ -562,12 +562,12 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base if (bracket_count) { fill_end = in_pos + 1; } - } else if (wcschr(L"abefnrtv*?$(){}[]'\"<>^ \\#;|&", escaped_char)) { + } else if (std::wcschr(L"abefnrtv*?$(){}[]'\"<>^ \\#;|&", escaped_char)) { fill_end = in_pos + 1; - } else if (wcschr(L"c", escaped_char)) { + } else if (std::wcschr(L"c", escaped_char)) { // Like \ci. So highlight three characters. fill_end = in_pos + 1; - } else if (wcschr(L"uUxX01234567", escaped_char)) { + } else if (std::wcschr(L"uUxX01234567", escaped_char)) { long long res = 0; int chars = 2; int base = 16; @@ -720,7 +720,7 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base // Backslash if (in_pos + 1 < buff_len) { const wchar_t escaped_char = buffstr.at(in_pos + 1); - if (wcschr(L"\\\"\n$", escaped_char)) { + if (std::wcschr(L"\\\"\n$", escaped_char)) { colors[in_pos] = highlight_role_t::escape; // backslash colors[in_pos + 1] = highlight_role_t::escape; // escaped char in_pos += 1; // skip over backslash @@ -1366,9 +1366,9 @@ static void highlight_universal_internal(const wcstring &buffstr, // Highlight matching parenthesis. const wchar_t c = buffstr.at(pos); - if (wcschr(L"()[]{}", c)) { - int step = wcschr(L"({[", c) ? 1 : -1; - wchar_t dec_char = *(wcschr(L"()[]{}", c) + step); + if (std::wcschr(L"()[]{}", c)) { + int step = std::wcschr(L"({[", c) ? 1 : -1; + wchar_t dec_char = *(std::wcschr(L"()[]{}", c) + step); wchar_t inc_char = c; int level = 0; bool match_found = false; diff --git a/src/history.cpp b/src/history.cpp index 36b3d081f..1c7abddfb 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -422,7 +422,7 @@ static history_item_t decode_item_fish_1_x(const char *begin, size_t length) { c = (unsigned char)*pos; res = 1; } else { - res = mbrtowc(&c, pos, end - pos, &state); + res = std::mbrtowc(&c, pos, end - pos, &state); } if (res == (size_t)-1) { diff --git a/src/input.cpp b/src/input.cpp index 4d82bc413..dffa07f15 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -2,7 +2,7 @@ #include "config.h" #include -#include +#include #include #if HAVE_TERM_H #include @@ -746,7 +746,7 @@ bool input_terminfo_get_sequence(const wchar_t *name, wcstring *out_seq) { for (size_t i = 0; i < terminfo_mappings.size(); i++) { const terminfo_mapping_t &m = terminfo_mappings.at(i); - if (!wcscmp(name, m.name)) { + if (!std::wcscmp(name, m.name)) { res = m.seq; err = EILSEQ; break; diff --git a/src/input_common.cpp b/src/input_common.cpp index 3ebbe92d7..655f5dfc2 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include @@ -165,7 +165,7 @@ void update_wait_on_escape_ms(const environment_t &vars) { long tmp = fish_wcstol(escape_time_ms->as_string().c_str()); if (errno || tmp < 10 || tmp >= 5000) { - fwprintf(stderr, + std::fwprintf(stderr, L"ignoring fish_escape_delay_ms: value '%ls' " L"is not an integer or is < 10 or >= 5000 ms\n", escape_time_ms->as_string().c_str()); @@ -201,7 +201,7 @@ wchar_t input_common_readch(int timed) { } char bb = b; - size_t sz = mbrtowc(&res, &bb, 1, &state); + size_t sz = std::mbrtowc(&res, &bb, 1, &state); switch (sz) { case (size_t)(-1): { diff --git a/src/intern.cpp b/src/intern.cpp index a13e1b9ff..1073a6b07 100644 --- a/src/intern.cpp +++ b/src/intern.cpp @@ -2,7 +2,7 @@ #include "config.h" // IWYU pragma: keep #include -#include +#include #include #include @@ -12,7 +12,7 @@ #include "fallback.h" // IWYU pragma: keep #include "intern.h" -bool string_less_than_string(const wchar_t *a, const wchar_t *b) { return wcscmp(a, b) < 0; } +bool string_less_than_string(const wchar_t *a, const wchar_t *b) { return std::wcscmp(a, b) < 0; } /// The table of intern'd strings. owning_lock> string_table; @@ -25,7 +25,7 @@ static const wchar_t *intern_with_dup(const wchar_t *in, bool dup) { const wchar_t *result; auto iter = std::lower_bound(table->begin(), table->end(), in, string_less_than_string); - if (iter != table->end() && wcscmp(*iter, in) == 0) { + if (iter != table->end() && std::wcscmp(*iter, in) == 0) { result = *iter; } else { result = dup ? wcsdup(in) : in; diff --git a/src/io.cpp b/src/io.cpp index 5dcff30de..5f2ed4166 100644 --- a/src/io.cpp +++ b/src/io.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include "common.h" #include "exec.h" @@ -18,17 +18,17 @@ io_data_t::~io_data_t() = default; -void io_close_t::print() const { fwprintf(stderr, L"close %d\n", fd); } +void io_close_t::print() const { std::fwprintf(stderr, L"close %d\n", fd); } -void io_fd_t::print() const { fwprintf(stderr, L"FD map %d -> %d\n", old_fd, fd); } +void io_fd_t::print() const { std::fwprintf(stderr, L"FD map %d -> %d\n", old_fd, fd); } -void io_file_t::print() const { fwprintf(stderr, L"file (%s)\n", filename_cstr); } +void io_file_t::print() const { std::fwprintf(stderr, L"file (%s)\n", filename_cstr); } void io_pipe_t::print() const { - fwprintf(stderr, L"pipe {%d} (input: %s)\n", pipe_fd(), is_input_ ? "yes" : "no"); + std::fwprintf(stderr, L"pipe {%d} (input: %s)\n", pipe_fd(), is_input_ ? "yes" : "no"); } -void io_bufferfill_t::print() const { fwprintf(stderr, L"bufferfill {%d}\n", write_fd_.fd()); } +void io_bufferfill_t::print() const { std::fwprintf(stderr, L"bufferfill {%d}\n", write_fd_.fd()); } void io_buffer_t::append_from_stream(const output_stream_t &stream) { if (stream.empty()) return; @@ -223,21 +223,21 @@ void io_print(const io_chain_t &chain) { if (chain.empty()) { - fwprintf(stderr, L"Empty chain %p\n", &chain); + std::fwprintf(stderr, L"Empty chain %p\n", &chain); return; } - fwprintf(stderr, L"Chain %p (%ld items):\n", &chain, (long)chain.size()); + std::fwprintf(stderr, L"Chain %p (%ld items):\n", &chain, (long)chain.size()); for (size_t i=0; i < chain.size(); i++) { const shared_ptr &io = chain.at(i); if (io.get() == NULL) { - fwprintf(stderr, L"\t(null)\n"); + std::fwprintf(stderr, L"\t(null)\n"); } else { - fwprintf(stderr, L"\t%lu: fd:%d, ", (unsigned long)i, io->fd); + std::fwprintf(stderr, L"\t%lu: fd:%d, ", (unsigned long)i, io->fd); io->print(); } } diff --git a/src/io.h b/src/io.h index 6f5e12447..4017af474 100644 --- a/src/io.h +++ b/src/io.h @@ -383,7 +383,7 @@ class output_stream_t { const separated_buffer_t &buffer() const { return buffer_; } - void append(const wchar_t *s) { append(s, wcslen(s)); } + void append(const wchar_t *s) { append(s, std::wcslen(s)); } void append(wchar_t s) { append(&s, 1); } diff --git a/src/iothread.cpp b/src/iothread.cpp index 7aec8803e..a9d799b43 100644 --- a/src/iothread.cpp +++ b/src/iothread.cpp @@ -246,7 +246,7 @@ void iothread_drain_all() { } #if TIME_DRAIN double after = timef(); - fwprintf(stdout, L"(Waited %.02f msec for %d thread(s) to drain)\n", 1000 * (after - now), + std::fwprintf(stdout, L"(Waited %.02f msec for %d thread(s) to drain)\n", 1000 * (after - now), thread_count); #endif } diff --git a/src/lru.h b/src/lru.h index f91c63f74..0cf7b08c2 100644 --- a/src/lru.h +++ b/src/lru.h @@ -2,7 +2,7 @@ #ifndef FISH_LRU_H #define FISH_LRU_H -#include +#include #include diff --git a/src/output.cpp b/src/output.cpp index 581964101..5cca74258 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -17,7 +17,7 @@ #include #endif #include -#include +#include #include #include @@ -379,7 +379,7 @@ int outputter_t::writech(wint_t ch) { len = 1; } else { mbstate_t state = {}; - len = wcrtomb(buff, ch, &state); + len = std::wcrtomb(buff, ch, &state); if (len == (size_t)-1) { return 1; } @@ -389,7 +389,7 @@ int outputter_t::writech(wint_t ch) { } /// Write a wide character string to stdout. This should not be used to output things like warning -/// messages; just use debug() or fwprintf() for that. It should only be used to output user +/// messages; just use debug() or std::fwprintf() for that. It should only be used to output user /// supplied strings that might contain literal bytes; e.g., "\342\224\214" from issue #1894. This /// is needed because those strings may contain chars specially encoded using ENCODE_DIRECT_BASE. void outputter_t::writestr(const wchar_t *str) { @@ -508,7 +508,7 @@ rgb_color_t parse_color(const env_var_t &var, bool is_background) { #if 0 wcstring desc = result.description(); - fwprintf(stdout, L"Parsed %ls from %ls (%s)\n", desc.c_str(), val.c_str(), + std::fwprintf(stdout, L"Parsed %ls from %ls (%s)\n", desc.c_str(), val.c_str(), is_background ? "background" : "foreground"); #endif diff --git a/src/pager.cpp b/src/pager.cpp index 5066240d2..03273037d 100644 --- a/src/pager.cpp +++ b/src/pager.cpp @@ -2,7 +2,7 @@ // IWYU pragma: no_include #include -#include +#include #include #include @@ -852,7 +852,7 @@ void pager_t::set_search_field_shown(bool flag) { this->search_field_shown = fla bool pager_t::is_search_field_shown() const { return this->search_field_shown; } size_t pager_t::cursor_position() const { - size_t result = wcslen(SEARCH_FIELD_PROMPT) + this->search_field_line.position; + size_t result = std::wcslen(SEARCH_FIELD_PROMPT) + this->search_field_line.position; // Clamp it to the right edge. if (available_term_width > 0 && result + 1 > available_term_width) { result = available_term_width - 1; diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 6e8d2af36..3d83c9035 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -628,7 +628,7 @@ parse_execution_result_t parse_execution_context_t::report_errors( // Print it. if (!should_suppress_stderr_for_tests()) { - fwprintf(stderr, L"%ls", backtrace_and_desc.c_str()); + std::fwprintf(stderr, L"%ls", backtrace_and_desc.c_str()); } } return parse_execution_errored; @@ -673,7 +673,7 @@ parse_execution_result_t parse_execution_context_t::handle_command_not_found( // status to 127, which is the standard number used by other shells like bash and zsh. const wchar_t *const cmd = cmd_str.c_str(); - const wchar_t *const equals_ptr = wcschr(cmd, L'='); + const wchar_t *const equals_ptr = std::wcschr(cmd, L'='); if (equals_ptr != NULL) { // Try to figure out if this is a pure variable assignment (foo=bar), or if this appears to // be running a command (foo=bar ruby...). diff --git a/src/parse_tree.cpp b/src/parse_tree.cpp index 245573d12..52be15884 100644 --- a/src/parse_tree.cpp +++ b/src/parse_tree.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -407,17 +407,17 @@ class parse_ll_t { bool logit = false; if (logit) { int count = 0; - fwprintf(stderr, L"Applying production:\n"); + std::fwprintf(stderr, L"Applying production:\n"); for (int i = 0;; i++) { production_element_t elem = production[i]; if (!production_element_is_valid(elem)) break; // all done, bail out parse_token_type_t type = production_element_type(elem); parse_keyword_t keyword = production_element_keyword(elem); - fwprintf(stderr, L"\t%ls <%ls>\n", token_type_description(type), + std::fwprintf(stderr, L"\t%ls <%ls>\n", token_type_description(type), keyword_description(keyword)); count++; } - if (!count) fwprintf(stderr, L"\t\n"); + if (!count) std::fwprintf(stderr, L"\t\n"); } // Get the parent index. But we can't get the parent parse node yet, since it may be made @@ -524,9 +524,9 @@ void parse_ll_t::dump_stack(void) const { } } - fwprintf(stderr, L"Stack dump (%zu elements):\n", symbol_stack.size()); + std::fwprintf(stderr, L"Stack dump (%zu elements):\n", symbol_stack.size()); for (size_t idx = 0; idx < stack_lines.size(); idx++) { - fwprintf(stderr, L" %ls\n", stack_lines.at(idx).c_str()); + std::fwprintf(stderr, L" %ls\n", stack_lines.at(idx).c_str()); } } #endif diff --git a/src/parse_util.cpp b/src/parse_util.cpp index aa909b1ce..bcca52cb4 100644 --- a/src/parse_util.cpp +++ b/src/parse_util.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include @@ -117,7 +117,7 @@ static int parse_util_locate_brackets_of_type(const wchar_t *in, wchar_t **begin for (pos = const_cast(in); *pos; pos++) { if (prev != '\\') { - if (wcschr(L"\'\"", *pos)) { + if (std::wcschr(L"\'\"", *pos)) { wchar_t *q_end = quote_end(pos); if (q_end && *q_end) { pos = q_end; @@ -165,7 +165,7 @@ static int parse_util_locate_brackets_of_type(const wchar_t *in, wchar_t **begin } if (end) { - *end = paran_count ? (wchar_t *)in + wcslen(in) : paran_end; + *end = paran_count ? (wchar_t *)in + std::wcslen(in) : paran_end; } return 1; @@ -239,7 +239,7 @@ void parse_util_cmdsubst_extent(const wchar_t *buff, size_t cursor_pos, const wc CHECK(buff, ); - const size_t bufflen = wcslen(buff); + const size_t bufflen = std::wcslen(buff); assert(cursor_pos <= bufflen); // ap and bp are the beginning and end of the tightest command substitition found so far. @@ -360,7 +360,7 @@ void parse_util_token_extent(const wchar_t *buff, size_t cursor_pos, const wchar // pos is equivalent to cursor_pos within the range of the command substitution {begin, end}. size_t offset_within_cmdsubst = cursor_pos - (cmdsubst_begin - buff); - size_t bufflen = wcslen(buff); + size_t bufflen = std::wcslen(buff); a = cmdsubst_begin + offset_within_cmdsubst; b = a; @@ -462,7 +462,7 @@ static wchar_t get_quote(const wcstring &cmd_str, size_t len) { } else { if (cmd[i] == L'\'' || cmd[i] == L'\"') { const wchar_t *end = quote_end(&cmd[i]); - // fwprintf( stderr, L"Jump %d\n", end-cmd ); + // std::fwprintf( stderr, L"Jump %d\n", end-cmd ); if ((end == 0) || (!*end) || (end > cmd + len)) { res = cmd[i]; break; @@ -500,7 +500,7 @@ void parse_util_get_parameter_info(const wcstring &cmd, const size_t pos, wchar_ bool finished = cmdlen != 0; if (finished) { finished = (quote == NULL); - if (finished && wcschr(L" \t\n\r", cmd_tmp[cmdlen - 1])) { + if (finished && std::wcschr(L" \t\n\r", cmd_tmp[cmdlen - 1])) { finished = cmdlen > 1 && cmd_tmp[cmdlen - 2] == L'\\'; } } @@ -509,7 +509,7 @@ void parse_util_get_parameter_info(const wcstring &cmd, const size_t pos, wchar_ if (offset != 0) { if (finished) { - while ((cmd_tmp[prev_pos] != 0) && (wcschr(L";|", cmd_tmp[prev_pos]) != 0)) prev_pos++; + while ((cmd_tmp[prev_pos] != 0) && (std::wcschr(L";|", cmd_tmp[prev_pos]) != 0)) prev_pos++; *offset = prev_pos; } else { *offset = pos; @@ -729,7 +729,7 @@ std::vector parse_util_compute_indents(const wcstring &src) { // indentation level if a new line starts with whitespace. size_t prev_char_idx = i; while (prev_char_idx--) { - if (!wcschr(L" \n\t\r", src.at(prev_char_idx))) break; + if (!std::wcschr(L" \n\t\r", src.at(prev_char_idx))) break; indents.at(prev_char_idx) = last_indent; } } @@ -739,7 +739,7 @@ std::vector parse_util_compute_indents(const wcstring &src) { // indented even if it is empty. size_t suffix_idx = src_size; while (suffix_idx--) { - if (!wcschr(L" \n\t\r", src.at(suffix_idx))) break; + if (!std::wcschr(L" \n\t\r", src.at(suffix_idx))) break; indents.at(suffix_idx) = last_trailing_indent; } @@ -771,7 +771,7 @@ static int parser_is_pipe_forbidden(const wcstring &word) { } bool parse_util_argument_is_help(const wchar_t *s) { - return wcscmp(L"-h", s) == 0 || wcscmp(L"--help", s) == 0; + return std::wcscmp(L"-h", s) == 0 || std::wcscmp(L"--help", s) == 0; } /// Check if the first argument under the given node is --help. diff --git a/src/parser.cpp b/src/parser.cpp index 72a263258..a8d30e0bf 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2,7 +2,7 @@ #include "config.h" // IWYU pragma: keep #include -#include +#include #include #include @@ -275,19 +275,19 @@ static void print_profile(const std::vector> &it continue; } - if (fwprintf(out, L"%d\t%d\t", my_time, me->parse + me->exec) < 0) { + if (std::fwprintf(out, L"%d\t%d\t", my_time, me->parse + me->exec) < 0) { wperror(L"fwprintf"); return; } for (i = 0; i < me->level; i++) { - if (fwprintf(out, L"-") < 0) { + if (std::fwprintf(out, L"-") < 0) { wperror(L"fwprintf"); return; } } - if (fwprintf(out, L"> %ls\n", me->cmd.c_str()) < 0) { + if (std::fwprintf(out, L"> %ls\n", me->cmd.c_str()) < 0) { wperror(L"fwprintf"); return; } @@ -301,7 +301,7 @@ void parser_t::emit_profiling(const char *path) const { if (!f) { debug(1, _(L"Could not write profiling information to file '%s'"), path); } else { - if (fwprintf(f, _(L"Time\tSum\tCommand\n"), profile_items.size()) < 0) { + if (std::fwprintf(f, _(L"Time\tSum\tCommand\n"), profile_items.size()) < 0) { wperror(L"fwprintf"); } else { print_profile(profile_items, f); @@ -639,7 +639,7 @@ int parser_t::eval(wcstring cmd, const io_chain_t &io, enum block_type_t block_t this->get_backtrace(cmd, error_list, backtrace_and_desc); // Print it. - fwprintf(stderr, L"%ls\n", backtrace_and_desc.c_str()); + std::fwprintf(stderr, L"%ls\n", backtrace_and_desc.c_str()); return 1; } this->eval(ps, io, block_type); diff --git a/src/path.cpp b/src/path.cpp index 4117cec41..2523e4ef9 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/postfork.cpp b/src/postfork.cpp index e24b3fd62..ca3607628 100644 --- a/src/postfork.cpp +++ b/src/postfork.cpp @@ -11,7 +11,7 @@ #if FISH_USE_POSIX_SPAWN #include #endif -#include +#include #include "common.h" #include "exec.h" diff --git a/src/proc.cpp b/src/proc.cpp index c5005cbcb..e2ededc77 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #if HAVE_TERM_H @@ -441,7 +441,7 @@ static wcstring truncate_command(const wcstring &cmd) { } // Truncation required. - const size_t ellipsis_length = wcslen(ellipsis_str); // no need for wcwidth + const size_t ellipsis_length = std::wcslen(ellipsis_str); // no need for wcwidth size_t trunc_length = max_len - ellipsis_length; // Eat trailing whitespace. while (trunc_length > 0 && iswspace(cmd.at(trunc_length - 1))) { @@ -547,7 +547,7 @@ static bool process_clean_after_marking(bool allow_interactive) { // we don't need to. const wcstring job_number_desc = only_one_job ? wcstring() : format_string(_(L"Job %d, "), j->job_id); - fwprintf(stdout, _(L"%ls: %ls\'%ls\' terminated by signal %ls (%ls)"), + std::fwprintf(stdout, _(L"%ls: %ls\'%ls\' terminated by signal %ls (%ls)"), program_name, job_number_desc.c_str(), truncate_command(j->command()).c_str(), sig2wcs(s.signal_code()), signal_get_desc(s.signal_code())); @@ -556,13 +556,13 @@ static bool process_clean_after_marking(bool allow_interactive) { only_one_job ? wcstring() : format_string(L"from job %d, ", j->job_id); const wchar_t *fmt = _(L"%ls: Process %d, \'%ls\' %ls\'%ls\' terminated by signal %ls (%ls)"); - fwprintf(stdout, fmt, program_name, p->pid, p->argv0(), job_number_desc.c_str(), + std::fwprintf(stdout, fmt, program_name, p->pid, p->argv0(), job_number_desc.c_str(), truncate_command(j->command()).c_str(), sig2wcs(s.signal_code()), signal_get_desc(s.signal_code())); } if (clr_eol) outputter_t::stdoutput().term_puts(clr_eol, 1); - fwprintf(stdout, L"\n"); + std::fwprintf(stdout, L"\n"); } found = false; // clear status so it is not reported more than once @@ -641,7 +641,7 @@ unsigned long proc_get_jiffies(process_t *p) { wchan, nswap, cnswap; char comm[1024]; - swprintf(fn, FN_SIZE, L"/proc/%d/stat", p->pid); + std::swprintf(fn, FN_SIZE, L"/proc/%d/stat", p->pid); FILE *f = wfopen(fn, "r"); if (!f) return 0; diff --git a/src/reader.cpp b/src/reader.cpp index b29fec63d..505dae066 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include @@ -564,7 +564,7 @@ wcstring combine_command_and_autosuggestion(const wcstring &cmdline, parse_util_token_extent(cmd, cmdline.size() - 1, &begin, NULL, NULL, NULL); bool last_token_contains_uppercase = false; if (begin) { - const wchar_t *end = begin + wcslen(begin); + const wchar_t *end = begin + std::wcslen(begin); last_token_contains_uppercase = (std::find_if(begin, end, iswupper) != end); } if (!last_token_contains_uppercase) { @@ -884,9 +884,9 @@ void reader_write_title(const wcstring &cmd, bool reset_cursor_position) { if (exec_subshell(fish_title_command, parser_t::principal_parser(), lst, false /* ignore exit status */) != -1 && !lst.empty()) { - fputws(L"\x1B]0;", stdout); + std::fputws(L"\x1B]0;", stdout); for (size_t i = 0; i < lst.size(); i++) { - fputws(lst.at(i).c_str(), stdout); + std::fputws(lst.at(i).c_str(), stdout); } ignore_result(write(STDOUT_FILENO, "\a", 1)); } @@ -1146,7 +1146,7 @@ bool reader_data_t::insert_string(editable_line_t *el, const wcstring &str, // space). Expand abbreviations. if (has_expansion_triggering_char && allow_expand_abbreviations) { assert(range_end > 0); - assert(wcschr(expansion_triggering_chars, str.at(range_end - 1))); + assert(std::wcschr(expansion_triggering_chars, str.at(range_end - 1))); expand_abbreviation_as_necessary(1); } cursor = range_end; @@ -1330,7 +1330,7 @@ static std::function get_autosuggestion_performer if (!cursor_at_end && iswspace(last_char)) return nothing; // On the other hand, if the line ends with a quote, don't go dumping stuff after the quote. - if (wcschr(L"'\"", last_char) && cursor_at_end) return nothing; + if (std::wcschr(L"'\"", last_char) && cursor_at_end) return nothing; // Try normal completions. completion_request_flags_t complete_flags = COMPLETION_REQUEST_AUTOSUGGESTION; @@ -1467,7 +1467,7 @@ static bool reader_can_replace(const wcstring &in, int flags) { // Test characters that have a special meaning in any character position. while (*str) { - if (wcschr(REPLACE_UNCLEAN, *str)) return false; + if (std::wcschr(REPLACE_UNCLEAN, *str)) return false; str++; } @@ -2007,7 +2007,7 @@ parser_test_error_bits_t reader_shell_test(const wcstring &b) { if (!string_suffixes_string(L"\n", error_desc)) { error_desc.push_back(L'\n'); } - fwprintf(stderr, L"\n%ls", error_desc.c_str()); + std::fwprintf(stderr, L"\n%ls", error_desc.c_str()); } return res; } @@ -2204,13 +2204,13 @@ void reader_import_history_if_necessary() { bool shell_is_exiting() { return s_pending_exit.should_exit(); } void reader_bg_job_warning() { - fputws(_(L"There are still jobs active:\n"), stdout); - fputws(_(L"\n PID Command\n"), stdout); + std::fputws(_(L"There are still jobs active:\n"), stdout); + std::fputws(_(L"\n PID Command\n"), stdout); job_iterator_t jobs; while (job_t *j = jobs.next()) { if (!j->is_completed()) { - fwprintf(stdout, L"%6d %ls\n", j->processes[0]->pid, j->command_wcstr()); + std::fwprintf(stdout, L"%6d %ls\n", j->processes[0]->pid, j->command_wcstr()); } } fputws(L"\n", stdout); @@ -2438,7 +2438,7 @@ maybe_t reader_data_t::readline(int nchars) { is_interactive_read = 1; c = input_readch(); is_interactive_read = was_interactive_read; - // fwprintf(stderr, L"C: %lx\n", (long)c); + // std::fwprintf(stderr, L"C: %lx\n", (long)c); if (((!fish_reserved_codepoint(c))) && (c > 31) && (c != 127) && can_read(0)) { wchar_t arr[READAHEAD_MAX + 1]; @@ -2499,7 +2499,7 @@ maybe_t reader_data_t::readline(int nchars) { if (command_ends_paging(c, focused_on_search_field)) { clear_pager(); } - // fwprintf(stderr, L"\n\nchar: %ls\n\n", describe_char(c).c_str()); + // std::fwprintf(stderr, L"\n\nchar: %ls\n\n", describe_char(c).c_str()); switch (c) { // Go to beginning of line. @@ -2618,7 +2618,7 @@ maybe_t reader_data_t::readline(int nchars) { // up to the end of the token we're completing. const wcstring buffcpy = wcstring(cmdsub_begin, token_end); - // fwprintf(stderr, L"Complete (%ls)\n", buffcpy.c_str()); + // std::fwprintf(stderr, L"Complete (%ls)\n", buffcpy.c_str()); complete_flags_t complete_flags = COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_DESCRIPTIONS | COMPLETION_REQUEST_FUZZY_MATCH; @@ -2727,7 +2727,7 @@ maybe_t reader_data_t::readline(int nchars) { case R_YANK: { yank_str = kill_yank(); insert_string(active_edit_line(), yank_str); - yank_len = wcslen(yank_str); + yank_len = std::wcslen(yank_str); break; } case R_YANK_POP: { @@ -2736,7 +2736,7 @@ maybe_t reader_data_t::readline(int nchars) { yank_str = kill_yank_rotate(); insert_string(active_edit_line(), yank_str); - yank_len = wcslen(yank_str); + yank_len = std::wcslen(yank_str); } break; } @@ -3476,7 +3476,7 @@ static int read_ni(int fd, const io_chain_t &io) { } else { wcstring sb; parser.get_backtrace(str, errors, sb); - fwprintf(stderr, L"%ls", sb.c_str()); + std::fwprintf(stderr, L"%ls", sb.c_str()); res = 1; } } else { diff --git a/src/screen.cpp b/src/screen.cpp index 560868739..bc3161a40 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #if HAVE_CURSES_H #include @@ -101,12 +101,12 @@ static bool is_screen_name_escape_seq(const wchar_t *code, size_t *resulting_len return false; } const wchar_t *const screen_name_end_sentinel = L"\x1B\\"; - const wchar_t *screen_name_end = wcsstr(&code[2], screen_name_end_sentinel); + const wchar_t *screen_name_end = std::wcsstr(&code[2], screen_name_end_sentinel); if (screen_name_end == NULL) { // Consider just k to be the code. *resulting_length = 2; } else { - const wchar_t *escape_sequence_end = screen_name_end + wcslen(screen_name_end_sentinel); + const wchar_t *escape_sequence_end = screen_name_end + std::wcslen(screen_name_end_sentinel); *resulting_length = escape_sequence_end - code; } return true; @@ -403,7 +403,7 @@ static void s_desired_append_char(screen_t *s, wchar_t b, highlight_spec_t c, in if ((s->desired.cursor.x + cw) > screen_width) { // Current line is soft wrapped (assuming we support it). s->desired.line(s->desired.cursor.y).is_soft_wrapped = true; - // fwprintf(stderr, L"\n\n1 Soft wrapping %d\n\n", s->desired.cursor.y); + // std::fwprintf(stderr, L"\n\n1 Soft wrapping %d\n\n", s->desired.cursor.y); line_no = (int)s->desired.line_count(); s->desired.add_line(); @@ -863,7 +863,7 @@ static screen_layout_t compute_layout(screen_t *s, size_t screen_width, // Compute the width of the autosuggestion at all possible truncation offsets. std::vector autosuggest_truncated_widths; - autosuggest_truncated_widths.reserve(1 + wcslen(autosuggestion)); + autosuggest_truncated_widths.reserve(1 + std::wcslen(autosuggestion)); size_t autosuggest_total_width = 0; for (size_t i = 0; autosuggestion[i] != L'\0'; i++) { autosuggest_truncated_widths.push_back(autosuggest_total_width); diff --git a/src/screen.h b/src/screen.h index 3a0afba73..d44e40457 100644 --- a/src/screen.h +++ b/src/screen.h @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 38ec77029..8de6f3da2 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include @@ -223,7 +223,7 @@ tok_t tokenizer_t::read_string() { this->buff = end; } else { const wchar_t *error_loc = this->buff; - this->buff += wcslen(this->buff); + this->buff += std::wcslen(this->buff); if ((!this->accept_unfinished)) { return this->call_error(tokenizer_error_t::unterminated_quote, buff_start, error_loc); @@ -637,7 +637,7 @@ bool move_word_state_machine_t::consume_char_punctuation(wchar_t c) { bool move_word_state_machine_t::is_path_component_character(wchar_t c) { // Always treat separators as first. All this does is ensure that we treat ^ as a string // character instead of as stderr redirection, which I hypothesize is usually what is desired. - return tok_is_string_character(c, true) && !wcschr(L"/={,}'\"", c); + return tok_is_string_character(c, true) && !std::wcschr(L"/={,}'\"", c); } bool move_word_state_machine_t::consume_char_path_components(wchar_t c) { @@ -650,7 +650,7 @@ bool move_word_state_machine_t::consume_char_path_components(wchar_t c) { s_end }; - // fwprintf(stdout, L"state %d, consume '%lc'\n", state, c); + // std::fwprintf(stdout, L"state %d, consume '%lc'\n", state, c); bool consumed = false; while (state != s_end && !consumed) { switch (state) { diff --git a/src/util.cpp b/src/util.cpp index 550c1830b..5bb89e5ba 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include "common.h" @@ -85,7 +85,7 @@ int wcsfilecmp(const wchar_t *a, const wchar_t *b) { // names are literally identical because that won't occur given how this function is // used. And even if it were to occur (due to being reused in some other context) it // would be so rare that it isn't worth optimizing for. - retval = wcscmp(orig_a, orig_b); + retval = std::wcscmp(orig_a, orig_b); return retval < 0 ? -1 : retval == 0 ? 0 : 1; } return -1; // string a is a prefix of b and b is longer diff --git a/src/wcstringutil.cpp b/src/wcstringutil.cpp index b56da9d99..c8e47b30c 100644 --- a/src/wcstringutil.cpp +++ b/src/wcstringutil.cpp @@ -39,7 +39,7 @@ wcstring truncate(const wcstring &input, int max_len, ellipsis_type etype) { return input.substr(0, max_len); } if (etype == ellipsis_type::Prettiest) { - return input.substr(0, max_len - wcslen(ellipsis_str)).append(ellipsis_str); + return input.substr(0, max_len - std::wcslen(ellipsis_str)).append(ellipsis_str); } wcstring output = input.substr(0, max_len - 1); output.push_back(ellipsis_char); diff --git a/src/wgetopt.cpp b/src/wgetopt.cpp index 155759ad2..2355db669 100644 --- a/src/wgetopt.cpp +++ b/src/wgetopt.cpp @@ -39,7 +39,7 @@ #include "config.h" // IWYU pragma: keep #include -#include +#include #include // This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves @@ -159,7 +159,7 @@ int wgetopter_t::_advance_to_next_argv( //!OCLINT(high cyclomatic complexity) // The special ARGV-element `--' means premature end of options. Skip it like a null option, // then exchange with previous non-options as if it were an option, then skip everything // else like a non-option. - if (woptind != argc && !wcscmp(argv[woptind], L"--")) { + if (woptind != argc && !std::wcscmp(argv[woptind], L"--")) { woptind++; if (first_nonopt != last_nonopt && last_nonopt != woptind) { @@ -198,14 +198,14 @@ int wgetopter_t::_advance_to_next_argv( //!OCLINT(high cyclomatic complexity) int wgetopter_t::_handle_short_opt(int argc, wchar_t **argv) { // Look at and handle the next short option-character. wchar_t c = *nextchar++; - const wchar_t *temp = wcschr(shortopts, c); + const wchar_t *temp = std::wcschr(shortopts, c); // Increment `woptind' when we start to process its last character. if (*nextchar == '\0') ++woptind; if (temp == NULL || c == ':') { if (wopterr) { - fwprintf(stderr, _(L"%ls: Invalid option -- %lc\n"), argv[0], (wint_t)c); + std::fwprintf(stderr, _(L"%ls: Invalid option -- %lc\n"), argv[0], (wint_t)c); } woptopt = c; @@ -236,7 +236,7 @@ int wgetopter_t::_handle_short_opt(int argc, wchar_t **argv) { } else if (woptind == argc) { if (wopterr) { // 1003.2 specifies the format of this message. - fwprintf(stderr, _(L"%ls: Option requires an argument -- %lc\n"), argv[0], + std::fwprintf(stderr, _(L"%ls: Option requires an argument -- %lc\n"), argv[0], (wint_t)c); } woptopt = c; @@ -263,14 +263,14 @@ void wgetopter_t::_update_long_opt(int argc, wchar_t **argv, const struct woptio else { if (wopterr) { if (argv[woptind - 1][1] == '-') // --option - fwprintf(stderr, _(L"%ls: Option '--%ls' doesn't allow an argument\n"), argv[0], + std::fwprintf(stderr, _(L"%ls: Option '--%ls' doesn't allow an argument\n"), argv[0], pfound->name); else // +option or -option - fwprintf(stderr, _(L"%ls: Option '%lc%ls' doesn't allow an argument\n"), + std::fwprintf(stderr, _(L"%ls: Option '%lc%ls' doesn't allow an argument\n"), argv[0], argv[woptind - 1][0], pfound->name); } - nextchar += wcslen(nextchar); + nextchar += std::wcslen(nextchar); *retval = '?'; return; } @@ -279,15 +279,15 @@ void wgetopter_t::_update_long_opt(int argc, wchar_t **argv, const struct woptio woptarg = argv[woptind++]; else { if (wopterr) - fwprintf(stderr, _(L"%ls: Option '%ls' requires an argument\n"), argv[0], + std::fwprintf(stderr, _(L"%ls: Option '%ls' requires an argument\n"), argv[0], argv[woptind - 1]); - nextchar += wcslen(nextchar); + nextchar += std::wcslen(nextchar); *retval = missing_arg_return_colon ? ':' : '?'; return; } } - nextchar += wcslen(nextchar); + nextchar += std::wcslen(nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; @@ -306,7 +306,7 @@ const struct woption *wgetopter_t::_find_matching_long_opt(const struct woption // Test all long options for either exact match or abbreviated matches. for (const struct woption *p = longopts; p->name; p++, option_index++) { - if (!wcsncmp(p->name, nextchar, nameend - nextchar)) { + if (!std::wcsncmp(p->name, nextchar, nameend - nextchar)) { if ((unsigned int)(nameend - nextchar) == (unsigned int)wcslen(p->name)) { // Exact match found. pfound = p; @@ -342,9 +342,9 @@ bool wgetopter_t::_handle_long_opt(int argc, wchar_t **argv, const struct woptio if (ambig && !exact) { if (wopterr) { - fwprintf(stderr, _(L"%ls: Option '%ls' is ambiguous\n"), argv[0], argv[woptind]); + std::fwprintf(stderr, _(L"%ls: Option '%ls' is ambiguous\n"), argv[0], argv[woptind]); } - nextchar += wcslen(nextchar); + nextchar += std::wcslen(nextchar); woptind++; *retval = '?'; return true; @@ -358,13 +358,13 @@ bool wgetopter_t::_handle_long_opt(int argc, wchar_t **argv, const struct woptio // Can't find it as a long option. If this is not getopt_long_only, or the option starts // with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a // short option. - if (!long_only || argv[woptind][1] == '-' || wcschr(shortopts, *nextchar) == NULL) { + if (!long_only || argv[woptind][1] == '-' || std::wcschr(shortopts, *nextchar) == NULL) { if (wopterr) { if (argv[woptind][1] == '-') // --option - fwprintf(stderr, _(L"%ls: Unrecognized option '--%ls'\n"), argv[0], nextchar); + std::fwprintf(stderr, _(L"%ls: Unrecognized option '--%ls'\n"), argv[0], nextchar); else // +option or -option - fwprintf(stderr, _(L"%ls: Unrecognized option '%lc%ls'\n"), argv[0], + std::fwprintf(stderr, _(L"%ls: Unrecognized option '%lc%ls'\n"), argv[0], argv[woptind][0], nextchar); } nextchar = (wchar_t *)L""; @@ -441,7 +441,7 @@ int wgetopter_t::_wgetopt_internal(int argc, wchar_t **argv, const wchar_t *opts // This distinction seems to be the most useful approach. if (longopts != NULL && (argv[woptind][1] == '-' || - (long_only && (argv[woptind][2] || !wcschr(shortopts, argv[woptind][1]))))) { + (long_only && (argv[woptind][2] || !std::wcschr(shortopts, argv[woptind][1]))))) { int retval; if (_handle_long_opt(argc, argv, longopts, longind, long_only, &retval)) return retval; } diff --git a/src/wildcard.cpp b/src/wildcard.cpp index 6172c3042..398b155d8 100644 --- a/src/wildcard.cpp +++ b/src/wildcard.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -82,7 +82,7 @@ static bool wildcard_has_impl(const wchar_t *str, size_t len, bool internal) { bool wildcard_has(const wchar_t *str, bool internal) { assert(str != NULL); - return wildcard_has_impl(str, wcslen(str), internal); + return wildcard_has_impl(str, std::wcslen(str), internal); } bool wildcard_has(const wcstring &str, bool internal) { @@ -99,9 +99,9 @@ static enum fuzzy_match_type_t wildcard_match_internal(const wchar_t *str, const bool leading_dots_fail_to_match) { // Hackish fix for issue #270. Prevent wildcards from matching . or .., but we must still allow // literal matches. - if (leading_dots_fail_to_match && (!wcscmp(str, L".") || !wcscmp(str, L".."))) { + if (leading_dots_fail_to_match && (!std::wcscmp(str, L".") || !std::wcscmp(str, L".."))) { // The string is '.' or '..'. Return true if the wildcard exactly matches. - return wcscmp(str, wc) ? fuzzy_match_none : fuzzy_match_exact; + return std::wcscmp(str, wc) ? fuzzy_match_none : fuzzy_match_exact; } // Near Linear implementation as proposed here https://research.swtch.com/glob. @@ -235,8 +235,8 @@ static bool wildcard_complete_internal(const wchar_t *str, const wchar_t *wc, // If we are not replacing the token, be careful to only store the part of the string after // the wildcard. - assert(!full_replacement || wcslen(wc) <= wcslen(str)); - wcstring out_completion = full_replacement ? params.orig : str + wcslen(wc); + assert(!full_replacement || std::wcslen(wc) <= std::wcslen(str)); + wcstring out_completion = full_replacement ? params.orig : str + std::wcslen(wc); wcstring out_desc = resolve_description(params.orig, &out_completion, params.expand_flags, params.desc_func); @@ -248,7 +248,7 @@ static bool wildcard_complete_internal(const wchar_t *str, const wchar_t *wc, } else if (next_wc_char_pos > 0) { // Here we have a non-wildcard prefix. Note that we don't do fuzzy matching for stuff before // a wildcard, so just do case comparison and then recurse. - if (wcsncmp(str, wc, next_wc_char_pos) == 0) { + if (std::wcsncmp(str, wc, next_wc_char_pos) == 0) { // Normal match. return wildcard_complete_internal(str + next_wc_char_pos, wc + next_wc_char_pos, params, flags, out); @@ -822,8 +822,8 @@ void wildcard_expander_t::expand(const wcstring &base_dir, const wchar_t *wc, } // Get the current segment and compute interesting properties about it. - const size_t wc_len = wcslen(wc); - const wchar_t *const next_slash = wcschr(wc, L'/'); + const size_t wc_len = std::wcslen(wc); + const wchar_t *const next_slash = std::wcschr(wc, L'/'); const bool is_last_segment = (next_slash == NULL); const size_t wc_segment_len = next_slash ? next_slash - wc : wc_len; const wcstring wc_segment = wcstring(wc, wc_segment_len); diff --git a/src/wutil.cpp b/src/wutil.cpp index 5dda39b87..b9aefb108 100644 --- a/src/wutil.cpp +++ b/src/wutil.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include @@ -260,9 +260,9 @@ int wunlink(const wcstring &file_name) { void wperror(const wchar_t *s) { int e = errno; if (s[0] != L'\0') { - fwprintf(stderr, L"%ls: ", s); + std::fwprintf(stderr, L"%ls: ", s); } - fwprintf(stderr, L"%s\n", strerror(e)); + std::fwprintf(stderr, L"%s\n", strerror(e)); } int make_fd_nonblocking(int fd) { @@ -604,7 +604,7 @@ int fish_iswgraph(wint_t wc) { /// Convenience variants on fish_wcwswidth(). /// /// See fallback.h for the normal definitions. -int fish_wcswidth(const wchar_t *str) { return fish_wcswidth(str, wcslen(str)); } +int fish_wcswidth(const wchar_t *str) { return fish_wcswidth(str, std::wcslen(str)); } /// Convenience variants on fish_wcwswidth(). /// @@ -635,7 +635,7 @@ int fish_wcstoi(const wchar_t *str, const wchar_t **endptr, int base) { errno = 0; wchar_t *_endptr; - long result = wcstol(str, &_endptr, base); + long result = std::wcstol(str, &_endptr, base); if (result > INT_MAX) { result = INT_MAX; errno = ERANGE; @@ -673,7 +673,7 @@ long fish_wcstol(const wchar_t *str, const wchar_t **endptr, int base) { errno = 0; wchar_t *_endptr; - long result = wcstol(str, &_endptr, base); + long result = std::wcstol(str, &_endptr, base); while (iswspace(*_endptr)) ++_endptr; // skip trailing whitespace if (!errno && *_endptr) { if (_endptr == str) { @@ -704,7 +704,7 @@ long long fish_wcstoll(const wchar_t *str, const wchar_t **endptr, int base) { errno = 0; wchar_t *_endptr; - long long result = wcstoll(str, &_endptr, base); + long long result = std::wcstoll(str, &_endptr, base); while (iswspace(*_endptr)) ++_endptr; // skip trailing whitespace if (!errno && *_endptr) { if (_endptr == str) { @@ -737,7 +737,7 @@ unsigned long long fish_wcstoull(const wchar_t *str, const wchar_t **endptr, int errno = 0; wchar_t *_endptr; - unsigned long long result = wcstoull(str, &_endptr, base); + unsigned long long result = std::wcstoull(str, &_endptr, base); while (iswspace(*_endptr)) ++_endptr; // skip trailing whitespace if (!errno && *_endptr) { if (_endptr == str) { @@ -755,7 +755,7 @@ unsigned long long fish_wcstoull(const wchar_t *str, const wchar_t **endptr, int double fish_wcstod(const wchar_t *str, wchar_t **endptr) { // The "fast path." If we're all ASCII and we fit inline, use strtod(). char narrow[128]; - size_t len = wcslen(str); + size_t len = std::wcslen(str); size_t len_plus_0 = 1 + len; auto is_digit = [](wchar_t c) { return '0' <= c && c <= '9'; }; if (len_plus_0 <= sizeof narrow && std::all_of(str, str + len, is_digit)) { From aaacdb89b628eb37bb2e7c461662a677baf9b23e Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Tue, 12 Mar 2019 15:07:07 -0700 Subject: [PATCH 0045/1732] Switches over to cstring from string.h. --- src/builtin.cpp | 4 ++-- src/builtin_math.cpp | 2 +- src/builtin_printf.cpp | 4 ++-- src/builtin_pwd.cpp | 4 ++-- src/builtin_read.cpp | 4 ++-- src/builtin_realpath.cpp | 4 ++-- src/builtin_set.cpp | 4 ++-- src/builtin_test.cpp | 4 ++-- src/color.cpp | 8 ++++---- src/color.h | 4 ++-- src/common.cpp | 30 +++++++++++++++--------------- src/env.cpp | 6 +++--- src/env_universal_common.cpp | 30 +++++++++++++++--------------- src/exec.cpp | 10 +++++----- src/expand.cpp | 4 ++-- src/fallback.cpp | 4 ++-- src/fish.cpp | 8 ++++---- src/fish_indent.cpp | 8 ++++---- src/fish_key_reader.cpp | 6 +++--- src/fish_tests.cpp | 26 +++++++++++++------------- src/history.cpp | 36 ++++++++++++++++++------------------ src/input_common.cpp | 4 ++-- src/io.cpp | 2 +- src/iothread.cpp | 2 +- src/output.cpp | 16 ++++++++-------- src/output.h | 2 +- src/path.cpp | 4 ++-- src/postfork.cpp | 6 +++--- src/print_help.cpp | 4 ++-- src/reader.cpp | 8 ++++---- src/screen.cpp | 6 +++--- src/tinyexpr.cpp | 10 +++++----- src/wgetopt.cpp | 2 +- src/wutil.cpp | 12 ++++++------ src/wutil.h | 2 +- 35 files changed, 145 insertions(+), 145 deletions(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index be3c98fbe..76e235813 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include @@ -97,7 +97,7 @@ int builtin_count_args(const wchar_t *const *argv) { /// This function works like wperror, but it prints its result into the streams.err string instead /// to stderr. Used by the builtin commands. void builtin_wperror(const wchar_t *s, io_streams_t &streams) { - char *err = strerror(errno); + char *err = std::strerror(errno); if (s != NULL) { streams.err.append(s); streams.err.append(L": "); diff --git a/src/builtin_math.cpp b/src/builtin_math.cpp index a1fb48d25..7798fe1a8 100644 --- a/src/builtin_math.cpp +++ b/src/builtin_math.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/builtin_printf.cpp b/src/builtin_printf.cpp index 1bcf05cc8..d12d9c596 100644 --- a/src/builtin_printf.cpp +++ b/src/builtin_printf.cpp @@ -57,7 +57,7 @@ #include #include #include -#include +#include #include #include #include @@ -238,7 +238,7 @@ void builtin_printf_state_t::verify_numeric(const wchar_t *s, const wchar_t *end if (errcode == ERANGE) { this->fatal_error(L"%ls: %ls", s, _(L"Number out of range")); } else { - this->fatal_error(L"%ls: %s", s, strerror(errcode)); + this->fatal_error(L"%ls: %s", s, std::strerror(errcode)); } } else if (*end) { if (s == end) diff --git a/src/builtin_pwd.cpp b/src/builtin_pwd.cpp index ca668b0ea..66fb64efc 100644 --- a/src/builtin_pwd.cpp +++ b/src/builtin_pwd.cpp @@ -1,7 +1,7 @@ // Implementation of the pwd builtin. #include "config.h" // IWYU pragma: keep -#include +#include #include "builtin.h" #include "builtin_pwd.h" @@ -58,7 +58,7 @@ int builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (auto real_pwd = wrealpath(pwd)) { pwd = std::move(*real_pwd); } else { - const char *error = strerror(errno); + const char *error = std::strerror(errno); streams.err.append_format(L"%ls: realpath failed:", cmd, error); return STATUS_CMD_ERROR; } diff --git a/src/builtin_read.cpp b/src/builtin_read.cpp index 523fb2d9e..a0f1ab91a 100644 --- a/src/builtin_read.cpp +++ b/src/builtin_read.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -319,7 +319,7 @@ static int read_one_char_at_a_time(int fd, wcstring &buff, int nchars, bool spli } else { size_t sz = std::mbrtowc(&res, &b, 1, &state); if (sz == (size_t)-1) { - memset(&state, 0, sizeof(state)); + std::memset(&state, 0, sizeof(state)); } else if (sz != (size_t)-2) { finished = true; } diff --git a/src/builtin_realpath.cpp b/src/builtin_realpath.cpp index 552eae5c1..62edae85b 100644 --- a/src/builtin_realpath.cpp +++ b/src/builtin_realpath.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include "builtin.h" @@ -43,7 +43,7 @@ int builtin_realpath(parser_t &parser, io_streams_t &streams, wchar_t **argv) { // realpath() just couldn't do it. Report the error and make it clear // this is an error from our builtin, not the system's realpath. streams.err.append_format(L"builtin %ls: %ls: %s\n", cmd, argv[optind], - strerror(errno)); + std::strerror(errno)); } else { // Who knows. Probably a bug in our wrealpath() implementation. streams.err.append_format(_(L"builtin %ls: Invalid path: %ls\n"), cmd, argv[optind]); diff --git a/src/builtin_set.cpp b/src/builtin_set.cpp index c57b1d60f..3a18e5a09 100644 --- a/src/builtin_set.cpp +++ b/src/builtin_set.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -295,7 +295,7 @@ static bool validate_path_warning_on_colons(const wchar_t *cmd, any_success = true; } else if (looks_like_colon_sep) { streams.err.append_format(BUILTIN_SET_PATH_ERROR, cmd, key, dir.c_str(), - strerror(errno)); + std::strerror(errno)); streams.err.append_format(BUILTIN_SET_PATH_HINT, cmd, key, key, std::wcschr(dir.c_str(), L':') + 1); } diff --git a/src/builtin_test.cpp b/src/builtin_test.cpp index b49fa7bb6..3951a7ecc 100644 --- a/src/builtin_test.cpp +++ b/src/builtin_test.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include @@ -675,7 +675,7 @@ static bool parse_number(const wcstring &arg, number_t *number, wcstring_list_t errors.push_back(format_string(_(L"Integer %lld in '%ls' followed by non-digit"), integral, argcs)); } else { - errors.push_back(format_string(L"%s: '%ls'", strerror(errno), argcs)); + errors.push_back(format_string(L"%s: '%ls'", std::strerror(errno), argcs)); } return false; } diff --git a/src/color.cpp b/src/color.cpp index 4dd60ef46..ceaec1ffd 100644 --- a/src/color.cpp +++ b/src/color.cpp @@ -11,7 +11,7 @@ #include "fallback.h" // IWYU pragma: keep bool rgb_color_t::try_parse_special(const wcstring &special) { - memset(&data, 0, sizeof data); + std::memset(&data, 0, sizeof data); const wchar_t *name = special.c_str(); if (!wcscasecmp(name, L"normal")) { this->type = type_normal; @@ -108,7 +108,7 @@ static unsigned char convert_color(const unsigned char rgb[3], const uint32_t *c } bool rgb_color_t::try_parse_rgb(const wcstring &name) { - memset(&data, 0, sizeof data); + std::memset(&data, 0, sizeof data); // We support the following style of rgb formats (case insensitive): // #FA3 // #F3A035 @@ -185,7 +185,7 @@ wcstring_list_t rgb_color_t::named_color_names() { } bool rgb_color_t::try_parse_named(const wcstring &str) { - memset(&data, 0, sizeof data); + std::memset(&data, 0, sizeof data); size_t max = sizeof named_colors / sizeof *named_colors; for (size_t idx = 0; idx < max; idx++) { if (0 == wcscasecmp(str.c_str(), named_colors[idx].name)) { @@ -299,7 +299,7 @@ void rgb_color_t::parse(const wcstring &str) { if (!success) success = try_parse_named(str); if (!success) success = try_parse_rgb(str); if (!success) { - memset(&this->data, 0, sizeof this->data); + std::memset(&this->data, 0, sizeof this->data); this->type = type_none; } } diff --git a/src/color.h b/src/color.h index ec6d29dbb..2e437b966 100644 --- a/src/color.h +++ b/src/color.h @@ -2,7 +2,7 @@ #ifndef FISH_COLOR_H #define FISH_COLOR_H -#include +#include #include @@ -159,7 +159,7 @@ class rgb_color_t { /// Compare two colors for equality. bool operator==(const rgb_color_t &other) const { - return type == other.type && !memcmp(&data, &other.data, sizeof data); + return type == other.type && !std::memcmp(&data, &other.data, sizeof data); } /// Compare two colors for inequality. diff --git a/src/common.cpp b/src/common.cpp index ba7da173d..cb158912f 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -141,7 +141,7 @@ long convert_digit(wchar_t d, int base) { } /// Test whether the char is a valid hex digit as used by the `escape_string_*()` functions. -static bool is_hex_digit(int c) { return strchr("0123456789ABCDEF", c) != NULL; } +static bool is_hex_digit(int c) { return std::strchr("0123456789ABCDEF", c) != NULL; } /// This is a specialization of `convert_digit()` that only handles base 16 and only uppercase. long convert_hex_digit(wchar_t d) { @@ -170,8 +170,8 @@ bool is_windows_subsystem_for_linux() { uname(&info); // Sample utsname.release under WSL: 4.4.0-17763-Microsoft - if (strstr(info.release, "Microsoft") != nullptr) { - const char *dash = strchr(info.release, '-'); + if (std::strstr(info.release, "Microsoft") != nullptr) { + const char *dash = std::strchr(info.release, '-'); if (dash == nullptr || strtod(dash + 1, nullptr) < 17763) { debug(1, "This version of WSL is not supported and fish will probably not work correctly!\n" "Please upgrade to Windows 10 1809 (17763) or higher to use fish!"); @@ -346,11 +346,11 @@ static wcstring str2wcs_internal(const char *in, const size_t in_len) { wc = ENCODE_DIRECT_BASE + (unsigned char)in[in_pos]; result.push_back(wc); in_pos++; - memset(&state, 0, sizeof state); + std::memset(&state, 0, sizeof state); } else if (ret == 0) { // embedded null byte! result.push_back(L'\0'); in_pos++; - memset(&state, 0, sizeof state); + std::memset(&state, 0, sizeof state); } else { // normal case result.push_back(wc); in_pos += ret; @@ -362,7 +362,7 @@ static wcstring str2wcs_internal(const char *in, const size_t in_len) { wcstring str2wcstring(const char *in, size_t len) { return str2wcs_internal(in, len); } -wcstring str2wcstring(const char *in) { return str2wcs_internal(in, strlen(in)); } +wcstring str2wcstring(const char *in) { return str2wcs_internal(in, std::strlen(in)); } wcstring str2wcstring(const std::string &in) { // Handles embedded nulls! @@ -423,11 +423,11 @@ std::string wcs2string(const wcstring &input) { converted[0] = wc; result.append(converted, 1); } else { - memset(converted, 0, sizeof converted); + std::memset(converted, 0, sizeof converted); size_t len = std::wcrtomb(converted, wc, &state); if (len == (size_t)-1) { debug(1, L"Wide character U+%4X has no narrow representation", wc); - memset(&state, 0, sizeof(state)); + std::memset(&state, 0, sizeof(state)); } else { result.append(converted, len); } @@ -467,7 +467,7 @@ static char *wcs2str_internal(const wchar_t *in, char *out) { size_t len = std::wcrtomb(&out[out_pos], in[in_pos], &state); if (len == (size_t)-1) { debug(1, L"Wide character U+%4X has no narrow representation", in[in_pos]); - memset(&state, 0, sizeof(state)); + std::memset(&state, 0, sizeof(state)); } else { out_pos += len; } @@ -707,8 +707,8 @@ void debug_safe(int level, const char *msg, const char *param1, const char *para size_t param_idx = 0; const char *cursor = msg; while (*cursor != '\0') { - const char *end = strchr(cursor, '%'); - if (end == NULL) end = cursor + strlen(cursor); + const char *end = std::strchr(cursor, '%'); + if (end == NULL) end = cursor + std::strlen(cursor); ignore_result(write(STDERR_FILENO, cursor, end - cursor)); @@ -717,7 +717,7 @@ void debug_safe(int level, const char *msg, const char *param1, const char *para assert(param_idx < sizeof params / sizeof *params); const char *format = params[param_idx++]; if (!format) format = "(null)"; - ignore_result(write(STDERR_FILENO, format, strlen(format))); + ignore_result(write(STDERR_FILENO, format, std::strlen(format))); cursor = end + 2; } else if (end[0] == '\0') { // Must be at the end of the string. @@ -2138,7 +2138,7 @@ void append_str(char *buff, const char *str, size_t *inout_idx, size_t max_len) void format_size_safe(char buff[128], unsigned long long sz) { const size_t buff_size = 128; const size_t max_len = buff_size - 1; // need to leave room for a null terminator - memset(buff, 0, buff_size); + std::memset(buff, 0, buff_size); size_t idx = 0; const char *const sz_name[] = {"kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", NULL}; if (sz < 1) { @@ -2403,7 +2403,7 @@ void redirect_tty_output() { [[noreturn]] void __fish_assert(const char *msg, const char *file, size_t line, int error) { if (error) { debug(0, L"%s:%zu: failed assertion: %s: errno %d (%s)", file, line, msg, error, - strerror(error)); + std::strerror(error)); } else { debug(0, L"%s:%zu: failed assertion: %s", file, line, msg); } diff --git a/src/env.cpp b/src/env.cpp index 13d95763e..40bc26b34 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include @@ -411,7 +411,7 @@ static void init_locale(const environment_t &vars) { debug(5, L"old LC_MESSAGES locale: '%s'", old_msg_locale); debug(5, L"new LC_MESSAGES locale: '%s'", new_msg_locale); #ifdef HAVE__NL_MSG_CAT_CNTR - if (strcmp(old_msg_locale, new_msg_locale)) { + if (std::strcmp(old_msg_locale, new_msg_locale)) { // Make change known to GNU gettext. extern int _nl_msg_cat_cntr; _nl_msg_cat_cntr++; @@ -455,7 +455,7 @@ static bool does_term_support_setting_title(const environment_t &vars) { char buf[PATH_MAX]; int retval = ttyname_r(STDIN_FILENO, buf, PATH_MAX); - if (retval != 0 || strstr(buf, "tty") || strstr(buf, "/vc/")) return false; + if (retval != 0 || std::strstr(buf, "tty") || std::strstr(buf, "/vc/")) return false; } return true; diff --git a/src/env_universal_common.cpp b/src/env_universal_common.cpp index f30cbad56..cde707860 100644 --- a/src/env_universal_common.cpp +++ b/src/env_universal_common.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #ifdef __CYGWIN__ #include #endif @@ -123,7 +123,7 @@ static maybe_t default_vars_path() { /// On success, updates the cursor to just past the command. static bool match(const wchar_t **inout_cursor, const char *cmd) { const wchar_t *cursor = *inout_cursor; - size_t len = strlen(cmd); + size_t len = std::strlen(cmd); if (!std::equal(cmd, cmd + len, cursor)) { return false; } @@ -445,7 +445,7 @@ bool env_universal_t::write_to_fd(int fd, const wcstring &path) { bool success = true; std::string contents = serialize_with_vars(vars); if (write_loop(fd, contents.data(), contents.size()) < 0) { - const char *error = strerror(errno); + const char *error = std::strerror(errno); debug(0, _(L"Unable to write to universal variables file '%ls': %s"), path.c_str(), error); success = false; } @@ -460,7 +460,7 @@ bool env_universal_t::write_to_fd(int fd, const wcstring &path) { bool env_universal_t::move_new_vars_file_into_place(const wcstring &src, const wcstring &dst) { int ret = wrename(src, dst); if (ret != 0) { - const char *error = strerror(errno); + const char *error = std::strerror(errno); debug(0, _(L"Unable to rename file from '%ls' to '%ls': %s"), src.c_str(), dst.c_str(), error); } @@ -521,7 +521,7 @@ bool env_universal_t::open_temporary_file(const wcstring &directory, wcstring *o } if (!success) { - const char *error = strerror(saved_errno); + const char *error = std::strerror(saved_errno); debug(0, _(L"Unable to open temporary file '%ls': %s"), out_path->c_str(), error); } return success; @@ -583,7 +583,7 @@ bool env_universal_t::open_and_acquire_lock(const wcstring &path, int *out_fd) { continue; } #endif - const char *error = strerror(errno); + const char *error = std::strerror(errno); debug(0, _(L"Unable to open universal variable file '%ls': %s"), path.c_str(), error); break; } @@ -801,7 +801,7 @@ uvar_format_t env_universal_t::format_for_contents(const std::string &s) { if (sscanf(line.c_str(), "# VERSION: %64s", versionbuf) != 1) continue; // Try reading the version. - if (!strcmp(versionbuf, UVARS_VERSION_3_0)) { + if (!std::strcmp(versionbuf, UVARS_VERSION_3_0)) { return uvar_format_t::fish_3_0; } else { // Unknown future version. @@ -946,7 +946,7 @@ static bool get_mac_address(unsigned char macaddr[MAC_ADDRESS_MAX_LEN], strncpy((char *)r.ifr_name, interface, sizeof r.ifr_name - 1); r.ifr_name[sizeof r.ifr_name - 1] = 0; if (ioctl(dummy, SIOCGIFHWADDR, &r) >= 0) { - memcpy(macaddr, r.ifr_hwaddr.sa_data, MAC_ADDRESS_MAX_LEN); + std::memcpy(macaddr, r.ifr_hwaddr.sa_data, MAC_ADDRESS_MAX_LEN); result = true; } close(dummy); @@ -978,7 +978,7 @@ static bool get_mac_address(unsigned char macaddr[MAC_ADDRESS_MAX_LEN], size_t alen = sdl.sdl_alen; if (alen > MAC_ADDRESS_MAX_LEN) alen = MAC_ADDRESS_MAX_LEN; - memcpy(macaddr, sdl.sdl_data + sdl.sdl_nlen, alen); + std::memcpy(macaddr, sdl.sdl_data + sdl.sdl_nlen, alen); ok = true; break; } @@ -1053,7 +1053,7 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t { bool errored = false; int fd = shm_open(path, O_RDWR | O_CREAT, 0600); if (fd < 0) { - const char *error = strerror(errno); + const char *error = std::strerror(errno); debug(0, _(L"Unable to open shared memory with path '%s': %s"), path, error); errored = true; } @@ -1063,7 +1063,7 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t { if (!errored) { struct stat buf = {}; if (fstat(fd, &buf) < 0) { - const char *error = strerror(errno); + const char *error = std::strerror(errno); debug(0, _(L"Unable to fstat shared memory object with path '%s': %s"), path, error); errored = true; @@ -1074,7 +1074,7 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t { // Set the size, if it's too small. bool set_size = !errored && size < (off_t)sizeof(universal_notifier_shmem_t); if (set_size && ftruncate(fd, sizeof(universal_notifier_shmem_t)) < 0) { - const char *error = strerror(errno); + const char *error = std::strerror(errno); debug(0, _(L"Unable to truncate shared memory object with path '%s': %s"), path, error); errored = true; } @@ -1084,7 +1084,7 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t { void *addr = mmap(NULL, sizeof(universal_notifier_shmem_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { - const char *error = strerror(errno); + const char *error = std::strerror(errno); debug(0, _(L"Unable to memory map shared memory object with path '%s': %s"), path, error); this->region = NULL; @@ -1489,7 +1489,7 @@ void universal_notifier_named_pipe_t::make_pipe(const wchar_t *test_path) { int mkfifo_status = mkfifo(narrow_path.c_str(), 0600); if (mkfifo_status == -1 && errno != EEXIST) { - const char *error = strerror(errno); + const char *error = std::strerror(errno); const wchar_t *errmsg = _(L"Unable to make a pipe for universal variables using '%ls': %s"); debug(0, errmsg, vars_path.c_str(), error); pipe_fd = -1; @@ -1498,7 +1498,7 @@ void universal_notifier_named_pipe_t::make_pipe(const wchar_t *test_path) { int fd = wopen_cloexec(vars_path, O_RDWR | O_NONBLOCK, 0600); if (fd < 0) { - const char *error = strerror(errno); + const char *error = std::strerror(errno); const wchar_t *errmsg = _(L"Unable to open a pipe for universal variables using '%ls': %s"); debug(0, errmsg, vars_path.c_str(), error); pipe_fd = -1; diff --git a/src/exec.cpp b/src/exec.cpp index 7d55ca99e..05ebea52a 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -14,7 +14,7 @@ #include #endif #include -#include +#include #include #include #include @@ -78,7 +78,7 @@ static bool redirection_is_to_real_file(const shared_ptr &io) { if (io && io->io_mode == io_mode_t::file) { // It's a file redirection. Compare the path to /dev/null. const char *path = static_cast(io.get())->filename_cstr; - if (strcmp(path, "/dev/null") != 0) { + if (std::strcmp(path, "/dev/null") != 0) { // It's not /dev/null. result = true; } @@ -104,9 +104,9 @@ char *get_interpreter(const char *command, char *interpreter, size_t buff_size) close(fd); } - if (strncmp(interpreter, "#! /", 4) == 0) { + if (std::strncmp(interpreter, "#! /", 4) == 0) { return interpreter + 3; - } else if (strncmp(interpreter, "#!/", 3) == 0) { + } else if (std::strncmp(interpreter, "#!/", 3) == 0) { return interpreter + 2; } @@ -1126,7 +1126,7 @@ static int exec_subshell_internal(const wcstring &cmd, parser_t &parser, wcstrin const char *cursor = begin; while (cursor < end) { // Look for the next separator. - const char *stop = (const char *)memchr(cursor, '\n', end - cursor); + const char *stop = (const char *)std::memchr(cursor, '\n', end - cursor); const bool hit_separator = (stop != NULL); if (!hit_separator) { // If it's not found, just use the end. diff --git a/src/expand.cpp b/src/expand.cpp index 4c7532fc8..42c44d8fa 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -1156,7 +1156,7 @@ expand_error_t expand_to_command_and_args(const wcstring &instr, const environme static std::string escape_single_quoted_hack_hack_hack_hack(const char *str) { std::string result; - size_t len = strlen(str); + size_t len = std::strlen(str); result.reserve(len + 2); result.push_back('\''); for (size_t i = 0; i < len; i++) { diff --git a/src/fallback.cpp b/src/fallback.cpp index f028e3f05..b944c0406 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -14,7 +14,7 @@ #include // IWYU pragma: keep #include // IWYU pragma: keep #include -#include +#include #include // IWYU pragma: keep #include // IWYU pragma: keep #include @@ -81,7 +81,7 @@ int fish_mkstemp_cloexec(char *name_template) { return 0; } - memcpy(out, in, sizeof(wchar_t) * (len + 1)); + std::memcpy(out, in, sizeof(wchar_t) * (len + 1)); return out; } diff --git a/src/fish.cpp b/src/fish.cpp index 4ec0ab190..21832b265 100644 --- a/src/fish.cpp +++ b/src/fish.cpp @@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA #include #include #include -#include +#include #include #include #include @@ -69,9 +69,9 @@ class fish_cmd_opts_t { static const char *s_profiling_output_filename = NULL; static bool has_suffix(const std::string &path, const char *suffix, bool ignore_case) { - size_t pathlen = path.size(), suffixlen = strlen(suffix); + size_t pathlen = path.size(), suffixlen = std::strlen(suffix); return pathlen >= suffixlen && - !(ignore_case ? strcasecmp : strcmp)(path.c_str() + pathlen - suffixlen, suffix); + !(ignore_case ? strcasecmp : std::strcmp)(path.c_str() + pathlen - suffixlen, suffix); } /// Modifies the given path by calling realpath. Returns true if realpath succeeded, false @@ -122,7 +122,7 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0) bool seems_installed = (suffix == installed_suffix); wcstring base_path = str2wcstring(exec_path); - base_path.resize(base_path.size() - strlen(suffix)); + base_path.resize(base_path.size() - std::strlen(suffix)); paths.data = base_path + (seems_installed ? L"/share/fish" : L"/share"); paths.sysconf = base_path + (seems_installed ? L"/etc/fish" : L"/etc"); diff --git a/src/fish_indent.cpp b/src/fish_indent.cpp index 61633dc10..01d3a3b94 100644 --- a/src/fish_indent.cpp +++ b/src/fish_indent.cpp @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA #include #include #include -#include +#include #include #include @@ -63,7 +63,7 @@ static wcstring read_file(FILE *f) { // Illegal byte sequence. Try to skip past it. clearerr(f); int ch = fgetc(f); // for printing the warning, and seeks forward 1 byte. - debug(1, "%s (byte=%X)", strerror(errno), ch); + debug(1, "%s (byte=%X)", std::strerror(errno), ch); ret = 1; continue; } else { @@ -518,7 +518,7 @@ int main(int argc, char *argv[]) { fclose(fh); output_location = *argv; } else { - std::fwprintf(stderr, _(L"Opening \"%s\" failed: %s\n"), *argv, strerror(errno)); + std::fwprintf(stderr, _(L"Opening \"%s\" failed: %s\n"), *argv, std::strerror(errno)); exit(1); } } else { @@ -549,7 +549,7 @@ int main(int argc, char *argv[]) { exit(0); } else { std::fwprintf(stderr, _(L"Opening \"%s\" failed: %s\n"), output_location, - strerror(errno)); + std::strerror(errno)); exit(1); } break; diff --git a/src/fish_key_reader.cpp b/src/fish_key_reader.cpp index fba073944..be845c63b 100644 --- a/src/fish_key_reader.cpp +++ b/src/fish_key_reader.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -62,7 +62,7 @@ static bool should_exit(wchar_t wc) { std::fwprintf(stderr, L"Press [ctrl-%c] again to exit\n", shell_modes.c_cc[VEOF] + 0x40); return false; } - return memcmp(recent_chars, "exit", 4) == 0 || memcmp(recent_chars, "quit", 4) == 0; + return std::memcmp(recent_chars, "exit", 4) == 0 || std::memcmp(recent_chars, "quit", 4) == 0; } /// Return the name if the recent sequence of characters matches a known terminfo sequence. @@ -265,7 +265,7 @@ static void install_our_signal_handlers() { for (int signo = 1; signo < 32; signo++) { if (sigaction(signo, &new_sa, &old_sa) != -1) { - memcpy(&old_sigactions[signo], &old_sa, sizeof(old_sa)); + std::memcpy(&old_sigactions[signo], &old_sa, sizeof(old_sa)); if (old_sa.sa_handler == SIG_IGN) { debug(3, "signal #%d (%ls) was being ignored", signo, sig2wcs(signo)); } diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 9059cf101..e459dc504 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -89,7 +89,7 @@ static bool should_test_function(const char *func_name) { result = true; } else { for (size_t i = 0; s_arguments[i] != NULL; i++) { - if (!strncmp(func_name, s_arguments[i], strlen(s_arguments[i]))) { + if (!std::strncmp(func_name, s_arguments[i], std::strlen(s_arguments[i]))) { // Prefix match. result = true; break; @@ -448,14 +448,14 @@ static void test_format() { for (i = 0; i < sizeof tests / sizeof *tests; i++) { char buff[128]; format_size_safe(buff, tests[i].val); - do_test(!strcmp(buff, tests[i].expected)); + do_test(!std::strcmp(buff, tests[i].expected)); } for (int j = -129; j <= 129; j++) { char buff1[128], buff2[128]; format_long_safe(buff1, j); sprintf(buff2, "%d", j); - do_test(!strcmp(buff1, buff2)); + do_test(!std::strcmp(buff1, buff2)); wchar_t wbuf1[128], wbuf2[128]; format_long_safe(wbuf1, j); @@ -467,12 +467,12 @@ static void test_format() { char buff1[128], buff2[128]; format_long_safe(buff1, q); sprintf(buff2, "%ld", q); - do_test(!strcmp(buff1, buff2)); + do_test(!std::strcmp(buff1, buff2)); } /// Helper to convert a narrow string to a sequence of hex digits. static char *str2hex(const char *input) { - char *output = (char *)malloc(5 * strlen(input) + 1); + char *output = (char *)malloc(5 * std::strlen(input) + 1); char *p = output; for (; *input; input++) { sprintf(p, "0x%02X ", (int)*input & 0xFF); @@ -511,12 +511,12 @@ static void test_convert() { L"wcs2str"); } - if (strcmp(o, n)) { + if (std::strcmp(o, n)) { char *o2 = str2hex(o); char *n2 = str2hex(n); err(L"Line %d - %d: Conversion cycle of string:\n%4d chars: %s\n" L"produced different string:\n%4d chars: %s", - __LINE__, i, strlen(o), o2, strlen(n), n2); + __LINE__, i, std::strlen(o), o2, std::strlen(n), n2); free(o2); free(n2); } @@ -1258,7 +1258,7 @@ static void test_utf82wchar(const char *src, size_t slen, const wchar_t *dst, si if (res != size) { err(L"u2w: %s: FAILED (rv: %lu, must be %lu)", descr, size, res); - } else if (mem && memcmp(mem, dst, size * sizeof(*mem)) != 0) { + } else if (mem && std::memcmp(mem, dst, size * sizeof(*mem)) != 0) { err(L"u2w: %s: BROKEN", descr); } @@ -1303,7 +1303,7 @@ static void test_wchar2utf8(const wchar_t *src, size_t slen, const char *dst, si size = wchar_to_utf8(src, slen, mem, dlen, flags); if (res != size) { err(L"w2u: %s: FAILED (rv: %lu, must be %lu)", descr, size, res); - } else if (dst && memcmp(mem, dst, size) != 0) { + } else if (dst && std::memcmp(mem, dst, size) != 0) { err(L"w2u: %s: BROKEN", descr); } @@ -1459,7 +1459,7 @@ static void test_escape_sequences() { err(L"test_escape_sequences failed on line %d\n", __LINE__); if (escape_code_length(L"\x1B[2J") != 4) err(L"test_escape_sequences failed on line %d\n", __LINE__); - if (escape_code_length(L"\x1B[38;5;123mABC") != strlen("\x1B[38;5;123m")) + if (escape_code_length(L"\x1B[38;5;123mABC") != std::strlen("\x1B[38;5;123m")) err(L"test_escape_sequences failed on line %d\n", __LINE__); if (escape_code_length(L"\x1B@") != 2) err(L"test_escape_sequences failed on line %d\n", __LINE__); @@ -3230,7 +3230,7 @@ static void test_universal_ok_to_save() { const char *contents = "# VERSION: 99999.99\n"; FILE *fp = wfopen(UVARS_TEST_PATH, "w"); assert(fp && "Failed to open UVARS_TEST_PATH for writing"); - fwrite(contents, strlen(contents), 1, fp); + fwrite(contents, std::strlen(contents), 1, fp); fclose(fp); file_id_t before_id = file_id_for_path(UVARS_TEST_PATH); @@ -5176,7 +5176,7 @@ int main(int argc, char **argv) { perror("getcwd"); exit(-1); } - if (!strcmp(wd, "/")) { + if (!std::strcmp(wd, "/")) { std::fwprintf(stderr, L"Unable to find 'tests' directory, which should contain file test.fish\n"); exit(EXIT_FAILURE); diff --git a/src/history.cpp b/src/history.cpp index 1c7abddfb..d0deb6eb5 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include // We need the sys/file.h for the flock() declaration on Linux but not OS X. #include // IWYU pragma: keep @@ -75,10 +75,10 @@ static constexpr int max_save_tries = 1024; namespace { +static size_t safe_strlen(const char *s) { return s ? std::strlen(s) : 0; } /// Helper class for certain output. This is basically a string that allows us to ensure we only /// flush at record boundaries, and avoids the copying of ostringstream. Have you ever tried to /// implement your own streambuf? Total insanity. -static size_t safe_strlen(const char *s) { return s ? strlen(s) : 0; } class history_output_buffer_t { std::vector buffer; @@ -271,7 +271,7 @@ class history_file_contents_t { ptr += amt; } } - memset(ptr, 0, remaining); + std::memset(ptr, 0, remaining); return true; } @@ -350,7 +350,7 @@ static size_t read_line(const char *base, size_t cursor, size_t len, std::string // Locate the newline. assert(cursor <= len); const char *start = base + cursor; - const char *a_newline = (char *)memchr(start, '\n', len - cursor); + const char *a_newline = (char *)std::memchr(start, '\n', len - cursor); if (a_newline != NULL) { // we found a newline result.assign(start, a_newline - start); // Return the amount to advance the cursor; skip over the newline. @@ -513,7 +513,7 @@ static history_item_t decode_item_fish_2_0(const char *base, size_t len) { size_t advance = read_line(base, cursor, len, line); if (trim_leading_spaces(line) <= indent) break; - if (strncmp(line.c_str(), "- ", 2)) break; + if (std::strncmp(line.c_str(), "- ", 2)) break; // We're going to consume this line. cursor += advance; @@ -636,7 +636,7 @@ static bool parse_timestamp(const char *str, time_t *out_when) { // Look for "when:". size_t when_len = 5; - if (strncmp(cursor, "when:", when_len) != 0) return false; + if (std::strncmp(cursor, "when:", when_len) != 0) return false; cursor += when_len; // Advance past spaces. @@ -661,7 +661,7 @@ static const char *next_line(const char *start, size_t length) { const char *const end = start + length; // Skip past the next newline. - const char *nextline = (const char *)memchr(start, '\n', length); + const char *nextline = (const char *)std::memchr(start, '\n', length); if (!nextline || nextline >= end) { return NULL; } @@ -671,7 +671,7 @@ static const char *next_line(const char *start, size_t length) { } // Make sure this new line is itself "newline terminated". If it's not, return NULL. - const char *next_newline = (const char *)memchr(nextline, '\n', end - nextline); + const char *next_newline = (const char *)std::memchr(nextline, '\n', end - nextline); if (!next_newline) { return NULL; } @@ -694,7 +694,7 @@ static size_t offset_of_next_item_fish_2_0(const history_file_contents_t &conten const char *line_start = contents.address_at(cursor); // Advance the cursor to the next line. - const char *a_newline = (const char *)memchr(line_start, '\n', length - cursor); + const char *a_newline = (const char *)std::memchr(line_start, '\n', length - cursor); if (a_newline == NULL) break; // Advance the cursor past this line. +1 is for the newline. @@ -707,26 +707,26 @@ static size_t offset_of_next_item_fish_2_0(const history_file_contents_t &conten if (a_newline - line_start < 3) continue; // Try to be a little YAML compatible. Skip lines with leading %, ---, or ... - if (!memcmp(line_start, "%", 1) || !memcmp(line_start, "---", 3) || - !memcmp(line_start, "...", 3)) + if (!std::memcmp(line_start, "%", 1) || !std::memcmp(line_start, "---", 3) || + !std::memcmp(line_start, "...", 3)) continue; // Hackish: fish 1.x rewriting a fish 2.0 history file can produce lines with lots of // leading "- cmd: - cmd: - cmd:". Trim all but one leading "- cmd:". const char *double_cmd = "- cmd: - cmd: "; - const size_t double_cmd_len = strlen(double_cmd); + const size_t double_cmd_len = std::strlen(double_cmd); while ((size_t)(a_newline - line_start) > double_cmd_len && - !memcmp(line_start, double_cmd, double_cmd_len)) { + !std::memcmp(line_start, double_cmd, double_cmd_len)) { // Skip over just one of the - cmd. In the end there will be just one left. - line_start += strlen("- cmd: "); + line_start += std::strlen("- cmd: "); } // Hackish: fish 1.x rewriting a fish 2.0 history file can produce commands like "when: // 123456". Ignore those. const char *cmd_when = "- cmd: when:"; - const size_t cmd_when_len = strlen(cmd_when); + const size_t cmd_when_len = std::strlen(cmd_when); if ((size_t)(a_newline - line_start) >= cmd_when_len && - !memcmp(line_start, cmd_when, cmd_when_len)) { + !std::memcmp(line_start, cmd_when, cmd_when_len)) { continue; } @@ -1141,7 +1141,7 @@ wcstring history_search_t::current_string() const { } static void replace_all(std::string *str, const char *needle, const char *replacement) { - size_t needle_len = strlen(needle), replacement_len = strlen(replacement); + size_t needle_len = std::strlen(needle), replacement_len = std::strlen(replacement); size_t offset = 0; while ((offset = str->find(needle, offset)) != std::string::npos) { str->replace(offset, needle_len, replacement); @@ -1820,7 +1820,7 @@ void history_t::populate_from_bash(FILE *stream) { } // Deal with the newline if present. - char *a_newline = strchr(buff, '\n'); + char *a_newline = std::strchr(buff, '\n'); if (a_newline) *a_newline = '\0'; line.append(buff); if (a_newline) break; diff --git a/src/input_common.cpp b/src/input_common.cpp index 655f5dfc2..19e4356a3 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -2,7 +2,7 @@ #include "config.h" #include -#include +#include #include #ifdef HAVE_SYS_SELECT_H #include @@ -205,7 +205,7 @@ wchar_t input_common_readch(int timed) { switch (sz) { case (size_t)(-1): { - memset(&state, '\0', sizeof(state)); + std::memset(&state, '\0', sizeof(state)); debug(2, L"Illegal input"); return R_NULL; } diff --git a/src/io.cpp b/src/io.cpp index 5f2ed4166..727796c96 100644 --- a/src/io.cpp +++ b/src/io.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/iothread.cpp b/src/iothread.cpp index a9d799b43..d3f7220dc 100644 --- a/src/iothread.cpp +++ b/src/iothread.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/output.cpp b/src/output.cpp index 5cca74258..14d210c3c 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #if HAVE_CURSES_H #include #elif HAVE_NCURSES_H @@ -234,7 +234,7 @@ void outputter_t::set_color(rgb_color_t c, rgb_color_t c2) { if (c == c2) c = (c2 == rgb_color_t::white()) ? rgb_color_t::black() : rgb_color_t::white(); } - if ((enter_bold_mode != 0) && (strlen(enter_bold_mode) > 0)) { + if ((enter_bold_mode != 0) && (std::strlen(enter_bold_mode) > 0)) { if (bg_set && !last_bg_set) { // Background color changed and is set, so we enter bold mode to make reading easier. // This means bold mode is _always_ on when the background color is set. @@ -295,7 +295,7 @@ void outputter_t::set_color(rgb_color_t c, rgb_color_t c2) { } // Lastly, we set bold, underline, italics, dim, and reverse modes correctly. - if (is_bold && !was_bold && enter_bold_mode && strlen(enter_bold_mode) > 0 && !bg_set) { + if (is_bold && !was_bold && enter_bold_mode && std::strlen(enter_bold_mode) > 0 && !bg_set) { // The unconst cast is for NetBSD's benefit. DO NOT REMOVE! writembs_nofail(*this, tparm((char *)enter_bold_mode)); was_bold = is_bold; @@ -310,27 +310,27 @@ void outputter_t::set_color(rgb_color_t c, rgb_color_t c2) { } was_underline = is_underline; - if (was_italics && !is_italics && enter_italics_mode && strlen(enter_italics_mode) > 0) { + if (was_italics && !is_italics && enter_italics_mode && std::strlen(enter_italics_mode) > 0) { writembs_nofail(*this, exit_italics_mode); was_italics = is_italics; } - if (!was_italics && is_italics && enter_italics_mode && strlen(enter_italics_mode) > 0) { + if (!was_italics && is_italics && enter_italics_mode && std::strlen(enter_italics_mode) > 0) { writembs_nofail(*this, enter_italics_mode); was_italics = is_italics; } - if (is_dim && !was_dim && enter_dim_mode && strlen(enter_dim_mode) > 0) { + if (is_dim && !was_dim && enter_dim_mode && std::strlen(enter_dim_mode) > 0) { writembs_nofail(*this, enter_dim_mode); was_dim = is_dim; } if (is_reverse && !was_reverse) { // Some terms do not have a reverse mode set, so standout mode is a fallback. - if (enter_reverse_mode && strlen(enter_reverse_mode) > 0) { + if (enter_reverse_mode && std::strlen(enter_reverse_mode) > 0) { writembs_nofail(*this, enter_reverse_mode); was_reverse = is_reverse; - } else if (enter_standout_mode && strlen(enter_standout_mode) > 0) { + } else if (enter_standout_mode && std::strlen(enter_standout_mode) > 0) { writembs_nofail(*this, enter_standout_mode); was_reverse = is_reverse; } diff --git a/src/output.h b/src/output.h index b0548aeb1..dee1ad982 100644 --- a/src/output.h +++ b/src/output.h @@ -69,7 +69,7 @@ class outputter_t { } /// Write a narrow NUL-terminated string. - void writestr(const char *str) { writestr(str, strlen(str)); } + void writestr(const char *str) { writestr(str, std::strlen(str)); } /// Write a narrow character. void push_back(char c) { diff --git a/src/path.cpp b/src/path.cpp index 2523e4ef9..93d941204 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -4,7 +4,7 @@ #include "config.h" // IWYU pragma: keep #include -#include +#include #include #include #include @@ -272,7 +272,7 @@ static void maybe_issue_path_warning(const wcstring &which_dir, const wcstring & const wchar_t *env_var = using_xdg ? xdg_var.c_str() : L"HOME"; debug(0, _(L"Unable to locate %ls directory derived from $%ls: '%ls'."), which_dir.c_str(), env_var, path.c_str()); - debug(0, _(L"The error was '%s'."), strerror(saved_errno)); + debug(0, _(L"The error was '%s'."), std::strerror(saved_errno)); debug(0, _(L"Please set $%ls to a directory where you have write access."), env_var); } ignore_result(write(STDERR_FILENO, "\n", 1)); diff --git a/src/postfork.cpp b/src/postfork.cpp index ca3607628..f4c14b6b6 100644 --- a/src/postfork.cpp +++ b/src/postfork.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #if FISH_USE_POSIX_SPAWN @@ -308,11 +308,11 @@ void safe_report_exec_error(int err, const char *actual_cmd, const char *const * size_t sz = 0; const char *const *p; for (p = argv; *p; p++) { - sz += strlen(*p) + 1; + sz += std::strlen(*p) + 1; } for (p = envv; *p; p++) { - sz += strlen(*p) + 1; + sz += std::strlen(*p) + 1; } format_size_safe(sz1, sz); diff --git a/src/print_help.cpp b/src/print_help.cpp index c19a51dfc..db8ed074b 100644 --- a/src/print_help.cpp +++ b/src/print_help.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include "common.h" #include "print_help.h" @@ -17,6 +17,6 @@ void print_help(const char *c, int fd) { int printed = snprintf(cmd, CMD_LEN, "fish -c '__fish_print_help %s >&%d'", c, fd); if (printed < CMD_LEN && system(cmd) == -1) { - write_loop(2, HELP_ERR, strlen(HELP_ERR)); + write_loop(2, HELP_ERR, std::strlen(HELP_ERR)); } } diff --git a/src/reader.cpp b/src/reader.cpp index 505dae066..0b8861633 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #ifdef HAVE_SYS_SELECT_H #include #endif @@ -969,13 +969,13 @@ void reader_init() { tcgetattr(STDIN_FILENO, &terminal_mode_on_startup); // Set the mode used for program execution, initialized to the current mode. - memcpy(&tty_modes_for_external_cmds, &terminal_mode_on_startup, + std::memcpy(&tty_modes_for_external_cmds, &terminal_mode_on_startup, sizeof tty_modes_for_external_cmds); tty_modes_for_external_cmds.c_iflag &= ~IXON; // disable flow control tty_modes_for_external_cmds.c_iflag &= ~IXOFF; // disable flow control // Set the mode used for the terminal, initialized to the current mode. - memcpy(&shell_modes, &terminal_mode_on_startup, sizeof shell_modes); + std::memcpy(&shell_modes, &terminal_mode_on_startup, sizeof shell_modes); shell_modes.c_iflag &= ~ICRNL; // disable mapping CR (\cM) to NL (\cJ) shell_modes.c_iflag &= ~INLCR; // disable mapping NL (\cJ) to CR (\cM) @@ -2447,7 +2447,7 @@ maybe_t reader_data_t::readline(int nchars) { (size_t)READAHEAD_MAX) : READAHEAD_MAX; - memset(arr, 0, sizeof(arr)); + std::memset(arr, 0, sizeof(arr)); arr[0] = c; for (i = 1; i < limit; ++i) { diff --git a/src/screen.cpp b/src/screen.cpp index bc3161a40..30efe600f 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -460,7 +460,7 @@ static void s_move(screen_t *s, int new_x, int new_y) { y_steps = new_y - s->actual.cursor.y; - if (y_steps > 0 && (strcmp(cursor_down, "\n") == 0)) { + if (y_steps > 0 && (std::strcmp(cursor_down, "\n") == 0)) { // This is very strange - it seems some (all?) consoles use a simple newline as the cursor // down escape. This will of course move the cursor to the beginning of the line as well as // moving it down one step. The cursor_up does not have this behaviour... @@ -496,7 +496,7 @@ static void s_move(screen_t *s, int new_x, int new_y) { // Use the bulk ('multi') output for cursor movement if it is supported and it would be shorter // Note that this is required to avoid some visual glitches in iTerm (issue #1448). bool use_multi = - multi_str != NULL && multi_str[0] != '\0' && abs(x_steps) * strlen(str) > strlen(multi_str); + multi_str != NULL && multi_str[0] != '\0' && abs(x_steps) * std::strlen(str) > std::strlen(multi_str); if (use_multi && cur_term) { char *multi_param = tparm((char *)multi_str, abs(x_steps)); writembs(outp, multi_param); diff --git a/src/tinyexpr.cpp b/src/tinyexpr.cpp index 842219dea..e4ae70a34 100644 --- a/src/tinyexpr.cpp +++ b/src/tinyexpr.cpp @@ -26,7 +26,7 @@ #include "tinyexpr.h" #include #include -#include +#include #include #include @@ -96,9 +96,9 @@ static te_expr *new_expr(const int type, const te_expr *parameters[]) { te_expr *ret = (te_expr *)malloc(size); // This sets float to 0, which depends on the implementation. // We rely on IEEE-754 floats anyway, so it's okay. - memset(ret, 0, size); + std::memset(ret, 0, size); if (arity && parameters) { - memcpy(ret->parameters, parameters, psize); + std::memcpy(ret->parameters, parameters, psize); } ret->type = type; return ret; @@ -192,10 +192,10 @@ static const te_builtin *find_builtin(const char *name, int len) { const te_builtin *found = std::lower_bound(std::begin(functions), end, name, [len](const te_builtin &lhs, const char *rhs) { // The length is important because that's where the parens start - return strncmp(lhs.name, rhs, len) < 0; + return std::strncmp(lhs.name, rhs, len) < 0; }); // We need to compare again because we might have gotten the first "larger" element. - if (found != end && strncmp(found->name, name, len) == 0) return found; + if (found != end && std::strncmp(found->name, name, len) == 0) return found; return NULL; } diff --git a/src/wgetopt.cpp b/src/wgetopt.cpp index 2355db669..c39ccd730 100644 --- a/src/wgetopt.cpp +++ b/src/wgetopt.cpp @@ -40,7 +40,7 @@ #include #include -#include +#include // This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves // differently for the user, since it allows the user to intersperse the options with the other diff --git a/src/wutil.cpp b/src/wutil.cpp index b9aefb108..2004dcf42 100644 --- a/src/wutil.cpp +++ b/src/wutil.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #if defined(__linux__) #include @@ -130,7 +130,7 @@ const wcstring wgetcwd() { return str2wcstring(res); } - debug(0, _(L"getcwd() failed with errno %d/%s"), errno, strerror(errno)); + debug(0, _(L"getcwd() failed with errno %d/%s"), errno, std::strerror(errno)); return wcstring(); } @@ -262,7 +262,7 @@ void wperror(const wchar_t *s) { if (s[0] != L'\0') { std::fwprintf(stderr, L"%ls: ", s); } - std::fwprintf(stderr, L"%s\n", strerror(e)); + std::fwprintf(stderr, L"%s\n", std::strerror(e)); } int make_fd_nonblocking(int fd) { @@ -318,7 +318,7 @@ int fd_check_is_remote(int fd) { } static inline void safe_append(char *buffer, const char *s, size_t buffsize) { - strncat(buffer, s, buffsize - strlen(buffer) - 1); + std::strncat(buffer, s, buffsize - std::strlen(buffer) - 1); } // In general, strerror is not async-safe, and therefore we cannot use it directly. So instead we @@ -328,7 +328,7 @@ const char *safe_strerror(int err) { #if defined(__UCLIBC__) // uClibc does not have sys_errlist, however, its strerror is believed to be async-safe. // See issue #808. - return strerror(err); + return std::strerror(err); #elif defined(HAVE__SYS__ERRS) || defined(HAVE_SYS_ERRLIST) #ifdef HAVE_SYS_ERRLIST if (err >= 0 && err < sys_nerr && sys_errlist[err] != NULL) { @@ -373,7 +373,7 @@ void safe_perror(const char *message) { safe_append(buff, safe_strerror(err), sizeof buff); safe_append(buff, "\n", sizeof buff); - ignore_result(write(STDERR_FILENO, buff, strlen(buff))); + ignore_result(write(STDERR_FILENO, buff, std::strlen(buff))); errno = err; } diff --git a/src/wutil.h b/src/wutil.h index 661e82d05..80eaf8005 100644 --- a/src/wutil.h +++ b/src/wutil.h @@ -59,7 +59,7 @@ void wperror(const wchar_t *s); /// Async-safe version of perror(). void safe_perror(const char *message); -/// Async-safe version of strerror(). +/// Async-safe version of std::strerror(). const char *safe_strerror(int err); /// Wide character version of getcwd(). From b7c069a765e3f142fba8dc920863b08f3593e9b9 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Tue, 12 Mar 2019 15:09:07 -0700 Subject: [PATCH 0046/1732] Remove two duplicated #includes --- src/common.cpp | 1 - src/history.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/common.cpp b/src/common.cpp index cb158912f..063d45d21 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -33,7 +33,6 @@ #ifdef __linux__ // Includes for WSL detection -#include #include #endif diff --git a/src/history.cpp b/src/history.cpp index d0deb6eb5..8ad1bfeb9 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include From 2e4948e1f423d3cdac84425b3dda5de74775c1c5 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Tue, 12 Mar 2019 15:27:13 -0700 Subject: [PATCH 0047/1732] Fix `switch` nesting in handler_matches I guess this worked, but whoops. --- src/event.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/event.cpp b/src/event.cpp index d2ae1959a..9cab7d427 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -120,8 +120,8 @@ static bool handler_matches(const event_handler_t &classv, const event_t &instan case event_type_t::generic: { return classv.desc.str_param1 == instance.desc.str_param1; } - case event_type_t::any: { - default: + case event_type_t::any: + default: { DIE("unexpected classv.type"); return false; } From b318ab17d2b3d759d8d844e4e19e7e047f0f7a19 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 12 Mar 2019 23:29:03 +0100 Subject: [PATCH 0048/1732] wcwidth: Classify some Hangul Jamo as combiners Hangul uses three codepoints to combine to one glyph. The first has a width of 2 (like the final glyph), but the second and third were assigned a width of 1, which seems to match EastAsianWidth.txt: > 1160..11FF;N # Lo [160] HANGUL JUNGSEONG FILLER..HANGUL JONGSEONG SSANGNIEUN Instead, we override that and treat the middle and end codepoint as combiners, always, because there's no way to figure out what the terminal will think and that's the way it's supposed to work. If they stand by themselves or in another combination, they'll indeed show up with a width of 1 so we'll get it wrong, but that's less likely and not expressible with wcwidth(). Fixes #5729. --- src/fallback.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fallback.cpp b/src/fallback.cpp index b944c0406..2b8dacb62 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -287,6 +287,9 @@ int fish_wcwidth(wchar_t wc) { if (wc == variation_selector_16) return 1; else if (wc == variation_selector_15) return 0; + // Korean Hangul Jamo median vowels and final consonants. + // These are effectively combiners, so we handle them like combiners. + if (wc >= L'\u1160' && wc <= L'\u11FF') return wcwidth(wc); int width = widechar_wcwidth(wc); switch (width) { case widechar_nonprint: From f92c2921d252af8c787915550505f23579d5d41a Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Tue, 12 Mar 2019 22:38:42 -0700 Subject: [PATCH 0049/1732] Remove mini() and maxi() C++11 provides std::min/std::max which we're using all over, obviating the need for our own templates for this. util.h now only provides two things: get_time and wcsfilecmp. This commit removes everything that includes it which doesn't use either; most because they no longer need mini or maxi from it but some others were #including it unnecessarily. --- src/builtin_commandline.cpp | 3 +-- src/builtin_ulimit.cpp | 3 +-- src/env_universal_common.cpp | 4 ++-- src/fallback.cpp | 1 - src/input_common.cpp | 5 ++--- src/pager.cpp | 7 +++---- src/parse_util.cpp | 1 - src/proc.cpp | 1 - src/reader.cpp | 21 ++++++++++++--------- src/screen.cpp | 13 +++++++------ src/util.h | 12 ------------ 11 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/builtin_commandline.cpp b/src/builtin_commandline.cpp index de6cd8126..5f7c27a16 100644 --- a/src/builtin_commandline.cpp +++ b/src/builtin_commandline.cpp @@ -15,7 +15,6 @@ #include "proc.h" #include "reader.h" #include "tokenizer.h" -#include "util.h" #include "wgetopt.h" #include "wutil.h" // IWYU pragma: keep @@ -398,7 +397,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) } current_buffer = reader_get_buffer(); - new_pos = maxi(0L, mini(new_pos, (long)wcslen(current_buffer))); + new_pos = std::max(0L, std::min(new_pos, (long)std::wcslen(current_buffer))); reader_set_buffer(current_buffer, (size_t)new_pos); } else { streams.out.append_format(L"%lu\n", (unsigned long)reader_get_cursor_pos()); diff --git a/src/builtin_ulimit.cpp b/src/builtin_ulimit.cpp index f7b9cf4c8..553c35514 100644 --- a/src/builtin_ulimit.cpp +++ b/src/builtin_ulimit.cpp @@ -9,7 +9,6 @@ #include "common.h" #include "fallback.h" // IWYU pragma: keep #include "io.h" -#include "util.h" #include "wgetopt.h" #include "wutil.h" // IWYU pragma: keep @@ -81,7 +80,7 @@ static void print_all(int hard, io_streams_t &streams) { int w = 0; for (i = 0; resource_arr[i].desc; i++) { - w = maxi(w, fish_wcswidth(resource_arr[i].desc)); + w = std::max(w, fish_wcswidth(resource_arr[i].desc)); } for (i = 0; resource_arr[i].desc; i++) { diff --git a/src/env_universal_common.cpp b/src/env_universal_common.cpp index cde707860..7a033f03c 100644 --- a/src/env_universal_common.cpp +++ b/src/env_universal_common.cpp @@ -1365,7 +1365,7 @@ class universal_notifier_named_pipe_t : public universal_notifier_t { // Now return the smaller of the two values. If we get ULONG_MAX, it means there's no more // need to poll; in that case return 0. - unsigned long result = mini(readback_delay, polling_delay); + unsigned long result = std::min(readback_delay, polling_delay); if (result == ULONG_MAX) { result = 0; } @@ -1378,7 +1378,7 @@ class universal_notifier_named_pipe_t : public universal_notifier_t { // Read back what we wrote. We do nothing with the value. while (this->readback_amount > 0) { char buff[64]; - size_t amt_to_read = mini(this->readback_amount, sizeof buff); + size_t amt_to_read = std::min(this->readback_amount, sizeof(buff)); ignore_result(read(this->pipe_fd, buff, amt_to_read)); this->readback_amount -= amt_to_read; } diff --git a/src/fallback.cpp b/src/fallback.cpp index 2b8dacb62..9f5542ba5 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -41,7 +41,6 @@ #include "common.h" // IWYU pragma: keep #include "fallback.h" // IWYU pragma: keep -#include "util.h" // IWYU pragma: keep #if defined(TPARM_SOLARIS_KLUDGE) #undef tparm diff --git a/src/input_common.cpp b/src/input_common.cpp index 19e4356a3..765a9d667 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -25,7 +25,6 @@ #include "fallback.h" // IWYU pragma: keep #include "input_common.h" #include "iothread.h" -#include "util.h" #include "wutil.h" /// Time in milliseconds to wait for another byte to be available for reading @@ -82,7 +81,7 @@ static wint_t readb() { FD_SET(0, &fdset); if (ioport > 0) { FD_SET(ioport, &fdset); - fd_max = maxi(fd_max, ioport); + fd_max = std::max(fd_max, ioport); } // Get our uvar notifier. @@ -92,7 +91,7 @@ static wint_t readb() { int notifier_fd = notifier.notification_fd(); if (notifier_fd > 0) { FD_SET(notifier_fd, &fdset); - fd_max = maxi(fd_max, notifier_fd); + fd_max = std::max(fd_max, notifier_fd); } // Get its suggested delay (possibly none). diff --git a/src/pager.cpp b/src/pager.cpp index 03273037d..8f6e864ca 100644 --- a/src/pager.cpp +++ b/src/pager.cpp @@ -18,7 +18,6 @@ #include "pager.h" #include "reader.h" #include "screen.h" -#include "util.h" #include "wutil.h" // IWYU pragma: keep typedef pager_t::comp_t comp_t; @@ -422,7 +421,7 @@ bool pager_t::completion_try_print(size_t cols, const wcstring &prefix, const co this->available_term_height - 1 - (search_field_shown ? 1 : 0); // we always subtract 1 to make room for a comment row if (!this->fully_disclosed) { - term_height = mini(term_height, (size_t)PAGER_UNDISCLOSED_MAX_ROWS); + term_height = std::min(term_height, (size_t)PAGER_UNDISCLOSED_MAX_ROWS); } size_t row_count = divide_round_up(lst.size(), cols); @@ -478,7 +477,7 @@ bool pager_t::completion_try_print(size_t cols, const wcstring &prefix, const co // suggested_start_row. assert(row_count > term_height); size_t last_starting_row = row_count - term_height; - start_row = mini(suggested_start_row, last_starting_row); + start_row = std::min(suggested_start_row, last_starting_row); stop_row = start_row + term_height; assert(start_row <= last_starting_row); } @@ -660,7 +659,7 @@ bool pager_t::select_next_completion_in_direction(selection_direction_t directio // Cardinal directions. We have a completion index; we wish to compute its row and column. size_t current_row = this->get_selected_row(rendering); size_t current_col = this->get_selected_column(rendering); - size_t page_height = maxi(rendering.term_height - 1, (size_t)1); + size_t page_height = std::max(rendering.term_height - 1, 1UL); switch (direction) { case direction_page_north: { diff --git a/src/parse_util.cpp b/src/parse_util.cpp index bcca52cb4..5d8fe3cc8 100644 --- a/src/parse_util.cpp +++ b/src/parse_util.cpp @@ -22,7 +22,6 @@ #include "parser.h" #include "tnode.h" #include "tokenizer.h" -#include "util.h" #include "wildcard.h" #include "wutil.h" // IWYU pragma: keep diff --git a/src/proc.cpp b/src/proc.cpp index e2ededc77..7c5016a14 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -46,7 +46,6 @@ #include "reader.h" #include "sanity.h" #include "signal.h" -#include "util.h" #include "wutil.h" // IWYU pragma: keep /// Statuses of last job's processes to exit - ensure we start off with one entry of 0. diff --git a/src/reader.cpp b/src/reader.cpp index 0b8861633..8d2b0ec35 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -73,7 +73,6 @@ #include "signal.h" #include "tnode.h" #include "tokenizer.h" -#include "util.h" #include "wutil.h" // IWYU pragma: keep // Name of the variable that tells how long it took, in milliseconds, for the previous @@ -137,8 +136,9 @@ static inline unsigned read_generation_count() { void editable_line_t::insert_string(const wcstring &str, size_t start, size_t len) { // Clamp the range to something valid. size_t string_length = str.size(); - start = mini(start, string_length); //!OCLINT(parameter reassignment) - len = mini(len, string_length - start); //!OCLINT(parameter reassignment) + + start = std::min(start, string_length); //!OCLINT(parameter reassignment) + len = std::min(len, string_length - start); //!OCLINT(parameter reassignment) this->text.insert(this->position, str, start, len); this->position += len; } @@ -631,8 +631,8 @@ void reader_data_t::repaint() { // term size, minus the number of lines consumed by our string. (Note this doesn't yet consider // wrapping). int full_line_count = 1 + std::count(full_line.begin(), full_line.end(), '\n'); - pager.set_term_size(maxi(1, common_get_width()), - maxi(1, common_get_height() - full_line_count)); + pager.set_term_size(std::max(1, common_get_width()), + std::max(1, common_get_height() - full_line_count)); pager.update_rendering(¤t_page_rendering); bool focused_on_pager = active_edit_line() == &pager.search_field_line; @@ -665,7 +665,7 @@ void reader_data_t::kill(editable_line_t *el, size_t begin_idx, size_t length, i if (el->position > begin_idx) { // Move the buff position back by the number of characters we deleted, but don't go past // buff_pos. - size_t backtrack = mini(el->position - begin_idx, length); + size_t backtrack = std::min(el->position - begin_idx, length); update_buff_pos(el, el->position - backtrack); } @@ -816,10 +816,12 @@ bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t curso bool reader_data_t::expand_abbreviation_as_necessary(size_t cursor_backtrack) { bool result = false; editable_line_t *el = active_edit_line(); + if (expand_abbreviations && el == &command_line) { // Try expanding abbreviations. wcstring new_cmdline; - size_t cursor_pos = el->position - mini(el->position, cursor_backtrack); + size_t cursor_pos = el->position - std::min(el->position, cursor_backtrack); + if (reader_expand_abbreviation_in_command(el->text, cursor_pos, vars(), &new_cmdline)) { // We expanded an abbreviation! The cursor moves by the difference in the command line // lengths. @@ -1585,7 +1587,8 @@ bool reader_data_t::handle_completions(const std::vector &comp, first = false; } else { // Determine the shared prefix length. - size_t idx, max = mini(common_prefix.size(), el.completion.size()); + size_t idx, max = std::min(common_prefix.size(), el.completion.size()); + for (idx = 0; idx < max; idx++) { wchar_t ac = common_prefix.at(idx), bc = el.completion.at(idx); bool matches = (ac == bc); @@ -2689,7 +2692,7 @@ maybe_t reader_data_t::readline(int nchars) { // If we landed on a newline, don't delete it. if (*begin == L'\n') begin++; assert(end >= begin); - size_t len = maxi(end - begin, 1); + size_t len = std::max(end - begin, 1); begin = end - len; kill(el, begin - buff, len, KILL_PREPEND, last_char != R_BACKWARD_KILL_LINE); break; diff --git a/src/screen.cpp b/src/screen.cpp index 30efe600f..ae11033ab 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -39,7 +39,6 @@ #include "output.h" #include "pager.h" #include "screen.h" -#include "util.h" /// The number of characters to indent new blocks. #define INDENT_STEP 4u @@ -86,7 +85,7 @@ static size_t next_tab_stop(size_t current_line_width) { } /// Like fish_wcwidth, but returns 0 for control characters instead of -1. -static int fish_wcwidth_min_0(wchar_t widechar) { return maxi(0, fish_wcwidth(widechar)); } +static int fish_wcwidth_min_0(wchar_t widechar) { return std::max(0, fish_wcwidth(widechar)); } /// Whether we permit soft wrapping. If so, in some cases we don't explicitly move to the second /// physical line on a wrapped logical line; instead we just output it. @@ -225,7 +224,8 @@ static bool is_visual_escape_seq(const wchar_t *code, size_t *resulting_length) if (!esc2[p]) continue; // Test both padded and unpadded version, just to be safe. Most versions of tparm don't // actually seem to do anything these days. - size_t esc_seq_len = maxi(try_sequence(tparm((char *)esc2[p]), code), try_sequence(esc2[p], code)); + size_t esc_seq_len = + std::max(try_sequence(tparm((char *)esc2[p]), code), try_sequence(esc2[p], code)); if (esc_seq_len) { *resulting_length = esc_seq_len; return true; @@ -615,7 +615,7 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring // Determine how many lines have stuff on them; we need to clear lines with stuff that we don't // want. - const size_t lines_with_stuff = maxi(actual_lines_before_reset, scr->actual.line_count()); + const size_t lines_with_stuff = std::max(actual_lines_before_reset, scr->actual.line_count()); if (left_prompt != scr->actual_left_prompt) { s_move(scr, 0, 0); @@ -657,7 +657,7 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring } } if (next_line_will_change) { - skip_remaining = mini(skip_remaining, (size_t)(scr->actual_width - 2)); + skip_remaining = std::min(skip_remaining, (size_t)(scr->actual_width - 2)); } } } @@ -1073,7 +1073,8 @@ void s_reset(screen_t *s, screen_reset_mode_t mode) { // underneath the cursor when resizing a window wider such that it reduces our desired line // count. if (!abandon_line) { - s->actual_lines_before_reset = maxi(s->actual_lines_before_reset, s->actual.line_count()); + s->actual_lines_before_reset = + std::max(s->actual_lines_before_reset, s->actual.line_count()); } if (repaint_prompt && !abandon_line) { diff --git a/src/util.h b/src/util.h index 9d2e4bbbb..f9f121849 100644 --- a/src/util.h +++ b/src/util.h @@ -2,18 +2,6 @@ #ifndef FISH_UTIL_H #define FISH_UTIL_H -/// Returns the larger of two ints. -template -inline T maxi(T a, T b) { - return a > b ? a : b; -} - -/// Returns the smaller of two ints. -template -inline T mini(T a, T b) { - return a < b ? a : b; -} - /// Compares two wide character strings with an (arguably) intuitive ordering. This function tries /// to order strings in a way which is intuitive to humans with regards to sorting strings /// containing numbers. From 51cc03ca75cb89335dade89cd0b7013dedd144fd Mon Sep 17 00:00:00 2001 From: hyperfekt Date: Wed, 13 Mar 2019 10:00:09 +0100 Subject: [PATCH 0050/1732] reflect #1912 in documentation --- sphinx_doc_src/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index 3c43779e1..20554418d 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -1014,7 +1014,7 @@ Universal variables are variables that are shared between all the users' fish se To see universal variables in action, start two fish sessions side by side, and issue the following command in one of them ``set fish_color_cwd blue``. Since ``fish_color_cwd`` is a universal variable, the color of the current working directory listing in the prompt will instantly change to blue on both terminals. -`Universal variables <#variables-universal>`_ are stored in the file ``.config/fish/fishd.MACHINE_ID``, where MACHINE_ID is typically your MAC address. Do not edit this file directly, as your edits may be overwritten. Edit them through fish scripts or by using fish interactively instead. +`Universal variables <#variables-universal>`_ are stored in the file ``.config/fish/fish_variables``. Do not edit this file directly, as your edits may be overwritten. Edit the variables through fish scripts or by using fish interactively instead. Do not append to universal variables in `config.fish <#initialization>`_, because these variables will then get longer with each new shell instance. Instead, simply set them once at the command line. From 5a9d1533639e4a95ab63a010c9588e65905d6864 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 13 Mar 2019 10:28:25 +0100 Subject: [PATCH 0051/1732] input: Use range-for Also adds a couple of consts. --- src/input.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index dffa07f15..66205a628 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -227,8 +227,7 @@ void input_mapping_add(const wchar_t *sequence, const wchar_t *const *commands, auto& ml = user ? mapping_list : preset_mapping_list; - for (size_t i = 0; i < ml.size(); i++) { - input_mapping_t &m = ml.at(i); + for (input_mapping_t& m : ml) { if (m.seq == sequence && m.mode == mode) { m.commands = commands_vector; m.sets_mode = sets_mode; @@ -744,8 +743,7 @@ bool input_terminfo_get_sequence(const wchar_t *name, wcstring *out_seq) { const char *res = 0; int err = ENOENT; - for (size_t i = 0; i < terminfo_mappings.size(); i++) { - const terminfo_mapping_t &m = terminfo_mappings.at(i); + for (const terminfo_mapping_t &m : terminfo_mappings) { if (!std::wcscmp(name, m.name)) { res = m.seq; err = EILSEQ; @@ -765,9 +763,7 @@ bool input_terminfo_get_sequence(const wchar_t *name, wcstring *out_seq) { bool input_terminfo_get_name(const wcstring &seq, wcstring *out_name) { assert(input_initialized); - for (size_t i = 0; i < terminfo_mappings.size(); i++) { - terminfo_mapping_t &m = terminfo_mappings.at(i); - + for (const terminfo_mapping_t &m : terminfo_mappings) { if (!m.seq) { continue; } @@ -787,9 +783,7 @@ wcstring_list_t input_terminfo_get_names(bool skip_null) { wcstring_list_t result; result.reserve(terminfo_mappings.size()); - for (size_t i = 0; i < terminfo_mappings.size(); i++) { - terminfo_mapping_t &m = terminfo_mappings.at(i); - + for (const terminfo_mapping_t &m : terminfo_mappings) { if (skip_null && !m.seq) { continue; } From ad0c8cfb83739508a9e0650ec490ab133b0fc2a6 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 13 Mar 2019 12:15:45 +0100 Subject: [PATCH 0052/1732] fish_clipboard_paste: Don't add histignore spaces If we're at the beginning of the commandline, we trim leading whitespace so we don't trigger histignore. Since that's the main issue of problems with histignore: Closes #4327. --- share/functions/fish_clipboard_paste.fish | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/share/functions/fish_clipboard_paste.fish b/share/functions/fish_clipboard_paste.fish index e56ff6b16..105ca1226 100644 --- a/share/functions/fish_clipboard_paste.fish +++ b/share/functions/fish_clipboard_paste.fish @@ -28,6 +28,11 @@ function fish_clipboard_paste if __fish_commandline_is_singlequoted set data (string replace -ra "(['\\\])" '\\\\\\\$1' -- $data) end + if not string length -q -- (commandline -c) + # If we're at the beginning of the first line, trim whitespace from the start, + # so we don't trigger ignoring history. + set data (string trim -l -- $data) + end if test -n "$data" commandline -i -- $data end From a5a643f854db2e52fe72c56fbd6a8cc6636e7623 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 13 Mar 2019 12:27:33 +0100 Subject: [PATCH 0053/1732] Bracketed paste: Strip leading spaces if they'd trigger histignore Similar to the last commit, only for the in-terminal-paste stuff. Also cleans up the comments on bracketed paste a bit - nobody has stepped forward to report problems with old emacsen or windows, so there's no need for a TODO comment. See #4327. --- .../functions/__fish_shared_key_bindings.fish | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/share/functions/__fish_shared_key_bindings.fish b/share/functions/__fish_shared_key_bindings.fish index d54887551..ad1d16b9b 100644 --- a/share/functions/__fish_shared_key_bindings.fish +++ b/share/functions/__fish_shared_key_bindings.fish @@ -110,7 +110,6 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod bind --preset $argv \ee edit_command_buffer bind --preset $argv \ev edit_command_buffer - # Tmux' focus events. # Exclude paste mode because that should get _everything_ literally. for mode in (bind --list-modes | string match -v paste) @@ -129,23 +128,17 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod # # We enable it after every command and disable it before (in __fish_config_interactive.fish) # - # Support for this seems to be ubiquitous - emacs enables it unconditionally (!) since 25.1 (though it only supports it since then, - # it seems to be the last term to gain support). - # TODO: Should we disable this in older emacsen? + # Support for this seems to be ubiquitous - emacs enables it unconditionally (!) since 25.1 + # (though it only supports it since then, it seems to be the last term to gain support). # # NOTE: This is more of a "security" measure than a proper feature. # The better way to paste remains the `fish_clipboard_paste` function (bound to \cv by default). # We don't disable highlighting here, so it will be redone after every character (which can be slow), - # and it doesn't handle "paste-stop" sequences in the paste (which the terminal needs to strip, but KDE konsole doesn't). + # and it doesn't handle "paste-stop" sequences in the paste (which the terminal needs to strip). # - # See http://thejh.net/misc/website-terminal-copy-paste. The second case will not be caught in KDE konsole. + # See http://thejh.net/misc/website-terminal-copy-paste. + # Bind the starting sequence in every bind mode, even user-defined ones. - - # We usually just pass the text through as-is to facilitate pasting code, - # but when the current token contains an unbalanced single-quote (`'`), - # we escape all single-quotes and backslashes, effectively turning the paste - # into one literal token, to facilitate pasting non-code (e.g. markdown or git commitishes) - # Exclude paste mode or there'll be an additional binding after switching between emacs and vi for mode in (bind --list-modes | string match -v paste) bind --preset -M $mode -m paste \e\[200~ '__fish_start_bracketed_paste' @@ -155,10 +148,17 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod # In paste-mode, everything self-inserts except for the sequence to get out of it bind --preset -M paste "" self-insert # Without this, a \r will overwrite the other text, rendering it invisible - which makes the exercise kinda pointless. - # TODO: Test this in windows (\r\n line endings) bind --preset -M paste \r "commandline -i \n" + + # We usually just pass the text through as-is to facilitate pasting code, + # but when the current token contains an unbalanced single-quote (`'`), + # we escape all single-quotes and backslashes, effectively turning the paste + # into one literal token, to facilitate pasting non-code (e.g. markdown or git commitishes) bind --preset -M paste "'" "__fish_commandline_insert_escaped \' \$__fish_paste_quoted" bind --preset -M paste \\ "__fish_commandline_insert_escaped \\\ \$__fish_paste_quoted" + # Only insert spaces if we're either quoted or not at the beginning of the commandline + # - this strips leading spaces if they would trigger histignore. + bind --preset -M paste \ 'if set -q __fish_paste_quoted[1]; or string length -q -- (commandline -c); commandline -i " "; end' end function __fish_commandline_insert_escaped --description 'Insert the first arg escaped if a second arg is given' From b792290c51e3736fa8006fd026ad0f3bc912d538 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 13 Mar 2019 12:30:22 +0100 Subject: [PATCH 0054/1732] CHANGELOG pasting leading spaces --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e4244899..07447150b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ ### Interactive improvements - Major improvements in performance and functionality to the 'sorin' sample prompt (#5411). - fish_clipboard_* now supports wayland by means of [wl-clipboard](https://github.com/bugaevc/wl-clipboard). +- Pasting will now strip leading spaces if they would trigger history ignoring (#4327). - mandoc can now be used to format the output from `--help` if nroff is not installed - New color options for the pager have been added (#5524). - The default escape delay (to differentiate between the escape key and an alt-combination) has been reduced to 30ms, down from 300ms for the default mode and 100ms for vi-mode (#3904). From 028112e535f2f3aee8593b71558cf22d93939a61 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 13 Mar 2019 12:32:17 +0100 Subject: [PATCH 0055/1732] CHANGELOG: Add "scripting improvements" paragraph It felt weird to put `math --scale` under "interactive", and it's not a syntax change, new command or particularly notable either. --- CHANGELOG.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07447150b..cbb93d6a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,24 +6,26 @@ ## Notable Fixes and improvements - Add `$pipestatus` support - macOS Mojave: fish.app can actually run (#5727), 10.14.4's Terminal.app no longer causes an error on launch (#5725) -- `string split0` now returns 0 if it split something (#5701). ### Syntax changes and new commands - None yet. +### Scripting improvements +- `string split0` now returns 0 if it split something (#5701). +- mandoc can now be used to format the output from `--help` if nroff is not installed. +- In the interest of consistency, `builtin -q` and `command -q` can now be used to query if a builtin or command exists (#5631). +- `math` now accepts `--scale=max` for the maximum scale (#5579). +- `complete --do-complete` now also does fuzzy matches (#5467). + ### Interactive improvements - Major improvements in performance and functionality to the 'sorin' sample prompt (#5411). - fish_clipboard_* now supports wayland by means of [wl-clipboard](https://github.com/bugaevc/wl-clipboard). - Pasting will now strip leading spaces if they would trigger history ignoring (#4327). -- mandoc can now be used to format the output from `--help` if nroff is not installed - New color options for the pager have been added (#5524). - The default escape delay (to differentiate between the escape key and an alt-combination) has been reduced to 30ms, down from 300ms for the default mode and 100ms for vi-mode (#3904). -- In the interest of consistency, `builtin -q` and `command -q` can now be used to query if a builtin or command exists (#5631). - The `path_helper` on macOS now only runs in login shells, matching the bash implementation. -- `math` now accepts `--scale=max` for the maximum scale (#5579). - The `forward-bigword` binding now interacts correctly with autosuggestions (#5336) - Fish now tries to guess if the system supports Unicode 9 (and displays emoji as wide), hopefully making setting $fish_emoji_width superfluous in most cases (#5722). -- `complete --do-complete` now also does fuzzy matches (#5467). - Lots of improvements to completions. - Added completions for - `cf` @@ -33,7 +35,7 @@ ### For distributors and developers - The autotools-based build system and legacy Xcode build systems have been removed, leaving only the CMake build system. All distributors and developers must migrate to the CMake build. -- The doxygen-based documenation system has been removed and replaced with one based on sphinx. All distributors and developers must migrate to that. +- The doxygen-based documentation system has been removed and replaced with one based on sphinx. All distributors and developers must migrate to that. --- From 05b9c07816499b7adf063e9ca4dad6d7b480a282 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 13 Mar 2019 12:37:24 +0100 Subject: [PATCH 0056/1732] wcwidth: Return 0 for median/final jamo Fixes #5729. --- src/fallback.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/fallback.cpp b/src/fallback.cpp index 9f5542ba5..722338c04 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -287,8 +287,10 @@ int fish_wcwidth(wchar_t wc) { else if (wc == variation_selector_15) return 0; // Korean Hangul Jamo median vowels and final consonants. - // These are effectively combiners, so we handle them like combiners. - if (wc >= L'\u1160' && wc <= L'\u11FF') return wcwidth(wc); + // These can either appear in combined form, taking 0 width themselves, + // or standalone with a 1 width. Since that's literally not expressible with wcwidth(), + // we take the position that the typical way for them to show up is composed. + if (wc >= L'\u1160' && wc <= L'\u11FF') return 0; int width = widechar_wcwidth(wc); switch (width) { case widechar_nonprint: From b879a2650cf826ca763424376cccfc5af48c0af4 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Wed, 13 Mar 2019 07:43:29 -0700 Subject: [PATCH 0057/1732] Fix 32-bit build Fixes #5740 --- src/pager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pager.cpp b/src/pager.cpp index 8f6e864ca..d8f8da40b 100644 --- a/src/pager.cpp +++ b/src/pager.cpp @@ -659,7 +659,7 @@ bool pager_t::select_next_completion_in_direction(selection_direction_t directio // Cardinal directions. We have a completion index; we wish to compute its row and column. size_t current_row = this->get_selected_row(rendering); size_t current_col = this->get_selected_column(rendering); - size_t page_height = std::max(rendering.term_height - 1, 1UL); + size_t page_height = std::max(rendering.term_height - 1, (size_t)1); switch (direction) { case direction_page_north: { From f0998fed6ab52a6056d2330f2bf16b0a2b17e88f Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Wed, 13 Mar 2019 13:52:11 -0700 Subject: [PATCH 0058/1732] simplify append_yaml_to_buffer --- src/history.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/history.cpp b/src/history.cpp index 8ad1bfeb9..fafcd72ce 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -608,17 +608,13 @@ static void append_yaml_to_buffer(const wcstring &wcmd, time_t timestamp, std::string cmd = wcs2string(wcmd); escape_yaml(&cmd); buffer->append("- cmd: ", cmd.c_str(), "\n"); - - char timestamp_str[96]; - snprintf(timestamp_str, sizeof timestamp_str, "%ld", (long)timestamp); - buffer->append(" when: ", timestamp_str, "\n"); + buffer->append(" when: ", std::to_string(timestamp).c_str(), "\n"); if (!required_paths.empty()) { buffer->append(" paths:\n"); - for (path_list_t::const_iterator iter = required_paths.begin(); - iter != required_paths.end(); ++iter) { - std::string path = wcs2string(*iter); + for (auto const &wpath : required_paths) { + std::string path = wcs2string(wpath); escape_yaml(&path); buffer->append(" - ", path.c_str(), "\n"); } From 6fc542dfca148e4a7578e74a581a445b62ec8be3 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Wed, 13 Mar 2019 14:05:23 -0700 Subject: [PATCH 0059/1732] Revert "simplify append_yaml_to_buffer" This reverts commit f0998fed6ab52a6056d2330f2bf16b0a2b17e88f. --- src/history.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/history.cpp b/src/history.cpp index fafcd72ce..8ad1bfeb9 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -608,13 +608,17 @@ static void append_yaml_to_buffer(const wcstring &wcmd, time_t timestamp, std::string cmd = wcs2string(wcmd); escape_yaml(&cmd); buffer->append("- cmd: ", cmd.c_str(), "\n"); - buffer->append(" when: ", std::to_string(timestamp).c_str(), "\n"); + + char timestamp_str[96]; + snprintf(timestamp_str, sizeof timestamp_str, "%ld", (long)timestamp); + buffer->append(" when: ", timestamp_str, "\n"); if (!required_paths.empty()) { buffer->append(" paths:\n"); - for (auto const &wpath : required_paths) { - std::string path = wcs2string(wpath); + for (path_list_t::const_iterator iter = required_paths.begin(); + iter != required_paths.end(); ++iter) { + std::string path = wcs2string(*iter); escape_yaml(&path); buffer->append(" - ", path.c_str(), "\n"); } From f798a02a2a5e24ae3f367a4efb112cee4d1c8e6e Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 10:38:59 +0100 Subject: [PATCH 0060/1732] Remove unused variable --- src/expand.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/expand.cpp b/src/expand.cpp index 42c44d8fa..2d517bf3c 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -181,8 +181,7 @@ wcstring expand_escape_variable(const env_var_t &var) { /// Parse an array slicing specification Returns 0 on success. If a parse error occurs, returns the /// index of the bad token. Note that 0 can never be a bad index because the string always starts /// with [. -static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector &idx, - std::vector &source_positions, size_t array_size) { +static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector &idx, size_t array_size) { const long size = (long)array_size; size_t pos = 1; // skip past the opening square brace @@ -255,7 +254,6 @@ static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector *out, siz size_t var_name_and_slice_stop = var_name_stop; bool all_values = true; const size_t slice_start = var_name_stop; - // List of indexes, and parallel array of source positions of each index in the variable list. std::vector var_idx_list; - std::vector var_pos_list; if (slice_start < insize && instr.at(slice_start) == L'[') { all_values = false; const wchar_t *in = instr.c_str(); @@ -380,8 +375,7 @@ static bool expand_variables(wcstring instr, std::vector *out, siz } else if (history) { effective_val_count = history->size(); } - size_t bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_list, var_pos_list, - effective_val_count); + size_t bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_list, effective_val_count); if (bad_pos != 0) { if (in[slice_start + bad_pos] == L'0') { append_syntax_error(errors, slice_start + bad_pos, @@ -657,13 +651,12 @@ static bool expand_cmdsubst(const wcstring &input, std::vector *ou tail_begin = paren_end + 1; if (*tail_begin == L'[') { std::vector slice_idx; - std::vector slice_source_positions; const wchar_t *const slice_begin = tail_begin; wchar_t *slice_end; size_t bad_pos; bad_pos = - parse_slice(slice_begin, &slice_end, slice_idx, slice_source_positions, sub_res.size()); + parse_slice(slice_begin, &slice_end, slice_idx, sub_res.size()); if (bad_pos != 0) { append_syntax_error(errors, slice_begin - in + bad_pos, L"Invalid index value"); return false; From 29556efebd76abcf37c92724864db96341f989b8 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 12:22:17 +0100 Subject: [PATCH 0061/1732] Drop rc.d completions This was an arch utility that it used shortly before introducing systemd. It's been dropped upstream for years. --- share/completions/rc.d.fish | 7 ------- share/functions/__fish_print_arch_daemons.fish | 4 ---- 2 files changed, 11 deletions(-) delete mode 100644 share/completions/rc.d.fish delete mode 100644 share/functions/__fish_print_arch_daemons.fish diff --git a/share/completions/rc.d.fish b/share/completions/rc.d.fish deleted file mode 100644 index 2a34f0f5c..000000000 --- a/share/completions/rc.d.fish +++ /dev/null @@ -1,7 +0,0 @@ - -complete -c rc.d -xa 'list start stop restart help' -n 'not __fish_seen_subcommand_from list start stop restart' -complete -c rc.d -s s -l started -n '__fish_seen_subcommand_from list start stop restart' -d 'Filter started daemons' -complete -c rc.d -s S -l stopped -n '__fish_seen_subcommand_from list start stop restart' -d 'Filter stopped daemons' -complete -c rc.d -s a -l auto -n '__fish_seen_subcommand_from list start stop restart' -d 'Filter auto started daemons' -complete -c rc.d -s A -l noauto -n '__fish_seen_subcommand_from list start stop restart' -d 'Filter manually started daemons' -complete -c rc.d -n '__fish_seen_subcommand_from list start stop restart' -xa '( __fish_print_arch_daemons )' diff --git a/share/functions/__fish_print_arch_daemons.fish b/share/functions/__fish_print_arch_daemons.fish deleted file mode 100644 index 3a683c149..000000000 --- a/share/functions/__fish_print_arch_daemons.fish +++ /dev/null @@ -1,4 +0,0 @@ -function __fish_print_arch_daemons --description 'Print arch daemons' - find /etc/rc.d/ -executable -type f -printf '%f\n' - -end From 7784a5f23c3a355445e76fce671e53c16e0ea5ed Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 12:39:47 +0100 Subject: [PATCH 0062/1732] __fish_describe_command: Remove awk This is really the only important place we're using it. See #5553. --- share/functions/__fish_describe_command.fish | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/share/functions/__fish_describe_command.fish b/share/functions/__fish_describe_command.fish index 7fb334d78..e11d49b0c 100644 --- a/share/functions/__fish_describe_command.fish +++ b/share/functions/__fish_describe_command.fish @@ -3,20 +3,8 @@ # function __fish_describe_command -d "Command used to find descriptions for commands" - # We're going to try to build a regex out of $argv inside awk. - # Make sure $argv has no special characters. - # TODO: stop interpolating argv into regex, and remove this hack. - string match --quiet --regex '^[a-zA-Z0-9_ ]+$' -- "$argv" - or return - type -q apropos; or return - apropos $argv 2>/dev/null | awk -v FS=" +- +" '{ - split($1, names, ", "); - for (name in names) - if (names[name] ~ /^'"$argv"'.* *\([18]\)/ ) { - sub( "( |\t)*\\\([18]\\\)", "", names[name] ); - sub( " \\\[.*\\\]", "", names[name] ); - print names[name] "\t" $2; - } - }' + command -sq apropos; or return + # Some systems could use -s 1,8 here, but FreeBSD doesn't have that. + apropos $argv 2>/dev/null | string replace -rf '^(\S+) \(\S+\)\s+- (.*)' '$1\t$2' \ + | string match (string replace -a '*' '\*' -- "$argv")"*" end - From 5859d205d814736d538f7cd1db2d610cb2e09a33 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 12:41:05 +0100 Subject: [PATCH 0063/1732] completions/apt-file: Remove `ls` call --- share/completions/apt-file.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/completions/apt-file.fish b/share/completions/apt-file.fish index 2a22b8000..20129557c 100644 --- a/share/completions/apt-file.fish +++ b/share/completions/apt-file.fish @@ -11,7 +11,7 @@ complete -f -c apt-file -s i -l ignore-case -d "Do not expand pattern" complete -f -c apt-file -s x -l regexp -d "Pattern is regexp" complete -f -c apt-file -s V -l version -d "Display version and exit" complete -f -c apt-file -s a -l architecture -d "Set arch" -complete -r -c apt-file -s s -l sources-list -a "(ls /etc/apt)" -d "Set sources.list file" +complete -r -c apt-file -s s -l sources-list -a '(set -l files /etc/apt/*; string replace /etc/apt/ "" -- $files)' -d "Set sources.list file" complete -f -c apt-file -s l -l package-only -d "Only display package name" complete -f -c apt-file -s F -l fixed-string -d "Do not expand pattern" complete -f -c apt-file -s y -l dummy -d "Run in dummy mode" From c5d5089871ddaabf77145c04a83233b744a18153 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 12:45:08 +0100 Subject: [PATCH 0064/1732] fish_svn_prompt: Stringify This was the only remaining use of `grep` in functions/. --- share/functions/fish_svn_prompt.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/functions/fish_svn_prompt.fish b/share/functions/fish_svn_prompt.fish index 5b3a90e23..c010cda94 100644 --- a/share/functions/fish_svn_prompt.fish +++ b/share/functions/fish_svn_prompt.fish @@ -78,7 +78,7 @@ function __fish_svn_prompt_parse_status --argument flag_status_string --descript # resolve the name of the variable for the character representing the current status type set -l flag_index (contains -i $flag_type $__fish_svn_prompt_flag_names) # check to see if the status string for this column contains the character representing the current status type - if test (echo $flag_status_string | grep -c $__fish_svn_prompt_chars[$flag_index]) -eq 1 + if test (count (string match $__fish_svn_prompt_chars[$flag_index] -- $flag_status_string)) -eq 1 # if it does, then get the names of the variables for the display character and colour to format it with set -l flag_var_display __fish_svn_prompt_char_{$flag_type}_display set -l flag_var_color __fish_svn_prompt_char_{$flag_type}_color From 3043d726bf83e210f323f54b16c97a75e10f6b82 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 12:46:48 +0100 Subject: [PATCH 0065/1732] completions/minikube: Stringify --- share/completions/minikube.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/completions/minikube.fish b/share/completions/minikube.fish index 81b974bac..fff7cf999 100644 --- a/share/completions/minikube.fish +++ b/share/completions/minikube.fish @@ -67,7 +67,7 @@ end function __minikube_list_addons if set -q argv[1] - minikube addons list | grep $argv[1] | string replace -r -- "- ([^:]*): .*" '$1' + minikube addons list | string match -- "*$argv[1]*" | string replace -r -- "- ([^:]*): .*" '$1' else minikube addons list | string replace -r -- "- ([^:]*): .*" '$1' end From a4d728c9deaa0a2b414c568861930575a3ec2a3c Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 12:49:12 +0100 Subject: [PATCH 0066/1732] completions/ezjail-admin: Stringify Specifically `grep`, these awks are still a bit too annoying to do with `string`. --- share/completions/ezjail-admin.fish | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/completions/ezjail-admin.fish b/share/completions/ezjail-admin.fish index 287bce118..5eb0fc74c 100644 --- a/share/completions/ezjail-admin.fish +++ b/share/completions/ezjail-admin.fish @@ -3,11 +3,11 @@ function __fish_complete_jails end function __fish_complete_running_jails - ezjail-admin list | tail +3 | grep '^.R' | awk '{ print $4 }' + ezjail-admin list | tail +3 | string match -r '^.R' | awk '{ print $4 }' end function __fish_complete_stopped_jails - ezjail-admin list | tail +3 | grep '^.S' | awk '{ print $4 }' + ezjail-admin list | tail +3 | string match -r '^.S' | awk '{ print $4 }' end # archive From aa08504fe3c7d54d861fa84f7ce2d9bbc6f4f9c3 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 13:07:10 +0100 Subject: [PATCH 0067/1732] completions/zpool: Stringify a bit These are the simple bits - replace useless helper functions and uses of grep/sed with string or other appropriate tools. --- share/completions/zpool.fish | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/share/completions/zpool.fish b/share/completions/zpool.fish index 379c87d10..20d47f41c 100644 --- a/share/completions/zpool.fish +++ b/share/completions/zpool.fish @@ -21,11 +21,7 @@ end # Does the current invocation need a command? function __fish_zpool_needs_command - if commandline -c | grep -E -q " (\?|add|attach|clear|create|destroy|detach|events|get|history|import|iostat|labelclear|list|offline|online|reguid|reopen|remove|replace|scrub|set|split|status|upgrade) " - return 1 - else - return 0 - end + not __fish_seen_subcommand_from \? add attach clear create destroy detach events get history import iostat labelclear list offline online reguid reopen remove replace scrub set split status upgrade end function __fish_zpool_using_command # zpool command whose completions are looked for @@ -40,11 +36,6 @@ function __fish_zpool_using_command # zpool command whose completions are looked end end -function __fish_zpool_append -d "Internal completion function for appending string to the zpool commandline" - set str (commandline -tc| sed -ne "s/\(.*,\)[^,]*/\1/p"|sed -e "s/--.*=//") - printf "%s\n" "$str"$argv -end - function __fish_zpool_list_used_vdevs -a pool if test -z "$pool" zpool list -H -v | grep -E "^\s" | cut -f2 | grep -x -E -v "(spare|log|cache|mirror|raidz.?)" @@ -68,12 +59,8 @@ function __fish_zpool_complete_vdevs # We can display the physical devices, as they are relevant whereas we are in a vdev definition or not __fish_zpool_list_available_vdevs # First, reverse token list to analyze it from the end - set -l reversedTokens "" - for i in (commandline -co) - set reversedTokens "$i $reversedTokens" - end set -l tokens 0 - for i in (echo "$reversedTokens" | sed "s/ /\n/g") + for i in (commandline -co)[-1..1] switch $i case spare log cache # At least 1 item expected if test $tokens -ge 1 @@ -289,9 +276,9 @@ complete -c zpool -x -n '__fish_zpool_using_command export' -d 'Pool to export' complete -c zpool -f -n '__fish_zpool_using_command get' -s p -d 'Print parsable (exact) values for numbers' complete -c zpool -f -n '__fish_zpool_using_command get' -s H -d 'Print output in a machine-parsable format' if contains -- $OS FreeBSD SunOS - complete -c zpool -x -n '__fish_zpool_using_command get' -s o -d 'Fields to display' -a '(__fish_zpool_append (__fish_zpool_list_get_fields))' + complete -c zpool -x -n '__fish_zpool_using_command get' -s o -d 'Fields to display' -a '(__fish_append , (__fish_zpool_list_get_fields))' end -complete -c zpool -x -n '__fish_zpool_using_command get' -d 'Properties to get' -a '(__fish_zpool_append (__fish_zpool_list_importtime_properties; __fish_zpool_list_rw_properties; __fish_zpool_list_writeonce_properties; __fish_zpool_list_ro_properties; __fish_zpool_list_device_properties; echo -e "all\t"(_ "All properties")))' +complete -c zpool -x -n '__fish_zpool_using_command get' -d 'Properties to get' -a '(__fish_append , (__fish_zpool_list_importtime_properties; __fish_zpool_list_rw_properties; __fish_zpool_list_writeonce_properties; __fish_zpool_list_ro_properties; __fish_zpool_list_device_properties; echo -e "all\t"(_ "All properties")))' complete -c zpool -x -n '__fish_zpool_using_command get' -d 'Pool to get properties of' -a '(__fish_complete_zfs_pools)' # history completions @@ -303,7 +290,7 @@ complete -c zpool -f -n '__fish_zpool_using_command history' -d 'Pool to get com complete -c zpool -r -n '__fish_zpool_using_command import; and __fish_not_contain_opt -s d' -s c -d 'Read configuration from specified cache file' complete -c zpool -r -n '__fish_zpool_using_command import; and __fish_not_contain_opt -s c' -s d -d 'Search for devices or files in specified directory' complete -c zpool -f -n '__fish_zpool_using_command import' -s D -d 'List or import destroyed pools only (requires -f for importation)' -complete -c zpool -x -n '__fish_zpool_using_command import' -s o -d 'Mount properties for contained datasets' -a '(__fish_zpool_append (__fish_complete_zfs_mountpoint_properties))' +complete -c zpool -x -n '__fish_zpool_using_command import' -s o -d 'Mount properties for contained datasets' -a '(__fish_append , (__fish_complete_zfs_mountpoint_properties))' complete -c zpool -x -n '__fish_zpool_using_command import' -s o -d 'Properties of the imported pool' -a '(__fish_complete_zfs_mountpoint_properties; __fish_zpool_list_importtime_properties; __fish_zpool_list_rw_properties)' complete -c zpool -f -n '__fish_zpool_using_command import' -s f -d 'Force import' complete -c zpool -f -n '__fish_zpool_using_command import' -s F -d 'Recovery mode' @@ -343,7 +330,7 @@ end complete -c zpool -f -n '__fish_zpool_using_command list' -s P -d 'Display device full path' complete -c zpool -x -n '__fish_zpool_using_command list' -s T -d 'Display a timestamp using specified format' complete -c zpool -f -n '__fish_zpool_using_command list' -s v -d 'Print verbose statistics' -complete -c zpool -x -n '__fish_zpool_using_command list' -s o -d 'Property to list' -a '(__fish_zpool_append (__fish_zpool_list_importtime_properties; __fish_zpool_list_rw_properties; __fish_zpool_list_writeonce_properties; __fish_zpool_list_ro_properties; __fish_zpool_list_device_properties))' +complete -c zpool -x -n '__fish_zpool_using_command list' -s o -d 'Property to list' -a '(__fish_append , (__fish_zpool_list_importtime_properties; __fish_zpool_list_rw_properties; __fish_zpool_list_writeonce_properties; __fish_zpool_list_ro_properties; __fish_zpool_list_device_properties))' complete -c zpool -f -n '__fish_zpool_using_command list' -d 'Pool to list properties of' -a '(__fish_complete_zfs_pools)' # offline completions @@ -396,7 +383,7 @@ complete -c zpool -f -n '__fish_zpool_using_command split' -s n -d 'Dry run: onl complete -c zpool -r -n '__fish_zpool_using_command split' -s R -d 'Set altroot for newpool and automatically import it' complete -c zpool -x -n '__fish_zpool_using_command split' -s o -d 'Pool property' -a '(__fish_zpool_list_writeonce_properties; __fish_zpool_list_rw_properties)' if test $OS = 'FreeBSD' - complete -c zpool -x -n '__fish_zpool_using_command split; and __fish_contains_opt -s R' -s o -d 'Mount properties for contained datasets' -a '(__fish_zpool_append (__fish_complete_zfs_mountpoint_properties))' + complete -c zpool -x -n '__fish_zpool_using_command split; and __fish_contains_opt -s R' -s o -d 'Mount properties for contained datasets' -a '(__fish_append , (__fish_complete_zfs_mountpoint_properties))' end complete -c zpool -x -n '__fish_zpool_using_command split' -d 'Pool to split' -a '(__fish_complete_zfs_pools)' From 05038fc8653b2c39edc7e65459528d3696c559c2 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 13:15:40 +0100 Subject: [PATCH 0068/1732] completions/zfs: Stringify --- share/completions/zfs.fish | 52 ++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/share/completions/zfs.fish b/share/completions/zfs.fish index 4b8227231..914d27d70 100644 --- a/share/completions/zfs.fish +++ b/share/completions/zfs.fish @@ -25,22 +25,14 @@ switch (uname) set OS "unknown" end -function __fish_zfs_append -d "Internal completion function for appending string to the ZFS commandline" - set str (commandline -tc | string replace -rf '(.*,)[^,]*' '$1' | string replace -r -- '--.*=' '') - printf "%s\n" "$str"$argv -end - # Does the current invocation need a command? function __fish_zfs_needs_command set -l bookmark "" if __fish_is_zfs_feature_enabled "feature@bookmarks" - set -l bookmark "|bookmark" - end - if commandline -c | grep -E -q " (\?|create|destroy|snap(shot)?|rollback|clone|promote|rename|list|set|get|inherit|upgrade|(user|group)space|(un?)?mount|(un)?share$bookmark|send|receive|recv|(un)?allow|holds?|release|diff|program) " - return 1 - else - return 0 + set bookmark "bookmark" end + + not __fish_seen_subcommand_from \? create destroy snap{,shot} rollback clone promote rename list set get inherit upgrade {user,group}space {u,un,}mount {un,}share $bookmark send receive recv {un,}allow hold{s,} release diff program end function __fish_zfs_using_command # ZFS command whose completions are looked for @@ -203,7 +195,7 @@ function __fish_zfs_list_permissions echo -e "casesensitivity\t"(_ "Case sensitivity")" (sensitive, insensitive, mixed)" end # Permissions set; if none are found, or if permission sets are not supported, no output is expected, even an error - for i in (zpool list -o name -H); zfs allow $i; end | grep -o '@[[:alnum:]]*' | sort -u + for i in (zpool list -o name -H); zfs allow $i; end | string match -r '@[[:alnum:]]*' | sort -u end complete -c zfs -f -n '__fish_zfs_needs_command' -s '?' -a '?' -d 'Display a help message' @@ -245,7 +237,7 @@ end # create completions complete -c zfs -f -n '__fish_zfs_using_command create' -s p -d 'Create all needed non-existing parent datasets' if test $OS = 'Linux' # Only Linux supports the comma-separated format; others need multiple -o calls - complete -c zfs -x -n '__fish_zfs_using_command create' -s o -d 'Dataset property' -a '(__fish_zfs_append (__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties))' + complete -c zfs -x -n '__fish_zfs_using_command create' -s o -d 'Dataset property' -a '(__fish_append , (__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties))' else complete -c zfs -x -n '__fish_zfs_using_command create' -s o -d 'Dataset property' -a '(__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties)' end @@ -268,7 +260,7 @@ complete -c zfs -x -n '__fish_zfs_using_command destroy' -d 'Dataset to destroy' # snapshot completions complete -c zfs -f -n '__fish_zfs_using_command snapshot; or __fish_zfs_using_command snap' -s r -d 'Recursively snapshot children' if test $OS = 'Linux' # Only Linux supports the comma-separated format; others need multiple -o calls - complete -c zfs -x -n '__fish_zfs_using_command snapshot; or __fish_zfs_using_command snap' -s o -d 'Snapshot property' -a '(__fish_zfs_append (__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties))' + complete -c zfs -x -n '__fish_zfs_using_command snapshot; or __fish_zfs_using_command snap' -s o -d 'Snapshot property' -a '(__fish_append , (__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties))' else complete -c zfs -x -n '__fish_zfs_using_command snapshot; or __fish_zfs_using_command snap' -s o -d 'Snapshot property' -a '(__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties)' end @@ -283,7 +275,7 @@ complete -c zfs -x -n '__fish_zfs_using_command rollback' -d 'Snapshot to roll b # clone completions complete -c zfs -f -n '__fish_zfs_using_command clone' -s p -d 'Create all needed non-existing parent datasets' if test $OS = 'Linux' # Only Linux supports the comma-separated format; others need multiple -o calls - complete -c zfs -x -n '__fish_zfs_using_command clone' -s o -d 'Clone property' -a '(__fish_zfs_append (__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties))' + complete -c zfs -x -n '__fish_zfs_using_command clone' -s o -d 'Clone property' -a '(__fish_append , (__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties))' else complete -c zfs -x -n '__fish_zfs_using_command clone' -s o -d 'Clone property' -a '(__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties)' end @@ -307,7 +299,7 @@ complete -c zfs -x -n '__fish_zfs_using_command rename' -d 'Dataset to rename' - complete -c zfs -f -n '__fish_zfs_using_command list' -s H -d 'Print output in a machine-parsable format' complete -c zfs -f -n '__fish_zfs_using_command list' -s r -d 'Operate recursively on datasets' complete -c zfs -x -n '__fish_zfs_using_command list; and __fish_contains_opt -s r' -s d -d 'Maximum recursion depth' -complete -c zfs -x -n '__fish_zfs_using_command list' -s o -d 'Property to list' -a '(__fish_zfs_append (__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties; __fish_complete_zfs_ro_properties; echo -e "name\t"(_ "Dataset name")"; echo -e "space\t"(_ "Space properties")"))' +complete -c zfs -x -n '__fish_zfs_using_command list' -s o -d 'Property to list' -a '(__fish_append , (__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties; __fish_complete_zfs_ro_properties; echo -e "name\t"(_ "Dataset name")"; echo -e "space\t"(_ "Space properties")"))' complete -c zfs -f -n '__fish_zfs_using_command list' -s p -d 'Print parsable (exact) values for numbers' complete -c zfs -x -n '__fish_zfs_using_command list; and __fish_not_contain_opt -s S' -s s -d 'Property to use for sorting output by ascending order' -a '(__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties; __fish_complete_zfs_ro_properties; echo -e "name\t"(_ "Dataset name"))' complete -c zfs -x -n '__fish_zfs_using_command list; and __fish_not_contain_opt -s s' -s S -d 'Property to use for sorting output by descending order' -a '(__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties; __fish_complete_zfs_ro_properties; echo -e "name\t"(_ "Dataset name"))' @@ -322,11 +314,11 @@ complete -c zfs -x -n '__fish_zfs_using_command set; and string match -q -r "zfs complete -c zfs -f -n '__fish_zfs_using_command get' -s r -d 'Operate recursively on datasets' complete -c zfs -x -n '__fish_zfs_using_command get; and __fish_contains_opt -s r' -s d -d 'Maximum recursion depth' complete -c zfs -f -n '__fish_zfs_using_command get' -s H -d 'Print output in a machine-parsable format' -complete -c zfs -x -n '__fish_zfs_using_command get' -s o -d 'Fields to display' -a '(__fish_zfs_append (__fish_zfs_list_get_fields))' -complete -c zfs -x -n '__fish_zfs_using_command get' -s s -d 'Property source to display' -a '(__fish_zfs_append (__fish_zfs_list_source_types))' +complete -c zfs -x -n '__fish_zfs_using_command get' -s o -d 'Fields to display' -a '(__fish_append , (__fish_zfs_list_get_fields))' +complete -c zfs -x -n '__fish_zfs_using_command get' -s s -d 'Property source to display' -a '(__fish_append , (__fish_zfs_list_source_types))' complete -c zfs -f -n '__fish_zfs_using_command get' -s p -d 'Print parsable (exact) values for numbers' -complete -c zfs -x -n '__fish_zfs_using_command get' -s t -d 'Dataset type' -a '(__fish_zfs_append (__fish_zfs_list_dataset_types))' -complete -c zfs -x -n '__fish_zfs_using_command get' -d 'Property to get' -a '(__fish_zfs_append (__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties; __fish_complete_zfs_ro_properties; echo "all"))' +complete -c zfs -x -n '__fish_zfs_using_command get' -s t -d 'Dataset type' -a '(__fish_append , (__fish_zfs_list_dataset_types))' +complete -c zfs -x -n '__fish_zfs_using_command get' -d 'Property to get' -a '(__fish_append , (__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties; __fish_complete_zfs_ro_properties; echo "all"))' complete -c zfs -x -n '__fish_zfs_using_command get' -d 'Dataset which properties is to be got' -a '(__fish_print_zfs_filesystems; __fish_print_zfs_volumes; __fish_print_zfs_snapshots)' # inherit completions @@ -346,16 +338,16 @@ complete -c zfs -f -n '__fish_zfs_using_command userspace' -s n -d 'Print UID in complete -c zfs -f -n '__fish_zfs_using_command groupspace' -s n -d 'Print GID instead of group name' complete -c zfs -f -n '__fish_zfs_using_command userspace; or __fish_zfs_using_command groupspace' -s H -d 'Print output in a machine-parsable format' complete -c zfs -f -n '__fish_zfs_using_command userspace; or __fish_zfs_using_command groupspace' -s p -d 'Print parsable (exact) values for numbers' -complete -c zfs -x -n '__fish_zfs_using_command userspace; or __fish_zfs_using_command groupspace' -s o -d 'Field to display' -a '(__fish_zfs_append (__fish_zfs_list_space_fields))' +complete -c zfs -x -n '__fish_zfs_using_command userspace; or __fish_zfs_using_command groupspace' -s o -d 'Field to display' -a '(__fish_append , (__fish_zfs_list_space_fields))' complete -c zfs -x -n '__fish_zfs_using_command userspace; or __fish_zfs_using_command groupspace; and __fish_not_contain_opt -s S' -s s -d 'Property to use for sorting output by ascending order' -a '__fish_zfs_list_space_fields' complete -c zfs -x -n '__fish_zfs_using_command userspace; or __fish_zfs_using_command groupspace; and __fish_not_contain_opt -s s' -s S -d 'Property to use for sorting output by descending order' -a '__fish_zfs_list_space_fields' -complete -c zfs -x -n '__fish_zfs_using_command userspace' -s t -d 'Identity types to display' -a '(__fish_zfs_append (__fish_zfs_list_userspace_types))' -complete -c zfs -x -n '__fish_zfs_using_command groupspace' -s t -d 'Identity types to display' -a '(__fish_zfs_append (__fish_zfs_list_groupspace_types))' +complete -c zfs -x -n '__fish_zfs_using_command userspace' -s t -d 'Identity types to display' -a '(__fish_append , (__fish_zfs_list_userspace_types))' +complete -c zfs -x -n '__fish_zfs_using_command groupspace' -s t -d 'Identity types to display' -a '(__fish_append , (__fish_zfs_list_groupspace_types))' complete -c zfs -f -n '__fish_zfs_using_command userspace; or __fish_zfs_using_command groupspace' -s i -d 'Translate S(amba)ID to POSIX ID' complete -c zfs -x -n '__fish_zfs_using_command userspace; or __fish_zfs_using_command groupspace' -d 'Dataset which space usage is to be got' -a '(__fish_print_zfs_filesystems; __fish_print_zfs_snapshots)' # mount completions -complete -c zfs -x -n '__fish_zfs_using_command mount' -s o -d 'Temporary mount point property' -a '(__fish_zfs_append (__fish_complete_zfs_mountpoint_properties))' +complete -c zfs -x -n '__fish_zfs_using_command mount' -s o -d 'Temporary mount point property' -a '(__fish_append , (__fish_complete_zfs_mountpoint_properties))' complete -c zfs -f -n '__fish_zfs_using_command mount' -s v -d 'Report progress' complete -c zfs -f -n '__fish_zfs_using_command mount' -s a -d 'Mount all available ZFS filesystems' if contains -- $OS Linux SunOS @@ -424,23 +416,23 @@ complete -c zfs -x -n '__fish_zfs_using_command receive; or __fish_zfs_using_com # allow completions complete -c zfs -f -n '__fish_zfs_using_command allow; and __fish_not_contain_opt -s d' -s l -d 'Delegate permissions only on the specified dataset' complete -c zfs -f -n '__fish_zfs_using_command allow; and __fish_not_contain_opt -s l' -s d -d 'Delegate permissions only on the descendents dataset' -complete -c zfs -x -n '__fish_zfs_using_command allow; and __fish_not_contain_opt -s e' -s u -d 'User to delegate permissions to' -a '(__fish_zfs_append (__fish_complete_users))' -complete -c zfs -x -n '__fish_zfs_using_command allow; and __fish_not_contain_opt -s e' -s g -d 'Group to delegate permissions to' -a '(__fish_zfs_append (__fish_complete_groups))' +complete -c zfs -x -n '__fish_zfs_using_command allow; and __fish_not_contain_opt -s e' -s u -d 'User to delegate permissions to' -a '(__fish_append , (__fish_complete_users))' +complete -c zfs -x -n '__fish_zfs_using_command allow; and __fish_not_contain_opt -s e' -s g -d 'Group to delegate permissions to' -a '(__fish_append , (__fish_complete_groups))' if contains -- $OS SunOS FreeBSD complete -c zfs -f -n '__fish_zfs_using_command allow; and __fish_not_contain_opt -s u -s g -s e' -a 'everyone' -d 'Delegate permission to everyone' end complete -c zfs -x -n '__fish_zfs_using_command allow; and __fish_not_contain_opt -s u -s g everyone' -s e -d 'Delegate permission to everyone' -complete -c zfs -x -n '__fish_zfs_using_command allow; and __fish_not_contain_opt -s l -s d -s e -s g -s u -s s' -s c -d 'Delegate permissions only to the creator of later descendent datasets' -a '(__fish_zfs_append (__fish_zfs_list_permissions))' +complete -c zfs -x -n '__fish_zfs_using_command allow; and __fish_not_contain_opt -s l -s d -s e -s g -s u -s s' -s c -d 'Delegate permissions only to the creator of later descendent datasets' -a '(__fish_zfs_append , (__fish_zfs_list_permissions))' complete -c zfs -x -n '__fish_zfs_using_command allow; and __fish_not_contain_opt -s l -s d -s e -s g -s u -s c' -s s -d 'Create a permission set or add permissions to an existing one' complete -c zfs -x -n '__fish_zfs_using_command allow' -d 'Dataset on which delegation is to be applied' -a '(__fish_print_zfs_filesystems; __fish_print_zfs_volumes)' # unallow completions complete -c zfs -f -n '__fish_zfs_using_command unallow; and __fish_not_contain_opt -s d' -s l -d 'Remove permissions only on the specified dataset' complete -c zfs -f -n '__fish_zfs_using_command unallow; and __fish_not_contain_opt -s l' -s d -d 'Remove permissions only on the descendents dataset' -complete -c zfs -x -n '__fish_zfs_using_command unallow; and __fish_not_contain_opt -s e' -s u -d 'User to remove permissions from' -a '(__fish_zfs_append (__fish_complete_users))' -complete -c zfs -x -n '__fish_zfs_using_command unallow; and __fish_not_contain_opt -s e' -s g -d 'Group to remove permissions from' -a '(__fish_zfs_append (__fish_complete_groups))' +complete -c zfs -x -n '__fish_zfs_using_command unallow; and __fish_not_contain_opt -s e' -s u -d 'User to remove permissions from' -a '(__fish_zfs_append , (__fish_complete_users))' +complete -c zfs -x -n '__fish_zfs_using_command unallow; and __fish_not_contain_opt -s e' -s g -d 'Group to remove permissions from' -a '(__fish_zfs_append , (__fish_complete_groups))' complete -c zfs -x -n '__fish_zfs_using_command unallow; and __fish_not_contain_opt -s u -s g everyone' -s e -d 'Remove permission from everyone' -complete -c zfs -x -n '__fish_zfs_using_command unallow; and __fish_not_contain_opt -s l -s d -s e -s g -s u -s s' -s c -d 'Remove permissions only on later created descendent datasets' -a '(__fish_zfs_append (__fish_zfs_list_permissions))' +complete -c zfs -x -n '__fish_zfs_using_command unallow; and __fish_not_contain_opt -s l -s d -s e -s g -s u -s s' -s c -d 'Remove permissions only on later created descendent datasets' -a '(__fish_zfs_append , (__fish_zfs_list_permissions))' complete -c zfs -x -n '__fish_zfs_using_command unallow; and __fish_not_contain_opt -s l -s d -s e -s g -s u -s c' -s s -d 'Remove a permission set or remove permissions from an existing one' if test $OS = 'SunOS' complete -c zfs -f -n '__fish_zfs_using_command unallow' -s r -d 'Remove permissions recursively' From 912ba177ec881eb6c3298202a1fc531320dd7026 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 13:16:01 +0100 Subject: [PATCH 0069/1732] functions/__fish_append: Stringify This called `sed`, twice. --- share/functions/__fish_append.fish | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/share/functions/__fish_append.fish b/share/functions/__fish_append.fish index d1b6ece1e..d40163cab 100644 --- a/share/functions/__fish_append.fish +++ b/share/functions/__fish_append.fish @@ -1,7 +1,7 @@ -function __fish_append -d "Internal completion function for appending string to the commandline" --argument separator +function __fish_append -d "Internal completion function for appending string to the commandline" --argument sep set -e argv[1] - set str (commandline -tc| sed -ne "s/\(.*$separator\)[^$separator]*/\1/p"|sed -e "s/--.*=//") - printf "%s\n" "$str"$argv "$str"(printf "%s\n" $argv|sed -e "s/\(\t\|\$\)/,\1/") + set str (commandline -tc | string replace -rf "(.*$sep)[^$sep]*" '$1' | string replace -r -- '--.*=' '') + printf "%s\n" "$str"$argv end From 7766d0a7d04e75c296ae25fc929e042211bc92c1 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 13:22:56 +0100 Subject: [PATCH 0070/1732] Remove outdated comment [ci skip] --- share/completions/service.fish | 1 - 1 file changed, 1 deletion(-) diff --git a/share/completions/service.fish b/share/completions/service.fish index 2c5a1d64f..6cee6e241 100644 --- a/share/completions/service.fish +++ b/share/completions/service.fish @@ -19,7 +19,6 @@ else if test -d /etc/init.d # SysV on Debian and other linuxen __fish_complete_static_service_actions $service_commands else # FreeBSD # Use the output of `service -v foo` to retrieve the list of service-specific verbs - # We can safely use `sed` here because this is platform-specific complete -c service -n "not __fish_is_first_token" -xa "(__fish_complete_freebsd_service_actions)" end From 605b1cfab6d709396a797891b198ab42d72ccf95 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 13:30:49 +0100 Subject: [PATCH 0071/1732] README: Update deps - Remove `jq` since it can also use python now. - Add specific UNIX utilities Fixes #5553. [ci skip] --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8c9918a0f..28c60704c 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Once installed, run `fish` from your current shell to try fish out! Running fish requires: * curses or ncurses (preinstalled on most \*nix systems) -* some common \*nix system utilities (currently `mktemp` and `seq`), in addition to the basic POSIX utilities +* some common \*nix system utilities (currently `mktemp`), in addition to the basic POSIX utilities (`cat`, `cut`, `dirname`, `ls`, `mkdir`, `mkfifo`, `rm`, `sort`, `tr`, `uname` and `sed` at least, but the full coreutils plus find, sed and awk is preferred) * gettext (library and `gettext` command), if compiled with translation support The following optional features also have specific requirements: @@ -76,8 +76,7 @@ The following optional features also have specific requirements: `backports.lzma` module for Python 2.7 * the `fish_config` web configuration tool requires Python (2.7+ or 3.3 +) and a web browser * system clipboard integration (with the default Ctrl-V and Ctrl-X bindings) require either the - `xsel` or `pbcopy`/`pbpaste` utilities -* full completions for `yarn` and `bower` require the `jq` utility + `xsel`, `xclip`, `wl-copy`/`wl-paste` or `pbcopy`/`pbpaste` utilities * full completions for `yarn` and `npm` require the `all-the-package-names` NPM module ### Switching to fish From 9dcb5abaf1d60753e134954db4be9a7f200f0642 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 17:15:09 +0100 Subject: [PATCH 0072/1732] completions/pandoc: Stringify This should be the last call to `grep` outside of a script specifically related to `grep`. (With the exception of `zpool`, which I've already written, but which will probably be merged later) --- share/completions/pandoc.fish | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/share/completions/pandoc.fish b/share/completions/pandoc.fish index 1d45753f2..cb2927276 100644 --- a/share/completions/pandoc.fish +++ b/share/completions/pandoc.fish @@ -98,9 +98,9 @@ complete -c pandoc -r -f -l bibliography -a "(__fish_complete_suffix 'ria')" complete -c pandoc -r -f -l lua-filter -a "(__fish_complete_suffix 'lua')" # options that take files in DATADIR -complete -c pandoc -r -s F -l filter -a "(find $datadir/filters/** | sed -e 's|$datadir/filters/||')" -complete -c pandoc -r -l template -a "(find $datadir/templates/** | sed -e 's|$datadir/templates/||')" -complete -c pandoc -r -f -l lua-filter -a "(find $datadir/** | egrep '.lua\$' | sed -e 's|$datadir/||')" +complete -c pandoc -r -s F -l filter -a "(find $datadir/filters/** | string replace -- '$datadir/filters/' '')" +complete -c pandoc -r -l template -a "(find $datadir/templates/** | string replace -- '$datadir/templates/' '')" +complete -c pandoc -r -f -l lua-filter -a "(find $datadir/** | string match -r '.lua\$' | string replace -- '$datadir/' '')" # options that require arguments which cannot be autocompleted complete -c pandoc -x -l indented-code-classes From 2bf554ae5e18fdc6b4cebc9ba746242e1f9d6d63 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 14 Mar 2019 10:28:48 -0700 Subject: [PATCH 0073/1732] Simplify valid_var_name --- src/common.cpp | 14 +++----------- src/common.h | 1 - 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/common.cpp b/src/common.cpp index 063d45d21..451ec6d52 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -2414,21 +2414,13 @@ void redirect_tty_output() { bool valid_var_name_char(wchar_t chr) { return fish_iswalnum(chr) || chr == L'_'; } /// Test if the given string is a valid variable name. -bool valid_var_name(const wchar_t *str) { - if (str[0] == L'\0') return false; - while (*str) { - if (!valid_var_name_char(*str)) return false; - str++; - } - return true; +bool valid_var_name(const wcstring &str) { + return std::find_if(str.begin(), str.end(), valid_var_name_char) == str.end(); } -/// Test if the given string is a valid variable name. -bool valid_var_name(const wcstring &str) { return valid_var_name(str.c_str()); } - /// Test if the string is a valid function name. bool valid_func_name(const wcstring &str) { - if (str.size() == 0) return false; + if (str.empty()) return false; if (str.at(0) == L'-') return false; if (str.find_first_of(L'/') != wcstring::npos) return false; return true; diff --git a/src/common.h b/src/common.h index c927e0c11..c5522713d 100644 --- a/src/common.h +++ b/src/common.h @@ -971,7 +971,6 @@ void invalidate_termsize(bool invalidate_vars = false); struct winsize get_current_winsize(); bool valid_var_name_char(wchar_t chr); -bool valid_var_name(const wchar_t *str); bool valid_var_name(const wcstring &str); bool valid_func_name(const wcstring &str); From 2636876472b8e00b8a652b2a237255d4a910766d Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Wed, 13 Mar 2019 13:52:11 -0700 Subject: [PATCH 0074/1732] simplify append_yaml_to_buffer --- src/history.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/history.cpp b/src/history.cpp index 8ad1bfeb9..fafcd72ce 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -608,17 +608,13 @@ static void append_yaml_to_buffer(const wcstring &wcmd, time_t timestamp, std::string cmd = wcs2string(wcmd); escape_yaml(&cmd); buffer->append("- cmd: ", cmd.c_str(), "\n"); - - char timestamp_str[96]; - snprintf(timestamp_str, sizeof timestamp_str, "%ld", (long)timestamp); - buffer->append(" when: ", timestamp_str, "\n"); + buffer->append(" when: ", std::to_string(timestamp).c_str(), "\n"); if (!required_paths.empty()) { buffer->append(" paths:\n"); - for (path_list_t::const_iterator iter = required_paths.begin(); - iter != required_paths.end(); ++iter) { - std::string path = wcs2string(*iter); + for (auto const &wpath : required_paths) { + std::string path = wcs2string(wpath); escape_yaml(&path); buffer->append(" - ", path.c_str(), "\n"); } From cf570d4b11002112d2a24a58b9905d1c25543a05 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 14 Mar 2019 10:37:13 -0700 Subject: [PATCH 0075/1732] fixup previous commit --- src/common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common.cpp b/src/common.cpp index 451ec6d52..3374bd6aa 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -2415,7 +2415,7 @@ bool valid_var_name_char(wchar_t chr) { return fish_iswalnum(chr) || chr == L'_' /// Test if the given string is a valid variable name. bool valid_var_name(const wcstring &str) { - return std::find_if(str.begin(), str.end(), valid_var_name_char) == str.end(); + return std::find_if_not(str.begin(), str.end(), valid_var_name_char) == str.end(); } /// Test if the string is a valid function name. From 0ee98628096151d1fc63b4c5957d5a6406cee937 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 14 Mar 2019 10:52:26 -0700 Subject: [PATCH 0076/1732] Write out backtrace in one debug(), add \n after it. The goal here is to make fish -dn -Dn output a little easier to scan visually. --- src/common.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/common.cpp b/src/common.cpp index 3374bd6aa..de0759a5a 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -225,18 +225,8 @@ demangled_backtrace(int max_frames, int skip_levels) { [[gnu::noinline]] void show_stackframe(const wchar_t msg_level, int frame_count, int skip_levels) { if (frame_count < 1) return; - // TODO: Decide if this is still needed. I'm commenting it out because it caused me some grief - // while trying to debug a test failure. And the tests run just fine without spurious failures - // if this check is not done. - // - // Hack to avoid showing backtraces in the tester. - // if (program_name && !std::wcscmp(program_name, L"(ignore)")) return; - - debug_shared(msg_level, L"Backtrace:"); - std::vector bt = demangled_backtrace(frame_count, skip_levels + 2); - for (int i = 0; (size_t)i < bt.size(); i++) { - debug_shared(msg_level, bt[i]); - } + wcstring_list_t bt = demangled_backtrace(frame_count, skip_levels + 2); + debug_shared(msg_level, L"Backtrace:\n" + join_strings(bt, L'\n') + L'\n'); } #else // HAVE_BACKTRACE_SYMBOLS From 477b2e8d7c21c93f7ae544af82ad51a818040dbf Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 14 Mar 2019 11:15:50 -0700 Subject: [PATCH 0077/1732] std::vector is wcstring_list_t --- src/builtin_bind.cpp | 2 +- src/common.cpp | 2 +- src/exec.cpp | 2 +- src/exec.h | 2 +- src/fish_tests.cpp | 4 ++-- src/highlight.cpp | 2 +- src/input.cpp | 3 +-- src/path.cpp | 2 +- src/reader.cpp | 2 +- src/screen.h | 2 +- 10 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/builtin_bind.cpp b/src/builtin_bind.cpp index 533d48399..dbf717347 100644 --- a/src/builtin_bind.cpp +++ b/src/builtin_bind.cpp @@ -53,7 +53,7 @@ struct bind_cmd_opts_t { /// Returns false if no binding with that sequence and mode exists. bool builtin_bind_t::list_one(const wcstring &seq, const wcstring &bind_mode, bool user, io_streams_t &streams) { - std::vector ecmds; + wcstring_list_t ecmds; wcstring sets_mode; if (!input_mapping_get(seq, bind_mode, &ecmds, user, &sets_mode)) { diff --git a/src/common.cpp b/src/common.cpp index de0759a5a..41d7ee3e0 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -198,7 +198,7 @@ demangled_backtrace(int max_frames, int skip_levels) { int n_frames = backtrace(callstack, n_max_frames); char **symbols = backtrace_symbols(callstack, n_frames); wchar_t text[1024]; - std::vector backtrace_text; + wcstring_list_t backtrace_text; if (skip_levels + max_frames < n_frames) n_frames = skip_levels + max_frames; diff --git a/src/exec.cpp b/src/exec.cpp index 05ebea52a..b93c78f02 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -1150,7 +1150,7 @@ static int exec_subshell_internal(const wcstring &cmd, parser_t &parser, wcstrin return subcommand_statuses.status; } -int exec_subshell(const wcstring &cmd, parser_t &parser, std::vector &outputs, +int exec_subshell(const wcstring &cmd, parser_t &parser, wcstring_list_t &outputs, bool apply_exit_status, bool is_subcmd) { ASSERT_IS_MAIN_THREAD(); return exec_subshell_internal(cmd, parser, &outputs, apply_exit_status, is_subcmd); diff --git a/src/exec.h b/src/exec.h index 63b78abc7..12c5d9051 100644 --- a/src/exec.h +++ b/src/exec.h @@ -23,7 +23,7 @@ bool exec_job(parser_t &parser, std::shared_ptr j); /// \param outputs The list to insert output into. /// /// \return the status of the last job to exit, or -1 if en error was encountered. -int exec_subshell(const wcstring &cmd, parser_t &parser, std::vector &outputs, +int exec_subshell(const wcstring &cmd, parser_t &parser, wcstring_list_t &outputs, bool preserve_exit_status, bool is_subcmd = false); int exec_subshell(const wcstring &cmd, parser_t &parser, bool preserve_exit_status, bool is_subcmd = false); diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index e459dc504..217753c82 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -3012,10 +3012,10 @@ static void test_line_iterator() { do_test((lines1 == std::vector{"Alpha", "Beta", "Gamma", "", "Delta"})); wcstring text2 = L"\n\nAlpha\nBeta\nGamma\n\nDelta"; - std::vector lines2; + wcstring_list_t lines2; line_iterator_t iter2(text2); while (iter2.next()) lines2.push_back(iter2.line()); - do_test((lines2 == std::vector{L"", L"", L"Alpha", L"Beta", L"Gamma", L"", L"Delta"})); + do_test((lines2 == wcstring_list_t{L"", L"", L"Alpha", L"Beta", L"Gamma", L"", L"Delta"})); } #define UVARS_PER_THREAD 8 diff --git a/src/highlight.cpp b/src/highlight.cpp index d45426024..bea5a6dc5 100644 --- a/src/highlight.cpp +++ b/src/highlight.cpp @@ -322,7 +322,7 @@ static bool is_potential_cd_path(const wcstring &path, const wcstring &working_d } else { // Get the CDPATH. auto cdpath = vars.get(L"CDPATH"); - std::vector pathsv = + wcstring_list_t pathsv = cdpath.missing_or_empty() ? wcstring_list_t{L"."} : cdpath->as_list(); for (auto next_path : pathsv) { diff --git a/src/input.cpp b/src/input.cpp index 66205a628..5cece3eeb 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -46,8 +46,7 @@ struct input_mapping_t { /// New mode that should be switched to after command evaluation. wcstring sets_mode; - input_mapping_t(wcstring s, std::vector c, wcstring m, - wcstring sm) + input_mapping_t(wcstring s, wcstring_list_t c, wcstring m, wcstring sm) : seq(std::move(s)), commands(std::move(c)), mode(std::move(m)), sets_mode(std::move(sm)) { static unsigned int s_last_input_map_spec_order = 0; specification_order = ++s_last_input_map_spec_order; diff --git a/src/path.cpp b/src/path.cpp index 93d941204..8349dd50e 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -135,7 +135,7 @@ wcstring_list_t path_get_paths(const wcstring &cmd, const environment_t &vars) { } auto path_var = vars.get(L"PATH"); - std::vector pathsv; + wcstring_list_t pathsv; if (path_var) path_var->to_list(pathsv); for (auto path : pathsv) { if (path.empty()) continue; diff --git a/src/reader.cpp b/src/reader.cpp index 8d2b0ec35..02c5a11bc 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -196,7 +196,7 @@ class reader_history_search_t { tokenizer_t tok(text.c_str(), TOK_ACCEPT_UNFINISHED); tok_t token; - std::vector local_tokens; + wcstring_list_t local_tokens; while (tok.next(&token)) { if (token.type != TOK_STRING) continue; wcstring text = tok.text_of(token); diff --git a/src/screen.h b/src/screen.h index d44e40457..a88d9d4ef 100644 --- a/src/screen.h +++ b/src/screen.h @@ -222,7 +222,7 @@ class layout_cache_t { private: // Cached escape sequences we've already detected in the prompt and similar strings, ordered // lexicographically. - std::vector esc_cache_; + wcstring_list_t esc_cache_; // LRU-list of prompts and their layouts. // Use a list so we can promote to the front on a cache hit. From 4a67d9015b72a18de8f6ef29e486fd7c5c38a41b Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 21:07:10 +0100 Subject: [PATCH 0078/1732] docs/command: Make it clearer that `-a` needs a commandname Fixes #5107. [ci skip] --- sphinx_doc_src/cmds/command.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_doc_src/cmds/command.rst b/sphinx_doc_src/cmds/command.rst index 6b9c1f026..8fc7c5dc5 100644 --- a/sphinx_doc_src/cmds/command.rst +++ b/sphinx_doc_src/cmds/command.rst @@ -14,7 +14,7 @@ Description The following options are available: -- ``-a`` or ``--all`` returns all the external commands that are found in ``$PATH`` in the order they are found. +- ``-a`` or ``--all`` returns all the external COMMANDNAMEs that are found in ``$PATH`` in the order they are found. - ``-q`` or ``--quiet``, silences the output and prints nothing, setting only the exit code. Implies ``--search``. From d837eee09d481b7f47863e63d50d404c8f78f7ea Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 14 Mar 2019 15:12:14 -0700 Subject: [PATCH 0079/1732] remove some wcstring -> wchar_t* -> wcstring conversions Mostly related to usage _(L"foo"), keeping in mind the _ macro does a wcstring().c_str() already. And a smattering of other trivial micro-optimizations certain to not help tangibly. --- src/builtin.cpp | 4 ++-- src/builtin.h | 2 +- src/builtin_argparse.cpp | 3 +-- src/builtin_complete.cpp | 2 +- src/builtin_math.cpp | 4 ++-- src/builtin_string.cpp | 2 +- src/common.cpp | 3 +-- src/complete.cpp | 6 +++--- src/env.cpp | 4 ++-- src/expand.h | 1 + src/fish_tests.cpp | 4 ++-- src/history.cpp | 4 ++-- src/output.cpp | 14 +++++++------- src/parse_tree.cpp | 2 +- src/tokenizer.cpp | 5 +++-- src/tokenizer.h | 2 +- src/wildcard.cpp | 6 ++---- src/wutil.cpp | 4 ++-- 18 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index 76e235813..f7103a0bf 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -545,8 +545,8 @@ void builtin_get_names(std::vector *list) { } /// Return a one-line description of the specified builtin. -wcstring builtin_get_desc(const wcstring &name) { - wcstring result; +const wchar_t *builtin_get_desc(const wcstring &name) { + const wchar_t *result; const builtin_data_t *builtin = builtin_lookup(name); if (builtin) { result = _(builtin->desc); diff --git a/src/builtin.h b/src/builtin.h index e9fcd2c78..8e5fd5e18 100644 --- a/src/builtin.h +++ b/src/builtin.h @@ -83,7 +83,7 @@ proc_status_t builtin_run(parser_t &parser, int job_pgrp, wchar_t **argv, io_str wcstring_list_t builtin_get_names(); void builtin_get_names(std::vector *list); -wcstring builtin_get_desc(const wcstring &b); +const wchar_t *builtin_get_desc(const wcstring &b); /// Support for setting and removing transient command lines. This is used by /// 'complete -C' in order to make the commandline builtin operate on the string diff --git a/src/builtin_argparse.cpp b/src/builtin_argparse.cpp index 1e87a03a4..4490ae7d2 100644 --- a/src/builtin_argparse.cpp +++ b/src/builtin_argparse.cpp @@ -448,8 +448,7 @@ static int validate_arg(parser_t &parser, const argparse_cmd_opts_t &opts, optio if (is_long_flag) { vars.set_one(var_name_prefix + L"name", ENV_LOCAL, opt_spec->long_flag); } else { - vars.set_one(var_name_prefix + L"name", ENV_LOCAL, - wcstring(1, opt_spec->short_flag).c_str()); + vars.set_one(var_name_prefix + L"name", ENV_LOCAL, wcstring(1, opt_spec->short_flag)); } vars.set_one(var_name_prefix + L"value", ENV_LOCAL, woptarg); diff --git a/src/builtin_complete.cpp b/src/builtin_complete.cpp index 438a33bab..c96571210 100644 --- a/src/builtin_complete.cpp +++ b/src/builtin_complete.cpp @@ -49,7 +49,7 @@ static void builtin_complete_add2(const wchar_t *cmd, int cmd_type, const wchar_ comp, desc, flags); } - if (old_opt.empty() && gnu_opt.empty() && std::wcslen(short_opt) == 0) { + if (old_opt.empty() && gnu_opt.empty() && short_opt[0] == L'\0') { complete_add(cmd, cmd_type, wcstring(), option_type_args_only, result_mode, condition, comp, desc, flags); } diff --git a/src/builtin_math.cpp b/src/builtin_math.cpp index 7798fe1a8..fdbe0a980 100644 --- a/src/builtin_math.cpp +++ b/src/builtin_math.cpp @@ -129,7 +129,7 @@ static const wchar_t *math_get_arg(int *argidx, wchar_t **argv, wcstring *storag return math_get_arg_argv(argidx, argv); } -static wcstring math_describe_error(te_error_t& error) { +static const wchar_t *math_describe_error(te_error_t& error) { if (error.position == 0) return L"NO ERROR?!?"; switch(error.type) { @@ -210,7 +210,7 @@ static int evaluate_expression(const wchar_t *cmd, parser_t &parser, io_streams_ streams.out.push_back(L'\n'); } } else { - streams.err.append_format(L"%ls: Error: %ls\n", cmd, math_describe_error(error).c_str()); + streams.err.append_format(L"%ls: Error: %ls\n", cmd, math_describe_error(error)); streams.err.append_format(L"'%ls'\n", expression.c_str()); streams.err.append_format(L"%*ls%ls\n", error.position - 1, L" ",L"^"); retval = STATUS_CMD_ERROR; diff --git a/src/builtin_string.cpp b/src/builtin_string.cpp index a62392299..a136b1fb2 100644 --- a/src/builtin_string.cpp +++ b/src/builtin_string.cpp @@ -1008,13 +1008,13 @@ bool regex_replacer_t::replace_matches(const wcstring &arg) { } } - wcstring outstr(output, outlen); bool rc = true; if (pcre2_rc < 0) { string_error(streams, _(L"%ls: Regular expression substitute error: %ls\n"), argv0, pcre2_strerror(pcre2_rc).c_str()); rc = false; } else { + wcstring outstr(output, outlen); bool replacement_occurred = pcre2_rc > 0; if (!opts.quiet && (!opts.filter || replacement_occurred)) { streams.out.append(outstr); diff --git a/src/common.cpp b/src/common.cpp index 41d7ee3e0..3728ff269 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -1484,8 +1484,7 @@ static bool unescape_string_internal(const wchar_t *const input, const size_t in if (unescape_special && input_position == 0 && !std::wcscmp(input, PROCESS_EXPAND_SELF_STR)) { to_append_or_none = PROCESS_EXPAND_SELF; - input_position += - std::wcslen(PROCESS_EXPAND_SELF_STR) - 1; // skip over 'self' part. + input_position += PROCESS_EXPAND_SELF_STR_LEN - 1; // skip over 'self's } break; } diff --git a/src/complete.cpp b/src/complete.cpp index 30bab6506..481cff7d5 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -508,7 +508,7 @@ static void parse_cmd_string(const wcstring &str, wcstring *path, wcstring *cmd, const environment_t &vars) { if (!path_get_path(str, path, vars)) { /// Use the empty string as the 'path' for commands that can not be found. - *path = L""; + path->clear(); } // Make sure the path is not included in the command. @@ -1150,8 +1150,8 @@ bool completer_t::complete_variable(const wcstring &str, size_t start_offset) { auto var = vars.get(env_name); if (!var) continue; - wcstring value = expand_escape_variable(*var); if (this->type() != COMPLETE_AUTOSUGGEST) { + wcstring value = expand_escape_variable(*var); desc = format_string(COMPLETE_VAR_DESC_VAL, value.c_str()); } } @@ -1493,7 +1493,7 @@ void completer_t::perform() { bool cursor_in_whitespace = !plain_statement.location_in_or_at_end_of_source_range(pos); if (cursor_in_whitespace) { - current_argument = L""; + current_argument.clear(); previous_argument = matching_arg; } else { current_argument = matching_arg; diff --git a/src/env.cpp b/src/env.cpp index 40bc26b34..3cfe58715 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -481,7 +481,7 @@ static void update_fish_color_support(const environment_t &vars) { debug(2, L"256 color support enabled for TERM=%ls", term.c_str()); } else if (term.find(L"xterm") != wcstring::npos) { // Assume that all 'xterm's can handle 256, except for Terminal.app from Snow Leopard - wcstring term_program, term_version; + wcstring term_program; if (auto tp = vars.get(L"TERM_PROGRAM")) term_program = tp->as_string(); if (auto tpv = vars.get(L"TERM_PROGRAM_VERSION")) { if (term_program == L"Apple_Terminal" && @@ -821,7 +821,7 @@ static void handle_fish_history_change(const wcstring &op, const wcstring &var_n env_stack_t &vars) { UNUSED(op); UNUSED(var_name); - reader_change_history(history_session_id(vars).c_str()); + reader_change_history(history_session_id(vars)); } static void handle_function_path_change(const wcstring &op, const wcstring &var_name, diff --git a/src/expand.h b/src/expand.h index 8dd0da247..2386f45c4 100644 --- a/src/expand.h +++ b/src/expand.h @@ -102,6 +102,7 @@ enum expand_error_t { /// The string represented by PROCESS_EXPAND_SELF #define PROCESS_EXPAND_SELF_STR L"%self" +#define PROCESS_EXPAND_SELF_STR_LEN 5 /// Perform various forms of expansion on in, such as tilde expansion (\~USER becomes the users home /// directory), variable expansion (\$VAR_NAME becomes the value of the environment variable diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 217753c82..52692f0bc 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -2668,7 +2668,7 @@ static void test_complete() { do_test((completions.at(1).flags & COMPLETE_NO_SPACE) != 0); // Test wraps. - do_test(comma_join(complete_get_wrap_targets(L"wrapper1")) == L""); + do_test(comma_join(complete_get_wrap_targets(L"wrapper1")).empty()); complete_add_wrapper(L"wrapper1", L"wrapper2"); do_test(comma_join(complete_get_wrap_targets(L"wrapper1")) == L"wrapper2"); complete_add_wrapper(L"wrapper2", L"wrapper3"); @@ -2679,7 +2679,7 @@ static void test_complete() { do_test(comma_join(complete_get_wrap_targets(L"wrapper2")) == L"wrapper3"); do_test(comma_join(complete_get_wrap_targets(L"wrapper3")) == L"wrapper1"); complete_remove_wrapper(L"wrapper1", L"wrapper2"); - do_test(comma_join(complete_get_wrap_targets(L"wrapper1")) == L""); + do_test(comma_join(complete_get_wrap_targets(L"wrapper1")).empty()); do_test(comma_join(complete_get_wrap_targets(L"wrapper2")) == L"wrapper3"); do_test(comma_join(complete_get_wrap_targets(L"wrapper3")) == L"wrapper1"); } diff --git a/src/history.cpp b/src/history.cpp index fafcd72ce..dcc041c97 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -371,7 +371,7 @@ static size_t trim_leading_spaces(std::string &str) { static bool extract_prefix_and_unescape_yaml(std::string *key, std::string *value, const std::string &line) { - size_t where = line.find(":"); + size_t where = line.find(':'); if (where != std::string::npos) { key->assign(line, 0, where); @@ -1868,7 +1868,7 @@ wcstring history_session_id(const environment_t &vars) { if (var) { wcstring session_id = var->as_string(); if (session_id.empty()) { - result = L""; + result.clear(); } else if (session_id == L"default") { ; // using the default value } else if (valid_var_name(session_id)) { diff --git a/src/output.cpp b/src/output.cpp index 14d210c3c..ddabac3b4 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -234,7 +234,7 @@ void outputter_t::set_color(rgb_color_t c, rgb_color_t c2) { if (c == c2) c = (c2 == rgb_color_t::white()) ? rgb_color_t::black() : rgb_color_t::white(); } - if ((enter_bold_mode != 0) && (std::strlen(enter_bold_mode) > 0)) { + if (enter_bold_mode && enter_bold_mode[0] != '\0') { if (bg_set && !last_bg_set) { // Background color changed and is set, so we enter bold mode to make reading easier. // This means bold mode is _always_ on when the background color is set. @@ -295,7 +295,7 @@ void outputter_t::set_color(rgb_color_t c, rgb_color_t c2) { } // Lastly, we set bold, underline, italics, dim, and reverse modes correctly. - if (is_bold && !was_bold && enter_bold_mode && std::strlen(enter_bold_mode) > 0 && !bg_set) { + if (is_bold && !was_bold && enter_bold_mode && enter_bold_mode[0] != '\0' && !bg_set) { // The unconst cast is for NetBSD's benefit. DO NOT REMOVE! writembs_nofail(*this, tparm((char *)enter_bold_mode)); was_bold = is_bold; @@ -310,27 +310,27 @@ void outputter_t::set_color(rgb_color_t c, rgb_color_t c2) { } was_underline = is_underline; - if (was_italics && !is_italics && enter_italics_mode && std::strlen(enter_italics_mode) > 0) { + if (was_italics && !is_italics && enter_italics_mode && enter_italics_mode[0] != '\0') { writembs_nofail(*this, exit_italics_mode); was_italics = is_italics; } - if (!was_italics && is_italics && enter_italics_mode && std::strlen(enter_italics_mode) > 0) { + if (!was_italics && is_italics && enter_italics_mode && enter_italics_mode[0] != '\0') { writembs_nofail(*this, enter_italics_mode); was_italics = is_italics; } - if (is_dim && !was_dim && enter_dim_mode && std::strlen(enter_dim_mode) > 0) { + if (is_dim && !was_dim && enter_dim_mode && enter_dim_mode[0] != '\0') { writembs_nofail(*this, enter_dim_mode); was_dim = is_dim; } if (is_reverse && !was_reverse) { // Some terms do not have a reverse mode set, so standout mode is a fallback. - if (enter_reverse_mode && std::strlen(enter_reverse_mode) > 0) { + if (enter_reverse_mode && enter_reverse_mode[0] != '\0') { writembs_nofail(*this, enter_reverse_mode); was_reverse = is_reverse; - } else if (enter_standout_mode && std::strlen(enter_standout_mode) > 0) { + } else if (enter_standout_mode && enter_standout_mode[0] != '\0') { writembs_nofail(*this, enter_standout_mode); was_reverse = is_reverse; } diff --git a/src/parse_tree.cpp b/src/parse_tree.cpp index 52be15884..cd7b35568 100644 --- a/src/parse_tree.cpp +++ b/src/parse_tree.cpp @@ -691,7 +691,7 @@ void parse_ll_t::report_tokenizer_error(const tok_t &tok) { parse_error_code_t parse_error_code = parse_error_from_tokenizer_error(tok.error); this->parse_error_at_location(tok.offset, tok.length, tok.offset + tok.error_offset, parse_error_code, L"%ls", - tokenizer_get_error_message(tok.error).c_str()); + tokenizer_get_error_message(tok.error)); } void parse_ll_t::parse_error_unexpected_token(const wchar_t *expected, parse_token_t token) { diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 8de6f3da2..ef55b7877 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -17,7 +17,8 @@ #include "tokenizer.h" #include "wutil.h" // IWYU pragma: keep -wcstring tokenizer_get_error_message(tokenizer_error_t err) { +// _(s) is already wgettext(s).c_str(), so let's not convert back to wcstring +const wchar_t * tokenizer_get_error_message(tokenizer_error_t err) { switch (err) { case tokenizer_error_t::none: return L""; @@ -47,7 +48,7 @@ wcstring tokenizer_get_error_message(tokenizer_error_t err) { return _(L"Unexpected ')' found, expecting '}'"); } assert(0 && "Unexpected tokenizer error"); - return NULL; + return nullptr; } // Whether carets redirect stderr. diff --git a/src/tokenizer.h b/src/tokenizer.h index 5eb0806a3..0d0527e86 100644 --- a/src/tokenizer.h +++ b/src/tokenizer.h @@ -61,7 +61,7 @@ enum class tokenizer_error_t { }; /// Get the error message for an error \p err. -wcstring tokenizer_get_error_message(tokenizer_error_t err); +const wchar_t *tokenizer_get_error_message(tokenizer_error_t err); struct tok_t { // The type of the token. diff --git a/src/wildcard.cpp b/src/wildcard.cpp index 398b155d8..5e0b47b22 100644 --- a/src/wildcard.cpp +++ b/src/wildcard.cpp @@ -336,7 +336,7 @@ bool wildcard_match(const wcstring &str, const wcstring &wc, bool leading_dots_f /// \param stat_res The result of calling stat on the file /// \param buf The struct buf output of calling stat on the file /// \param err The errno value after a failed stat call on the file. -static wcstring file_get_desc(const wcstring &filename, int lstat_res, const struct stat &lbuf, +static const wchar_t *file_get_desc(const wcstring &filename, int lstat_res, const struct stat &lbuf, int stat_res, const struct stat &buf, int err) { if (lstat_res) { return COMPLETE_FILE_DESC; @@ -929,14 +929,12 @@ int wildcard_expand_string(const wcstring &wc, const wcstring &working_directory // Check for a leading slash. If we find one, we have an absolute path: the prefix is empty, the // base dir is /, and the wildcard is the remainder. If we don't find one, the prefix is the // working directory, the base dir is empty. - wcstring prefix, base_dir, effective_wc; + wcstring prefix = L"", base_dir = L"", effective_wc; if (string_prefixes_string(L"/", wc)) { - prefix = L""; base_dir = L"/"; effective_wc = wc.substr(1); } else { prefix = working_directory; - base_dir = L""; effective_wc = wc; } diff --git a/src/wutil.cpp b/src/wutil.cpp index 2004dcf42..fa250c59b 100644 --- a/src/wutil.cpp +++ b/src/wutil.cpp @@ -39,7 +39,7 @@ static owning_lock> wgettext_map; bool wreaddir_resolving(DIR *dir, const wcstring &dir_path, wcstring &out_name, bool *out_is_dir) { struct dirent *result = readdir(dir); if (!result) { - out_name = L""; + out_name.clear(); return false; } @@ -85,7 +85,7 @@ bool wreaddir_resolving(DIR *dir, const wcstring &dir_path, wcstring &out_name, bool wreaddir(DIR *dir, wcstring &out_name) { struct dirent *result = readdir(dir); if (!result) { - out_name = L""; + out_name.clear(); return false; } From 9a5022514f0767222e3a3496abceef959f92f1d4 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 14 Mar 2019 16:47:23 -0700 Subject: [PATCH 0080/1732] builtin_argparse: use std::swap --- src/builtin_argparse.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/builtin_argparse.cpp b/src/builtin_argparse.cpp index 4490ae7d2..9c6d930a3 100644 --- a/src/builtin_argparse.cpp +++ b/src/builtin_argparse.cpp @@ -105,9 +105,7 @@ static int check_for_mutually_exclusive_flags(const argparse_cmd_opts_t &opts, // We want the flag order to be deterministic. Primarily to make unit // testing easier. if (flag1 > flag2) { - wcstring tmp(flag1); - flag1 = flag2; - flag2 = tmp; + std::swap(flag1, flag2); } streams.err.append_format( _(L"%ls: Mutually exclusive flags '%ls' and `%ls` seen\n"), From cb36a9ca3639ae6ddabc7a2d2cd3dbbab0c1e8de Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 14 Mar 2019 21:45:31 -0700 Subject: [PATCH 0081/1732] builtin.cpp: ensure builtin_get_desc returns something initialized --- src/builtin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index f7103a0bf..802f95bc5 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -546,7 +546,7 @@ void builtin_get_names(std::vector *list) { /// Return a one-line description of the specified builtin. const wchar_t *builtin_get_desc(const wcstring &name) { - const wchar_t *result; + const wchar_t *result = L""; const builtin_data_t *builtin = builtin_lookup(name); if (builtin) { result = _(builtin->desc); From e7a964fdfad1ad2125902896b04dcce441f0c6ed Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 4 Jan 2018 00:42:12 +0100 Subject: [PATCH 0082/1732] [count] Allow counting lines from stdin As a simple replacement for `wc -l`. This counts both lines on stdin _and_ arguments. So if "file" has three lines, then `count a b c < file` will print 6. And since it counts newlines, like wc, `echo -n foo | count` prints 0. --- sphinx_doc_src/cmds/count.rst | 13 ++++++++++++- src/builtin.cpp | 28 +++++++++++++++++++++++++--- tests/count.err | 3 +++ tests/count.in | 9 +++++++++ tests/count.out | 6 ++++++ 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/sphinx_doc_src/cmds/count.rst b/sphinx_doc_src/cmds/count.rst index 058ea1102..981acc915 100644 --- a/sphinx_doc_src/cmds/count.rst +++ b/sphinx_doc_src/cmds/count.rst @@ -5,17 +5,20 @@ Synopsis -------- count $VARIABLE +COMMAND | count +count < FILE Description ----------- -``count`` prints the number of arguments that were passed to it. This is usually used to find out how many elements an environment variable array contains. +``count`` prints the number of arguments that were passed to it, plus the number of newlines passed to it via stdin. This is usually used to find out how many elements an environment variable array contains, or how many lines there are in a text file. ``count`` does not accept any options, not even ``-h`` or ``--help``. ``count`` exits with a non-zero exit status if no arguments were passed to it, and with zero if at least one argument was passed. +Note that, like ``wc -l``, reading from stdin counts newlines, so ``echo -n foo | count`` will print 0. Example ------- @@ -30,3 +33,11 @@ Example count *.txt # Returns the number of files in the current working directory ending with the suffix '.txt'. + git ls-files --others --exclude-standard | count + # Returns the number of untracked files in a git repository + + printf '%s\n' foo bar | count baz + # Returns 3 (2 lines from stdin plus 1 argument) + + count < /etc/hosts + # Counts the number of entries in the hosts file diff --git a/src/builtin.cpp b/src/builtin.cpp index 802f95bc5..6efffd6b3 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -300,12 +300,34 @@ static int builtin_generic(parser_t &parser, io_streams_t &streams, wchar_t **ar return STATUS_CMD_ERROR; } +// How many bytes we read() at once. +// Since this is just for counting, it can be massive. +#define COUNT_CHUNK_SIZE 512 * 256 /// Implementation of the builtin count command, used to count the number of arguments sent to it. static int builtin_count(parser_t &parser, io_streams_t &streams, wchar_t **argv) { UNUSED(parser); - int argc = builtin_count_args(argv); - streams.out.append_format(L"%d\n", argc - 1); - return argc - 1 == 0 ? STATUS_CMD_ERROR : STATUS_CMD_OK; + int argc = 0; + + // Count the newlines coming in via stdin like `wc -l`. + if (streams.stdin_is_directly_redirected) { + char buf[COUNT_CHUNK_SIZE]; + while (true) { + long n = read_blocked(streams.stdin_fd, buf, COUNT_CHUNK_SIZE); + // Ignore all errors for now. + if (n <= 0) break; + for (int i = 0; i < n; i++) { + if (buf[i] == L'\n') { + argc++; + } + } + } + } + + // Always add the size of argv. + // That means if you call `something | count a b c`, you'll get the count of something _plus 3_. + argc += builtin_count_args(argv) - 1; + streams.out.append_format(L"%d\n", argc); + return argc == 0 ? STATUS_CMD_ERROR : STATUS_CMD_OK; } /// This function handles both the 'continue' and the 'break' builtins that are used for loop diff --git a/tests/count.err b/tests/count.err index b9b02b750..333edb967 100644 --- a/tests/count.err +++ b/tests/count.err @@ -13,3 +13,6 @@ #################### # big counts + +#################### +# stdin diff --git a/tests/count.in b/tests/count.in index 81b54ce7d..e0a1480ed 100644 --- a/tests/count.in +++ b/tests/count.in @@ -27,3 +27,12 @@ for i in seq 500 break end end + +logmsg stdin +# Reading from stdin still counts the arguments +printf '%s\n' 1 2 3 4 5 | count 6 7 8 9 10 + +# Reading from stdin counts newlines - like `wc -l`. +echo -n 0 | count + +echo 1 | count diff --git a/tests/count.out b/tests/count.out index f3c2bb10e..c53b726d4 100644 --- a/tests/count.out +++ b/tests/count.out @@ -21,3 +21,9 @@ #################### # big counts + +#################### +# stdin +10 +0 +1 From 18d7123ff4f2c5cdc37728b446d37c83e57492bf Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 20:26:40 +0100 Subject: [PATCH 0083/1732] fish_git_prompt: Use `count` from stdin Removes any uses of `wc` in our codebase. --- share/functions/fish_git_prompt.fish | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/functions/fish_git_prompt.fish b/share/functions/fish_git_prompt.fish index 6f9657d1f..6ee0a8e5c 100644 --- a/share/functions/fish_git_prompt.fish +++ b/share/functions/fish_git_prompt.fish @@ -533,11 +533,11 @@ function __fish_git_prompt_informative_status set -l x (count $stagedFiles) set -l invalidstate (count (string match -r "U" -- $stagedFiles)) set -l stagedstate (math $x - $invalidstate) - set -l untrackedfiles (command git ls-files --others --exclude-standard | wc -l | string trim) + set -l untrackedfiles (command git ls-files --others --exclude-standard | count) set -l stashstate 0 set -l stashfile "$argv[1]/logs/refs/stash" if set -q __fish_git_prompt_showstashstate; and test -e "$stashfile" - set stashstate (wc -l $stashfile | string match -r '\d+') + set stashstate (count < $stashfile) end set -l info From b3f39096e7dd32d1cdc6b1f8d1c87223a5b02d49 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 20:34:37 +0100 Subject: [PATCH 0084/1732] CHANGELOG count from stdin [ci skip] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbb93d6a2..27e8026c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - In the interest of consistency, `builtin -q` and `command -q` can now be used to query if a builtin or command exists (#5631). - `math` now accepts `--scale=max` for the maximum scale (#5579). - `complete --do-complete` now also does fuzzy matches (#5467). +- `count` now also counts lines fed on stdin (#5744). ### Interactive improvements - Major improvements in performance and functionality to the 'sorin' sample prompt (#5411). From 864bb1f7a6c7b3aa582578f875d110f1b1e801dd Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 12 Jan 2019 20:20:35 +0100 Subject: [PATCH 0085/1732] Add string-replace-fewer-backslashes feature This disables an extra round of escaping in the `string replace -r` replacement string. Currently, to add a backslash to an a or b (to "escape" it): string replace -ra '([ab])' '\\\\\\\$1' a 7 backslashes! This removes one of the layers, so now 3 or 4 works (each one escaped for the single-quotes, so pcre receives two, which it reads as one literal): string replace -ra '([ab])' '\\\\$1' a This is backwards-incompatible as replacement strings will change meaning, so we put it behind a feature flag. The name is kinda crappy, though. Fixes #5474. --- src/builtin_string.cpp | 10 ++++++++-- src/future_feature_flags.cpp | 1 + src/future_feature_flags.h | 3 +++ .../invocation/features-string-backslashes-off.invoke | 1 + tests/invocation/features-string-backslashes-off.out | 1 + tests/invocation/features-string-backslashes.invoke | 1 + tests/invocation/features-string-backslashes.out | 1 + tests/status.out | 1 + 8 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/invocation/features-string-backslashes-off.invoke create mode 100644 tests/invocation/features-string-backslashes-off.out create mode 100644 tests/invocation/features-string-backslashes.invoke create mode 100644 tests/invocation/features-string-backslashes.out diff --git a/src/builtin_string.cpp b/src/builtin_string.cpp index a136b1fb2..201e7ab25 100644 --- a/src/builtin_string.cpp +++ b/src/builtin_string.cpp @@ -26,6 +26,7 @@ #include "builtin.h" #include "common.h" #include "fallback.h" // IWYU pragma: keep +#include "future_feature_flags.h" #include "io.h" #include "parse_util.h" #include "pcre2.h" @@ -933,8 +934,13 @@ class regex_replacer_t : public string_replacer_t { regex_replacer_t(const wchar_t *argv0, const wcstring &pattern, const wcstring &replacement_, const options_t &opts, io_streams_t &streams) : string_replacer_t(argv0, opts, streams), - regex(argv0, pattern, opts.ignore_case, streams), - replacement(interpret_escapes(replacement_)) {} + regex(argv0, pattern, opts.ignore_case, streams) { + if (feature_test(features_t::string_replace_backslash)) { + replacement = replacement_; + } else { + replacement = interpret_escapes(replacement_); + } + } bool replace_matches(const wcstring &arg) override; }; diff --git a/src/future_feature_flags.cpp b/src/future_feature_flags.cpp index 4feca703b..2caf145f5 100644 --- a/src/future_feature_flags.cpp +++ b/src/future_feature_flags.cpp @@ -13,6 +13,7 @@ features_t &mutable_fish_features() { return global_features; } const features_t::metadata_t features_t::metadata[features_t::flag_count] = { {stderr_nocaret, L"stderr-nocaret", L"3.0", L"^ no longer redirects stderr"}, {qmark_noglob, L"qmark-noglob", L"3.0", L"? no longer globs"}, + {string_replace_backslash, L"string-replace-fewer-backslashes", L"3.1", L"string replace -r needs fewer backslashes in the replacement"}, }; const struct features_t::metadata_t *features_t::metadata_for(const wchar_t *name) { diff --git a/src/future_feature_flags.h b/src/future_feature_flags.h index 7ccc7f570..1c42cb21a 100644 --- a/src/future_feature_flags.h +++ b/src/future_feature_flags.h @@ -17,6 +17,9 @@ class features_t { /// Whether ? is supported as a glob. qmark_noglob, + /// Whether string replace -r double-unescapes the replacement. + string_replace_backslash, + /// The number of flags. flag_count }; diff --git a/tests/invocation/features-string-backslashes-off.invoke b/tests/invocation/features-string-backslashes-off.invoke new file mode 100644 index 000000000..600bde64f --- /dev/null +++ b/tests/invocation/features-string-backslashes-off.invoke @@ -0,0 +1 @@ +--features 'no-string-replace-fewer-backslashes' -C 'string replace -ra "\\\\" "\\\\\\\\" -- "a\b\c"' diff --git a/tests/invocation/features-string-backslashes-off.out b/tests/invocation/features-string-backslashes-off.out new file mode 100644 index 000000000..2eba0a277 --- /dev/null +++ b/tests/invocation/features-string-backslashes-off.out @@ -0,0 +1 @@ +a\b\c diff --git a/tests/invocation/features-string-backslashes.invoke b/tests/invocation/features-string-backslashes.invoke new file mode 100644 index 000000000..e7923c0dc --- /dev/null +++ b/tests/invocation/features-string-backslashes.invoke @@ -0,0 +1 @@ +--features 'string-replace-fewer-backslashes' -C 'string replace -ra "\\\\" "\\\\\\\\" -- "a\b\c"' diff --git a/tests/invocation/features-string-backslashes.out b/tests/invocation/features-string-backslashes.out new file mode 100644 index 000000000..e67f30541 --- /dev/null +++ b/tests/invocation/features-string-backslashes.out @@ -0,0 +1 @@ +a\\b\\c diff --git a/tests/status.out b/tests/status.out index ea2ab205e..283b13030 100644 --- a/tests/status.out +++ b/tests/status.out @@ -6,5 +6,6 @@ test_function # Future Feature Flags stderr-nocaret off 3.0 ^ no longer redirects stderr qmark-noglob off 3.0 ? no longer globs +string-replace-fewer-backslashes off 3.1 string replace -r needs fewer backslashes in the replacement 1 2 From 83932441bb0cbe8fe0e873fc9018b0127b329a61 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 20 Jan 2019 11:12:27 +0100 Subject: [PATCH 0086/1732] Fix fish_clipboard_paste with string-replace-fewer-backslashes This is the one place in fish where we use a `\` in the replacement of a `string replace -r`, so we'll have to check the feature. --- share/functions/fish_clipboard_paste.fish | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/share/functions/fish_clipboard_paste.fish b/share/functions/fish_clipboard_paste.fish index 105ca1226..f9ab3dabe 100644 --- a/share/functions/fish_clipboard_paste.fish +++ b/share/functions/fish_clipboard_paste.fish @@ -26,7 +26,11 @@ function fish_clipboard_paste # # This eases pasting non-code (e.g. markdown or git commitishes). if __fish_commandline_is_singlequoted - set data (string replace -ra "(['\\\])" '\\\\\\\$1' -- $data) + if status test-feature string-replace-fewer-backslashes + set data (string replace -ra "(['\\\])" '\\\\$1' -- $data) + else + set data (string replace -ra "(['\\\])" '\\\\\\\$1' -- $data) + end end if not string length -q -- (commandline -c) # If we're at the beginning of the first line, trim whitespace from the start, From ef2fe0dfa0a50e18878d06fd32786908713108cf Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 15 Mar 2019 15:22:41 +0100 Subject: [PATCH 0087/1732] CHANGELOG string backslashes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27e8026c9..b92b7ef24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - The vcs-prompt functions have been renamed to names without double-underscore, so __fish_git_prompt is now fish_git_prompt, __fish_vcs_prompt is now fish_vcs_prompt, __fish_hg_prompt is now fish_hg_prompt and __fish_svn_prompt is now fish_svn_prompt. Shims at the old names have been added, and the variables have kept their old names (#5586). ## Notable Fixes and improvements +- `string replace` had an additional round of escaping in the replacement (not the match!), so escaping backslashes would require `string replace -ra '([ab])' '\\\\\\\$1' a`. A new feature flag `string-replace-fewer-backslashes` can be used to disable this, so that it becomes `string replace -ra '([ab])' '\\\\$1' a` (#5556). - Add `$pipestatus` support - macOS Mojave: fish.app can actually run (#5727), 10.14.4's Terminal.app no longer causes an error on launch (#5725) From 86e9e60ae7ad6dbba851f037911dbf59a671dc15 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 15 Mar 2019 11:19:13 +0100 Subject: [PATCH 0088/1732] completions/set: Fix `set -eU` This had a typo where it completed `-u` variables. Only `-u` means unexported, `-U` means universal. [ci skip] --- share/completions/set.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/completions/set.fish b/share/completions/set.fish index e7891b934..757fa6009 100644 --- a/share/completions/set.fish +++ b/share/completions/set.fish @@ -86,7 +86,7 @@ complete -c set -n '__fish_seen_argument -s e -l erase; and not __fish_seen_argu complete -c set -n '__fish_seen_argument -s e -l erase; and not __fish_seen_argument -s l -s U -s g -l local -l global -l Universal' -f -a "(set -U | string match -rv '^_|^fish_' | string replace ' ' \tUniversal\ Variable:\ )" # Complete scope-specific variables for `set --erase` complete -c set -n '__fish_seen_argument -s e -l erase; and __fish_seen_argument -s g -l global' -f -a "(set -g | string match -rv '^_|^fish_' | string replace ' ' \t'Global Variable: ')" -complete -c set -n '__fish_seen_argument -s e -l erase; and __fish_seen_argument -s U -l universal' -f -a "(set -u | string match -rv '^_|^fish_' | string replace ' ' \t'Universal Variable: ')" +complete -c set -n '__fish_seen_argument -s e -l erase; and __fish_seen_argument -s U -l universal' -f -a "(set -U | string match -rv '^_|^fish_' | string replace ' ' \t'Universal Variable: ')" complete -c set -n '__fish_seen_argument -s e -l erase; and __fish_seen_argument -s l -l local' -f -a "(set -l | string match -rv '^_|^fish_' | string replace ' ' \t'Local Variable: ')" # Color completions From 9bd398b9fb919abf300f4390940d80c38ea4727e Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 15 Mar 2019 15:29:49 +0100 Subject: [PATCH 0089/1732] Document features more This adds string-replace-fewer-backslashes, but also explains the feature flag system a bit more. [ci skip] --- sphinx_doc_src/index.rst | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index 20554418d..562d9c3f1 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -1627,8 +1627,14 @@ You can see the current list of features via ``status features``:: > status features stderr-nocaret on 3.0 ^ no longer redirects stderr qmark-noglob off 3.0 ? no longer globs + string-replace-fewer-backslashes off 3.1 string replace -r needs fewer backslashes in the replacement -There are two breaking changes in fish 3.0: caret ``^`` no longer redirects stderr, and question mark ``?`` is no longer a glob. These changes are off by default. They can be enabled on a per session basis:: +There are two breaking changes in fish 3.0: caret ``^`` no longer redirects stderr, and question mark ``?`` is no longer a glob. + +There is one breaking change in fish 3.1: ``string replace -r`` does a superfluous round of escaping for the replacement, so escaping backslashes would look like ``string replace -ra '([ab])' '\\\\\\\$1' a``. This flag removes that if turned on, so ``'\\\\$1'`` is enough. + + +These changes are off by default. They can be enabled on a per session basis:: > fish --features qmark-noglob,stderr-nocaret @@ -1638,6 +1644,11 @@ or opted into globally for a user:: > set -U fish_features stderr-nocaret qmark-noglob +Features will only be set on startup, so this variable will only take effect if it is universal or exported. + +You can also use the version as a group, so ``3.0`` is equivalent to "stderr-nocaret" and "qmark-noglob". + +Prefixing a feature with ``no-`` turns it off instead. .. _other: Other features From a1380a736b7d776b048225d475225ce6c2d515d9 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 15 Mar 2019 19:50:28 +0100 Subject: [PATCH 0090/1732] Move __fish_print_make_targets into make completions A function file for a function used only by one completion (and unlikely to be used anywhere else). If another user shows up, we can move it out again. Part of #5279 [ci skip] --- share/completions/make.fish | 33 +++++++++++++++++++ .../functions/__fish_print_make_targets.fish | 33 ------------------- 2 files changed, 33 insertions(+), 33 deletions(-) delete mode 100644 share/functions/__fish_print_make_targets.fish diff --git a/share/completions/make.fish b/share/completions/make.fish index 083e867f3..11d425924 100644 --- a/share/completions/make.fish +++ b/share/completions/make.fish @@ -1,4 +1,37 @@ # Completions for make +function __fish_print_make_targets --argument-names directory file + # Since we filter based on localized text, we need to ensure the + # text will be using the correct locale. + set -lx LC_ALL C + + if test -z "$directory" + set directory '.' + end + + if test -z "$file" + for standard_file in $directory/{GNUmakefile,Makefile,makefile} + if test -f $standard_file + set file $standard_file + break + end + end + end + + set -l bsd_make + if make --version 2>/dev/null | string match -q 'GNU*' + set bsd_make 0 + else + set bsd_make 1 + end + + if test "$bsd_make" = 0 + # https://stackoverflow.com/a/26339924 + make -C "$directory" -f "$file" -pRrq : 2>/dev/null | awk -v RS= -F: '/^# Files/,/^# Finished Make data base/ {if ($1 !~ "^[#.]") {print $1}}' 2>/dev/null + else + make -C "$directory" -f "$file" -d g1 -rn >/dev/null 2>| awk -F, '/^#\*\*\* Input graph:/,/^$/ {if ($1 !~ "^#... ") {gsub(/# /,"",$1); print $1}}' 2>/dev/null + end +end + function __fish_complete_make_targets set directory (string replace -r '^make .*(-C ?|--directory(=| +))([^ ]*) .*$' '$3' -- $argv) if not test $status -eq 0 -a -d $directory diff --git a/share/functions/__fish_print_make_targets.fish b/share/functions/__fish_print_make_targets.fish deleted file mode 100644 index fb8ce9c03..000000000 --- a/share/functions/__fish_print_make_targets.fish +++ /dev/null @@ -1,33 +0,0 @@ -function __fish_print_make_targets --argument-names directory file - # Since we filter based on localized text, we need to ensure the - # text will be using the correct locale. - set -lx LC_ALL C - - if test -z "$directory" - set directory '.' - end - - if test -z "$file" - for standard_file in $directory/{GNUmakefile,Makefile,makefile} - if test -f $standard_file - set file $standard_file - break - end - end - end - - set -l bsd_make - if make --version 2>/dev/null | string match -q 'GNU*' - set bsd_make 0 - else - set bsd_make 1 - end - - if test "$bsd_make" = 0 - # https://stackoverflow.com/a/26339924 - make -C "$directory" -f "$file" -pRrq : 2>/dev/null | awk -v RS= -F: '/^# Files/,/^# Finished Make data base/ {if ($1 !~ "^[#.]") {print $1}}' 2>/dev/null - else - make -C "$directory" -f "$file" -d g1 -rn >/dev/null 2>| awk -F, '/^#\*\*\* Input graph:/,/^$/ {if ($1 !~ "^#... ") {gsub(/# /,"",$1); print $1}}' 2>/dev/null - end -end - From 1c3c76165e49bafd54f8feafada3dc71e3697cd1 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 15 Mar 2019 19:51:58 +0100 Subject: [PATCH 0091/1732] Move xrandr functions into randr completions Part of #5279. [ci skip] --- share/completions/xrandr.fish | 15 +++++++++++++++ share/functions/__fish_print_xrandr_modes.fish | 11 ----------- share/functions/__fish_print_xrandr_outputs.fish | 3 --- 3 files changed, 15 insertions(+), 14 deletions(-) delete mode 100644 share/functions/__fish_print_xrandr_modes.fish delete mode 100644 share/functions/__fish_print_xrandr_outputs.fish diff --git a/share/completions/xrandr.fish b/share/completions/xrandr.fish index a4a345b96..2eed8e9f3 100644 --- a/share/completions/xrandr.fish +++ b/share/completions/xrandr.fish @@ -1,3 +1,18 @@ +function __fish_print_xrandr_outputs --description 'Print xrandr outputs' + xrandr | string replace -r --filter '^(\S+)\s+(.*)$' '$1\t$2' | string match -v -e Screen +end + +function __fish_print_xrandr_modes --description 'Print xrandr modes' + set -l output + xrandr | string match -v -r '^(Screen|\s{4,})' | while read line + switch $line + case ' *' + string trim $line | string replace -r '^(\S+)\s+(.*)$' "\$1\t\$2 [$output]" + case '*' + set output (string match -r '^\S+' $line) + end + end +end complete -c xrandr -l verbose -d 'Be more verbose' complete -c xrandr -l dryrun -d 'Make no changes' complete -c xrandr -l nograb -d 'Apply modifications without grabbing the screen' diff --git a/share/functions/__fish_print_xrandr_modes.fish b/share/functions/__fish_print_xrandr_modes.fish deleted file mode 100644 index 0023abe54..000000000 --- a/share/functions/__fish_print_xrandr_modes.fish +++ /dev/null @@ -1,11 +0,0 @@ -function __fish_print_xrandr_modes --description 'Print xrandr modes' - set -l output - xrandr | string match -v -r '^(Screen|\s{4,})' | while read line - switch $line - case ' *' - string trim $line | string replace -r '^(\S+)\s+(.*)$' "\$1\t\$2 [$output]" - case '*' - set output (string match -r '^\S+' $line) - end - end -end diff --git a/share/functions/__fish_print_xrandr_outputs.fish b/share/functions/__fish_print_xrandr_outputs.fish deleted file mode 100644 index 43614a996..000000000 --- a/share/functions/__fish_print_xrandr_outputs.fish +++ /dev/null @@ -1,3 +0,0 @@ -function __fish_print_xrandr_outputs --description 'Print xrandr outputs' - xrandr | string replace -r --filter '^(\S+)\s+(.*)$' '$1\t$2' | string match -v -e Screen -end From 2de3f7c68674e386df9c96819356bc158b6ac604 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 15 Mar 2019 19:53:20 +0100 Subject: [PATCH 0092/1732] Move ninja functions into ninja completions Part of #5279 [ci skip] --- share/completions/ninja.fish | 12 ++++++++++++ share/functions/__fish_print_ninja_targets.fish | 5 ----- share/functions/__fish_print_ninja_tools.fish | 6 ------ 3 files changed, 12 insertions(+), 11 deletions(-) delete mode 100644 share/functions/__fish_print_ninja_targets.fish delete mode 100644 share/functions/__fish_print_ninja_tools.fish diff --git a/share/completions/ninja.fish b/share/completions/ninja.fish index 0dd0174bf..935d324bd 100644 --- a/share/completions/ninja.fish +++ b/share/completions/ninja.fish @@ -1,3 +1,15 @@ +function __fish_print_ninja_tools + echo list + if test -f build.ninja + ninja -t list | string match -v '*:' | string replace -r '\s+(\w+).*' '$1' + end +end + +function __fish_print_ninja_targets + if test -f build.ninja + ninja -t targets 2>/dev/null | string replace -r ':.*' '' + end +end complete -c ninja -f -a '(__fish_print_ninja_targets)' -d target complete -x -c ninja -s t -x -a "(__fish_print_ninja_tools)" -d subtool complete -x -c ninja -s C -x -a "(__fish_complete_directories (commandline -ct))" -d "change to specified directory" diff --git a/share/functions/__fish_print_ninja_targets.fish b/share/functions/__fish_print_ninja_targets.fish deleted file mode 100644 index 18d62fba6..000000000 --- a/share/functions/__fish_print_ninja_targets.fish +++ /dev/null @@ -1,5 +0,0 @@ -function __fish_print_ninja_targets - if [ -f build.ninja ] - ninja -t targets 2>/dev/null | string replace -r ':.*' '' - end -end diff --git a/share/functions/__fish_print_ninja_tools.fish b/share/functions/__fish_print_ninja_tools.fish deleted file mode 100644 index 385c91edc..000000000 --- a/share/functions/__fish_print_ninja_tools.fish +++ /dev/null @@ -1,6 +0,0 @@ -function __fish_print_ninja_tools - echo list - if [ -f build.ninja ] - ninja -t list | string match -v '*:' | string replace -r '\s+(\w+).*' '$1' - end -end From a7ab8c6a4bfe6a4c566f17456f0c559f48140bef Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 15 Mar 2019 19:55:35 +0100 Subject: [PATCH 0093/1732] Remove __fish_test_arg helper function This was a remnant from before `string` existed, and was only used by the xterm completions. Part of #5279 [ci skip] --- share/completions/xterm.fish | 92 ++++++++++++++-------------- share/functions/__fish_test_arg.fish | 9 --- 2 files changed, 46 insertions(+), 55 deletions(-) delete mode 100644 share/functions/__fish_test_arg.fish diff --git a/share/completions/xterm.fish b/share/completions/xterm.fish index 4546f3730..036d0643e 100644 --- a/share/completions/xterm.fish +++ b/share/completions/xterm.fish @@ -1,52 +1,52 @@ # completion for xterm -complete -c xterm -n '__fish_test_arg "+*"' -a +ah -d 'Never highlight the text cursor' -complete -c xterm -n '__fish_test_arg "+*"' -a +ai -d 'Enable active icon support' -complete -c xterm -n '__fish_test_arg "+*"' -a +aw -d 'Disallow auto wraparound' -complete -c xterm -n '__fish_test_arg "+*"' -a +bc -d 'Turn off cursor blinking' -complete -c xterm -n '__fish_test_arg "+*"' -a +bdc -d 'Enable the display of bold characters' -complete -c xterm -n '__fish_test_arg "+*"' -a +cb -d 'Set the vt100 resource cutToBeginningOfLine to \'true\'' -complete -c xterm -n '__fish_test_arg "+*"' -a +cjk_width -d 'Set the cjkWidth resource to \'false\'' -complete -c xterm -n '__fish_test_arg "+*"' -a +cm -d 'Enable recognition of ANSI color-change escape sequences' -complete -c xterm -n '__fish_test_arg "+*"' -a +cn -d 'Cut newlines in line-mode selections' -complete -c xterm -n '__fish_test_arg "+*"' -a +cu -d 'Don\'t workaround the bug in more(1)' -complete -c xterm -n '__fish_test_arg "+*"' -a +dc -d 'Disable dynamic color changing' -complete -c xterm -n '__fish_test_arg "+*"' -a +fbb -d 'Don\'t ensure compatibility between normal and bold fonts bounding boxes' -complete -c xterm -n '__fish_test_arg "+*"' -a +fbx -d 'Normal and bold fonts have VT100 line-drawing characters' -complete -c xterm -n '__fish_test_arg "+*"' -a +hf -d 'Don\'t generate HP Function Key escape codes for function keys' -complete -c xterm -n '__fish_test_arg "+*"' -a +hold -d 'Close xterm\'s window after the shell exits' -complete -c xterm -n '__fish_test_arg "+*"' -a +ie -d 'Don\'t use pseudo-terminal\'s sense of the stty erase value' -complete -c xterm -n '__fish_test_arg "+*"' -a +im -d 'Don\'t force insert mode' -complete -c xterm -n '__fish_test_arg "+*"' -a +j -d 'Don\'t use jump scrolling' -complete -c xterm -n '__fish_test_arg "+*"' -a +k8 -d 'Don\'t treat C1 control characters as printable' -complete -c xterm -n '__fish_test_arg "+*"' -a +l -d 'Turn off logging' -complete -c xterm -n '__fish_test_arg "+*"' -a +lc -d 'Turn off support for encodings according the locale setting' -complete -c xterm -n '__fish_test_arg "+*"' -a +ls -d 'The shell in xterm\'s window will not be login shell' -complete -c xterm -n '__fish_test_arg "+*"' -a +mb -d 'Don\'t ring bell if the user types near the end of line' -complete -c xterm -n '__fish_test_arg "+*"' -a +mesg -d 'Allow write access to the terminal' -complete -c xterm -n '__fish_test_arg "+*"' -a +mk_width -d 'Don\'t use builtin version for the wide-character calculation' -complete -c xterm -n '__fish_test_arg "+*"' -a +nul -d 'Enable underlining' -complete -c xterm -n '__fish_test_arg "+*"' -a +pc -d 'Disable PC style bold colors' -complete -c xterm -n '__fish_test_arg "+*"' -a +pob -d 'Don\'t raise window on Control-G' -complete -c xterm -n '__fish_test_arg "+*"' -a +rvc -d 'Enable characters with reverse attribute as color' -complete -c xterm -n '__fish_test_arg "+*"' -a +rw -d 'Disable reverse-wraparound' -complete -c xterm -n '__fish_test_arg "+*"' -a +s -d 'Turn off asynchronous scrolling' -complete -c xterm -n '__fish_test_arg "+*"' -a +samename -d 'Send title/icon change requests always' -complete -c xterm -n '__fish_test_arg "+*"' -a +sb -d 'Don\'t display scrollbar' -complete -c xterm -n '__fish_test_arg "+*"' -a +sf -d 'Don\'t generate Sun Function Key escape codes for function keys' -complete -c xterm -n '__fish_test_arg "+*"' -a +si -d 'Move the screen to the bottom on input' -complete -c xterm -n '__fish_test_arg "+*"' -a +sk -d 'Don\'t move the screen to the bottom on key press while scrolling' -complete -c xterm -n '__fish_test_arg "+*"' -a +sm -d 'Don\'t setup session manager callbacks' -complete -c xterm -n '__fish_test_arg "+*"' -a +sp -d 'Don\'t assume Sun/PC keyboard' -complete -c xterm -n '__fish_test_arg "+*"' -a +t -d 'VT102 mode' -complete -c xterm -n '__fish_test_arg "+*"' -a +tb -d 'Don\'t display toolbar or menubar' -complete -c xterm -n '__fish_test_arg "+*"' -a +u8 -d 'Don\'t use UTF-8' -complete -c xterm -n '__fish_test_arg "+*"' -a +ulc -d 'Display characters with underline attribute as color' -complete -c xterm -n '__fish_test_arg "+*"' -a +ut -d 'Write to the system utmp log file' -complete -c xterm -n '__fish_test_arg "+*"' -a +vb -d 'Don\'t use visual bell insead of audio bell' -complete -c xterm -n '__fish_test_arg "+*"' -a +wc -d 'Don\'t use wide characters' -complete -c xterm -n '__fish_test_arg "+*"' -a +wf -d 'Don\'t wait the first time for the window to be mapped' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +ah -d 'Never highlight the text cursor' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +ai -d 'Enable active icon support' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +aw -d 'Disallow auto wraparound' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +bc -d 'Turn off cursor blinking' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +bdc -d 'Enable the display of bold characters' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +cb -d 'Set the vt100 resource cutToBeginningOfLine to \'true\'' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +cjk_width -d 'Set the cjkWidth resource to \'false\'' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +cm -d 'Enable recognition of ANSI color-change escape sequences' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +cn -d 'Cut newlines in line-mode selections' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +cu -d 'Don\'t workaround the bug in more(1)' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +dc -d 'Disable dynamic color changing' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +fbb -d 'Don\'t ensure compatibility between normal and bold fonts bounding boxes' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +fbx -d 'Normal and bold fonts have VT100 line-drawing characters' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +hf -d 'Don\'t generate HP Function Key escape codes for function keys' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +hold -d 'Close xterm\'s window after the shell exits' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +ie -d 'Don\'t use pseudo-terminal\'s sense of the stty erase value' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +im -d 'Don\'t force insert mode' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +j -d 'Don\'t use jump scrolling' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +k8 -d 'Don\'t treat C1 control characters as printable' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +l -d 'Turn off logging' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +lc -d 'Turn off support for encodings according the locale setting' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +ls -d 'The shell in xterm\'s window will not be login shell' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +mb -d 'Don\'t ring bell if the user types near the end of line' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +mesg -d 'Allow write access to the terminal' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +mk_width -d 'Don\'t use builtin version for the wide-character calculation' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +nul -d 'Enable underlining' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +pc -d 'Disable PC style bold colors' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +pob -d 'Don\'t raise window on Control-G' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +rvc -d 'Enable characters with reverse attribute as color' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +rw -d 'Disable reverse-wraparound' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +s -d 'Turn off asynchronous scrolling' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +samename -d 'Send title/icon change requests always' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +sb -d 'Don\'t display scrollbar' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +sf -d 'Don\'t generate Sun Function Key escape codes for function keys' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +si -d 'Move the screen to the bottom on input' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +sk -d 'Don\'t move the screen to the bottom on key press while scrolling' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +sm -d 'Don\'t setup session manager callbacks' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +sp -d 'Don\'t assume Sun/PC keyboard' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +t -d 'VT102 mode' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +tb -d 'Don\'t display toolbar or menubar' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +u8 -d 'Don\'t use UTF-8' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +ulc -d 'Display characters with underline attribute as color' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +ut -d 'Write to the system utmp log file' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +vb -d 'Don\'t use visual bell insead of audio bell' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +wc -d 'Don\'t use wide characters' +complete -c xterm -n 'string match "+*" -- (commandline -ct)' -a +wf -d 'Don\'t wait the first time for the window to be mapped' complete -c xterm -o version -d 'Print version number to the standard output' complete -c xterm -o help -d 'Print out a verbose message describing the options' diff --git a/share/functions/__fish_test_arg.fish b/share/functions/__fish_test_arg.fish deleted file mode 100644 index 695c96866..000000000 --- a/share/functions/__fish_test_arg.fish +++ /dev/null @@ -1,9 +0,0 @@ - -function __fish_test_arg --description "Test if the token under the cursor matches the specified wildcard" - switch (commandline -ct) - case $argv - return 0 - end - return 1 -end - From 0b6d6a29eb64ea62c98c0d65046ab571db09b482 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 15 Mar 2019 20:09:55 +0100 Subject: [PATCH 0094/1732] completions/git: Fix broken conditions for `git config` Classic case of not seeing `and` as a new command: `__fish_git_using_command config and anotherthing` causes `and anotherthing` to be passed as arguments to `__fish_git_using_command` instead of being executed. [ci skip] --- share/completions/git.fish | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/share/completions/git.fish b/share/completions/git.fish index 3edea1aa2..98e0c30a7 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -1494,8 +1494,8 @@ complete -f -c git -n '__fish_git_using_command config' -s f -l file -d 'Read co complete -f -c git -n '__fish_git_using_command config' -l blob -d 'Read config from blob' -ra '(__fish_complete_suffix '')' # If no argument is specified, it's as if --get was used -complete -c git -n '__fish_git_using_command config and __fish_is_token_n 3' -fa '(__fish_git_config_keys)' -complete -f -c git -n '__fish_git_using_command config and __fish_is_first_arg' -l get -d 'Get config with name' -ra '(__fish_git_config_keys)' +complete -c git -n '__fish_git_using_command config; and __fish_is_token_n 3' -fa '(__fish_git_config_keys)' +complete -f -c git -n '__fish_git_using_command config; and __fish_is_first_arg' -l get -d 'Get config with name' -ra '(__fish_git_config_keys)' complete -f -c git -n '__fish_git_using_command config' -l get -d 'Get config with name' -ra '(__fish_git_config_keys)' complete -f -c git -n '__fish_git_using_command config' -l get-all -d 'Get all values matching key' -a '(__fish_git_config_keys)' complete -f -c git -n '__fish_git_using_command config' -l get-urlmatch -d 'Get value specific for the section url' -r @@ -1518,7 +1518,7 @@ complete -f -c git -n '__fish_git_using_command config' -s z -l null -d 'Termina complete -f -c git -n '__fish_git_using_command config' -l name-only -d 'Show variable names only' complete -f -c git -n '__fish_git_using_command config' -l includes -d 'Respect include directives' complete -f -c git -n '__fish_git_using_command config' -l show-origin -d 'Show origin of configuration' -complete -f -c git -n '__fish_git_using_command config and __fish_seen_argument --get' -l default -d 'Use default value when missing entry' +complete -f -c git -n '__fish_git_using_command config; and __fish_seen_argument --get' -l default -d 'Use default value when missing entry' From 88d20e257b5fb87a616b358d9529527756d937af Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Fri, 15 Mar 2019 20:21:05 -0700 Subject: [PATCH 0095/1732] Remove some unused variables --- src/expand.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/expand.cpp b/src/expand.cpp index 2d517bf3c..408176166 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -206,7 +206,6 @@ static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector 0) { From 74a22ff4262b872668d9cca3279eece5b7e49350 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 16 Mar 2019 00:54:44 -0700 Subject: [PATCH 0096/1732] wcsfilecmp: punctuation [\]^_` after A-Z. This tweaks wcsfilecmp such that certain punctuation characters will come after A-Z. A big win with `set ` - the __prefixed fish junk now comes after the stuff users should care about. --- src/util.cpp | 4 ++-- tests/__fish_complete_directories.out | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/util.cpp b/src/util.cpp index 5bb89e5ba..4ca1cec54 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -61,8 +61,8 @@ int wcsfilecmp(const wchar_t *a, const wchar_t *b) { if (retval || *a == 0 || *b == 0) break; } - wint_t al = towlower(*a); - wint_t bl = towlower(*b); + wint_t al = towupper(*a); + wint_t bl = towupper(*b); if (al < bl) { retval = -1; break; diff --git a/tests/__fish_complete_directories.out b/tests/__fish_complete_directories.out index a098be2bb..a19636ac4 100644 --- a/tests/__fish_complete_directories.out +++ b/tests/__fish_complete_directories.out @@ -6,6 +6,8 @@ test/data/ Directory # __fish_complete_directories test/data/ test/data/abc/ Directory test/data/abcd/ Directory +test/data/fish-symlink/ Directory +test/data/fish-symlink2/ Directory test/data/fish/ Directory test/data/xy/ Directory test/data/xyz/ Directory From 6e525cc5d946965a31f74a28ab4dcb20cf01c11d Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 16 Mar 2019 01:08:21 -0700 Subject: [PATCH 0097/1732] wcsfilecmp: sort - after everything else Before this change, - was sorted with other punctuation before A-Z. Now, it sorts above the rest of the characters. This has a practical effect on completions, where when there are both -s and --long with the same description, the short option is now before the long option in the pager, which is what is now selected when navigating `foo -`. The long options can be picked out with `foo --`. Before, short options which duplicated a long option literally could not be selected by any means from the pager. Fixes #5634 --- src/util.cpp | 3 +++ tests/__fish_complete_directories.out | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/util.cpp b/src/util.cpp index 4ca1cec54..0ca0ac7b2 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -63,6 +63,9 @@ int wcsfilecmp(const wchar_t *a, const wchar_t *b) { wint_t al = towupper(*a); wint_t bl = towupper(*b); + if (al == L'-') al += 48; + if (bl == L'-') bl += 48; + if (al < bl) { retval = -1; break; diff --git a/tests/__fish_complete_directories.out b/tests/__fish_complete_directories.out index a19636ac4..6d72a4d55 100644 --- a/tests/__fish_complete_directories.out +++ b/tests/__fish_complete_directories.out @@ -6,9 +6,9 @@ test/data/ Directory # __fish_complete_directories test/data/ test/data/abc/ Directory test/data/abcd/ Directory +test/data/fish/ Directory test/data/fish-symlink/ Directory test/data/fish-symlink2/ Directory -test/data/fish/ Directory test/data/xy/ Directory test/data/xyz/ Directory # __fish_complete_directories test/data/abc From aea406290655a2c94d3d063051291595114995e4 Mon Sep 17 00:00:00 2001 From: SanskritFritz Date: Sun, 17 Mar 2019 10:28:15 +0100 Subject: [PATCH 0098/1732] cower doesn't exist anymore, completions dropped --- share/completions/cower.fish | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 share/completions/cower.fish diff --git a/share/completions/cower.fish b/share/completions/cower.fish deleted file mode 100644 index 9b1c6269d..000000000 --- a/share/completions/cower.fish +++ /dev/null @@ -1,23 +0,0 @@ -complete -c cower -f -s b -l 'brief' -d 'Show output in a more script friendly format' -complete -c cower -f -s d -l 'download' -d 'Download [twice to fetch dependencies]' -complete -c cower -f -s i -l 'info' -d 'Show info for target [twice for more details]' -complete -c cower -f -s m -l 'msearch' -d 'Search for packages by maintainer' -complete -c cower -f -s s -l 'search' -d 'Search for packages by name' -complete -c cower -f -s u -l 'update' -d 'Check AUR packages for updates' -complete -c cower -f -s c -l 'color' -xa 'always auto never' -d 'Use colored output' -complete -c cower -f -s v -l 'debug' -d 'Show debug output' -complete -c cower -f -s f -l 'force' -d 'Overwrite existing files when downloading' -complete -c cower -f -l 'format' -d 'Print formatted' -complete -c cower -f -s h -l 'help' -d 'Display help and quit' -complete -c cower -f -l 'ignore' -xa "(pacman -Qq)" -d 'Ignore a package upgrade' -complete -c cower -f -l 'ignorerepo' -xa "(__fish_print_pacman_repos)" -d 'Ignore a binary repo when checking for updates' -complete -c cower -f -l 'listdelim' -d 'Specify a delimiter for list formatters' -complete -c cower -f -s q -l 'quiet' -d 'Output less' -complete -c cower -f -s t -l 'target' -d 'Download targets to DIR' -complete -c cower -f -l 'threads' -d 'Limit the number of threads created [10]' -complete -c cower -f -l 'timeout' -d 'Curl timeout in seconds' -complete -c cower -f -s v -l 'verbose' -d 'Output more' - -# Complete with AUR packages: -# If the search string is too short, cower prints an annoying message to stderr - ignore that -complete -c cower -f -n 'not string match -q -- "-*" (commandline --current-token)' -a '(cower --format="%n\t%d\n" --search (commandline --current-token) 2>/dev/null)' From 0bde698f819b9352ca246a3b435a72593f50405b Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 17 Mar 2019 16:33:58 +0100 Subject: [PATCH 0099/1732] printf: Don't die on incomplete conversions POSIX dictates here that incomplete conversions, like in printf %d\n 15.2 or printf %d 14g are still printed along with any error. This seems alright, as it allows users to silence stderr to accept incomplete conversions. This commit implements it, but what's a bit weird is the ordering between stdout and stderr, causing the error to be printed _after_, like 15 14 15.1: value not completely converted 14,2: value not completely converted but that seems like a general issue with how we buffer the streams. (I know that nonfatal_error is a copy of most of fatal_error - I tried differently, and va_* is weird) Fixes #5532. --- CHANGELOG.md | 1 + src/builtin_printf.cpp | 27 +++++++++++++++++++++++---- tests/printf.err | 1 + tests/printf.in | 4 ++++ tests/printf.out | 3 +++ 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b92b7ef24..a476b3fb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - `math` now accepts `--scale=max` for the maximum scale (#5579). - `complete --do-complete` now also does fuzzy matches (#5467). - `count` now also counts lines fed on stdin (#5744). +- `printf` prints what it can when input hasn't been fully converted to a number, but still prints an error (#5532). ### Interactive improvements - Major improvements in performance and functionality to the 'sorin' sample prompt (#5411). diff --git a/src/builtin_printf.cpp b/src/builtin_printf.cpp index d12d9c596..09b3a9283 100644 --- a/src/builtin_printf.cpp +++ b/src/builtin_printf.cpp @@ -90,8 +90,10 @@ struct builtin_printf_state_t { int print_formatted(const wchar_t *format, int argc, wchar_t **argv); + void nonfatal_error(const wchar_t *fmt, ...); void fatal_error(const wchar_t *format, ...); + long print_esc(const wchar_t *escstart, bool octal_0); void print_esc_string(const wchar_t *str); void print_esc_char(wchar_t c); @@ -193,6 +195,22 @@ static int octal_to_bin(wchar_t c) { } } +void builtin_printf_state_t::nonfatal_error(const wchar_t *fmt, ...) { + // Don't error twice. + if (early_exit) return; + + va_list va; + va_start(va, fmt); + wcstring errstr = vformat_string(fmt, va); + va_end(va); + streams.err.append(errstr); + if (!string_suffixes_string(L"\n", errstr)) streams.err.push_back(L'\n'); + + // We set the exit code to error, because one occured, + // but we don't do an early exit so we still print what we can. + this->exit_code = STATUS_CMD_ERROR; +} + void builtin_printf_state_t::fatal_error(const wchar_t *fmt, ...) { // Don't error twice. if (early_exit) return; @@ -207,7 +225,6 @@ void builtin_printf_state_t::fatal_error(const wchar_t *fmt, ...) { this->exit_code = STATUS_CMD_ERROR; this->early_exit = true; } - void builtin_printf_state_t::append_output(wchar_t c) { // Don't output if we're done. if (early_exit) return; @@ -241,10 +258,12 @@ void builtin_printf_state_t::verify_numeric(const wchar_t *s, const wchar_t *end this->fatal_error(L"%ls: %s", s, std::strerror(errcode)); } } else if (*end) { - if (s == end) + if (s == end) { this->fatal_error(_(L"%ls: expected a numeric value"), s); - else - this->fatal_error(_(L"%ls: value not completely converted"), s); + } else { + // This isn't entirely fatal - the value should still be printed. + this->nonfatal_error(_(L"%ls: value not completely converted"), s); + } } } diff --git a/tests/printf.err b/tests/printf.err index 40686c8f9..d8d4de233 100644 --- a/tests/printf.err +++ b/tests/printf.err @@ -1,2 +1,3 @@ 2,34: value not completely converted 0xABCDEF12345678901: Number out of range +15.1: value not completely converted diff --git a/tests/printf.in b/tests/printf.in index 9c8b9f9a8..d7174253e 100644 --- a/tests/printf.in +++ b/tests/printf.in @@ -72,3 +72,7 @@ printf 'long hex4 %X\n' 0xABCDEF12345678901 printf 'long decimal %d\n' 498216206594 printf 'long signed %d\n' -498216206595 printf 'long signed to unsigned %u\n' -498216206596 + +# Verify numeric conversion still happens even if it couldn't be fully converted +printf '%d\n' 15.1 +echo $status diff --git a/tests/printf.out b/tests/printf.out index b965be413..40f19f791 100644 --- a/tests/printf.out +++ b/tests/printf.out @@ -16,6 +16,7 @@ a 0000000 376 0000001 1.230000e+00 +2.000000e+00 3,450000e+00 4,560000e+00 long hex1 73ffffff9a @@ -24,3 +25,5 @@ long hex3 ABCDEF1234567890 long hex4 long decimal 498216206594 long signed -498216206595 long signed to unsigned 18446743575493345020 +15 +1 From a58662dd46a6903e20ee0fc9e2cab33b1ada8f19 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 17 Mar 2019 12:47:24 -0700 Subject: [PATCH 0100/1732] Make maybe_t conditionally copyable This allows it to be used with both e.g. unique_ptr and std::vector. --- src/fish_tests.cpp | 16 ++++ src/maybe.h | 184 +++++++++++++++++++++++++++++++-------------- 2 files changed, 145 insertions(+), 55 deletions(-) diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 52692f0bc..364701fe0 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -5015,6 +5015,22 @@ void test_maybe() { std::string res = acquire_test.acquire(); do_test(!acquire_test); do_test(res == "def"); + + // maybe_t should be copyable iff T is copyable. + using copyable = std::shared_ptr; + using noncopyable = std::unique_ptr; + do_test(std::is_copy_assignable>::value == true); + do_test(std::is_copy_constructible>::value == true); + do_test(std::is_copy_assignable>::value == false); + do_test(std::is_copy_constructible>::value == false); + + maybe_t c1{"abc"}; + maybe_t c2 = c1; + do_test(c1.value() == "abc"); + do_test(c2.value() == "abc"); + c2 = c1; + do_test(c1.value() == "abc"); + do_test(c2.value() == "abc"); } void test_layout_cache() { diff --git a/src/maybe.h b/src/maybe.h index 7f3f96cde..a3e5cebda 100644 --- a/src/maybe.h +++ b/src/maybe.h @@ -2,6 +2,116 @@ #define FISH_MAYBE_H #include +#include + +namespace maybe_detail { +// Template magic to make maybe_t copyable iff T is copyable. +// maybe_impl_t is the "too aggressive" implementation: it is always copyable. +template +struct maybe_impl_t { + alignas(T) char storage[sizeof(T)]; + bool filled = false; + + T &value() { + assert(filled && "maybe_t does not have a value"); + return *reinterpret_cast(storage); + } + + const T &value() const { + assert(filled && "maybe_t does not have a value"); + return *reinterpret_cast(storage); + } + + void reset() { + if (this->filled) { + value().~T(); + this->filled = false; + } + } + + T acquire() { + assert(filled && "maybe_t does not have a value"); + T res = std::move(value()); + reset(); + return res; + } + + maybe_impl_t() = default; + + // Move construction/assignment from a T. + explicit maybe_impl_t(T &&v) : filled(true) { new (storage) T(std::forward(v)); } + maybe_impl_t &operator=(T &&v) { + if (filled) { + value() = std::move(v); + } else { + new (storage) T(std::move(v)); + filled = true; + } + return *this; + } + + // Copy construction/assignment from a T. + explicit maybe_impl_t(const T &v) : filled(true) { new (storage) T(v); } + maybe_impl_t &operator=(const T &v) { + if (filled) { + value() = v; + } else { + new (storage) T(v); + filled = true; + } + return *this; + } + + // Move construction/assignment from a maybe_impl. + maybe_impl_t(maybe_impl_t &&v) : filled(v.filled) { + if (filled) { + new (storage) T(std::move(v.value())); + } + } + maybe_impl_t &operator=(maybe_impl_t &&v) { + if (!v.filled) { + reset(); + } else { + *this = std::move(v.value()); + } + return *this; + } + + // Copy construction/assignment from a maybe_impl. + maybe_impl_t(const maybe_impl_t &v) : filled(v.filled) { + if (v.filled) { + new (storage) T(v.value()); + } + } + maybe_impl_t &operator=(const maybe_impl_t &v) { + if (&v == this) return *this; + if (!v.filled) { + reset(); + } else { + *this = v.value(); + } + return *this; + } + + ~maybe_impl_t() { reset(); } +}; + +struct copyable_t {}; +struct noncopyable_t { + noncopyable_t() = default; + noncopyable_t(noncopyable_t &&) = default; + noncopyable_t &operator=(noncopyable_t &&) = default; + noncopyable_t(const noncopyable_t &) = delete; + noncopyable_t &operator=(const noncopyable_t &) = delete; +}; + +// conditionally_copyable_t is copyable iff T is copyable. +// This enables conditionally copyable wrapper types by inheriting from it. +template +using conditionally_copyable_t = typename std::conditional::value, + copyable_t, noncopyable_t>::type; + +}; // namespace maybe_detail // A none_t is a helper type used to implicitly initialize maybe_t. // Example usage: @@ -15,16 +125,15 @@ inline constexpr none_t none() { return none_t::none; } // Support for a maybe, also known as Optional. // This is a value-type class that stores a value of T in aligned storage. template -class maybe_t { - alignas(T) char storage[sizeof(T)]; - bool filled = false; +class maybe_t : private maybe_detail::conditionally_copyable_t { + maybe_detail::maybe_impl_t impl_; public: // return whether the receiver contains a value. - bool has_value() const { return filled; } + bool has_value() const { return impl_.filled; } // bool conversion indicates whether the receiver contains a value. - explicit operator bool() const { return filled; } + explicit operator bool() const { return impl_.filled; } // The default constructor constructs a maybe with no value. maybe_t() = default; @@ -33,79 +142,46 @@ class maybe_t { /* implicit */ maybe_t(none_t n) { (void)n; } // Construct a maybe_t from a value T. - /* implicit */ maybe_t(T &&v) : filled(true) { new (storage) T(std::forward(v)); } + /* implicit */ maybe_t(T &&v) : impl_(std::move(v)) {} // Construct a maybe_t from a value T. - /* implicit */ maybe_t(const T &v) : filled(true) { new (storage) T(v); } + /* implicit */ maybe_t(const T &v) : impl_(v) {} // Copy constructor. - maybe_t(const maybe_t &v) : filled(v.filled) { - if (v.filled) { - new (storage) T(v.value()); - } - } + maybe_t(const maybe_t &v) = default; // Move constructor. - /* implicit */ maybe_t(maybe_t &&v) : filled(v.filled) { - if (v.filled) { - new (storage) T(std::move(v.value())); - } - } + /* implicit */ maybe_t(maybe_t &&v) = default; // Construct a value in-place. template void emplace(Args &&... args) { reset(); - filled = true; - new (storage) T(std::forward(args)...); + impl_.filled = true; + new (impl_.storage) T(std::forward(args)...); } // Access the value. - T &value() { - assert(filled && "maybe_t does not have a value"); - return *reinterpret_cast(storage); - } + T &value() { return impl_.value(); } - const T &value() const { - assert(filled && "maybe_t does not have a value"); - return *reinterpret_cast(storage); - } + const T &value() const { return impl_.value(); } // Transfer the value to the caller. - T acquire() { - assert(filled && "maybe_t does not have a value"); - T res = std::move(value()); - reset(); - return res; - } + T acquire() { return impl_.acquire(); } // Clear the value. - void reset() { - if (filled) { - value().~T(); - filled = false; - } - } + void reset() { impl_.reset(); } // Assign a new value. maybe_t &operator=(T &&v) { - if (filled) { - value() = std::move(v); - } else { - new (storage) T(std::move(v)); - filled = true; - } + impl_ = std::move(v); return *this; } - maybe_t &operator=(maybe_t &&v) { - if (!v) { - reset(); - } else { - *this = std::move(*v); - } - return *this; - } + // Note that defaulting these allows these to be conditionally deleted via + // conditionally_copyable_t(). + maybe_t &operator=(const maybe_t &v) = default; + maybe_t &operator=(maybe_t &&v) = default; // Dereference support. const T *operator->() const { return &value(); } @@ -127,8 +203,6 @@ class maybe_t { } bool operator!=(const maybe_t &rhs) const { return !(*this == rhs); } - - ~maybe_t() { reset(); } }; #endif From 03454b7dcd88ae713a6e213f918a367f05778fda Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Tue, 12 Mar 2019 09:52:46 -0700 Subject: [PATCH 0101/1732] Use a real struct type in fish_indent pending node stack --- src/fish_indent.cpp | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/fish_indent.cpp b/src/fish_indent.cpp index 01d3a3b94..c40c2fb24 100644 --- a/src/fish_indent.cpp +++ b/src/fish_indent.cpp @@ -99,9 +99,8 @@ struct prettifier_t { prettifier_t(const wcstring &source, bool do_indent) : source(source), do_indent(do_indent) {} - void prettify_node_nrecursive(const parse_node_tree_t &tree, - node_offset_t node_idx, indent_t node_indent, - parse_token_type_t parent_type); + void prettify_node(const parse_node_tree_t &tree, node_offset_t node_idx, indent_t node_indent, + parse_token_type_t parent_type); void maybe_prepend_escaped_newline(const parse_node_t &node) { if (node.has_preceding_escaped_newline()) { @@ -162,20 +161,23 @@ static void dump_node(indent_t node_indent, const parse_node_t &node, const wcst token_type_description(node.type), prevc_str, source_txt.c_str(), nextc_str); } -void prettifier_t::prettify_node_nrecursive(const parse_node_tree_t &tree, - node_offset_t node_idx, indent_t node_indent, - parse_token_type_t parent_type) { +void prettifier_t::prettify_node(const parse_node_tree_t &tree, node_offset_t node_idx, + indent_t node_indent, parse_token_type_t parent_type) { + // Use an explicit stack to avoid stack overflow. + struct pending_node_t { + node_offset_t index; + indent_t indent; + parse_token_type_t parent_type; + }; + std::stack pending_node_stack; - using call_tuple_t = std::tuple; - std::stack explicit_stack; - explicit_stack.push(std::make_tuple(node_idx, node_indent, parent_type)); - while(!explicit_stack.empty()){ - - call_tuple_t arguments = explicit_stack.top(); - explicit_stack.pop(); - auto node_idx = std::get<0>(arguments); - auto node_indent = std::get<1>(arguments); - auto parent_type = std::get<2>(arguments); + pending_node_stack.push({node_idx, node_indent, parent_type}); + while (!pending_node_stack.empty()) { + pending_node_t args = pending_node_stack.top(); + pending_node_stack.pop(); + auto node_idx = args.index; + auto node_indent = args.indent; + auto parent_type = args.parent_type; const parse_node_t &node = tree.at(node_idx); const parse_token_type_t node_type = node.type; @@ -236,7 +238,7 @@ void prettifier_t::prettify_node_nrecursive(const parse_node_tree_t &tree, // Note: We pass our type to our child, which becomes its parent node type. // Note: While node.child_start could be -1 (NODE_OFFSET_INVALID) the addition is safe // because we won't execute this call in that case since node.child_count should be zero. - explicit_stack.push(std::make_tuple(node.child_start + (idx - 1), node_indent, node_type)); + pending_node_stack.push({node.child_start + (idx - 1), node_indent, node_type}); } } } @@ -262,7 +264,7 @@ static wcstring prettify(const wcstring &src, bool do_indent) { const parse_node_t &node = parse_tree.at(i); if (node.parent == NODE_OFFSET_INVALID || node.type == parse_special_type_parse_error) { // A root node. - prettifier.prettify_node_nrecursive(parse_tree, i, 0, symbol_job_list); + prettifier.prettify_node(parse_tree, i, 0, symbol_job_list); } } return std::move(prettifier.output); From 69abbd7b2a9d0c97089d2fb86445acc291c353af Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 18 Mar 2019 17:09:48 +0100 Subject: [PATCH 0102/1732] docs: Mention $__fish_x_dir in autoloading chapter That's what we want people to use instead of hardcoding "/usr/share/fish", because that would break the code on other systems. [ci skip] --- sphinx_doc_src/index.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index 562d9c3f1..349aee5e1 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -452,9 +452,10 @@ Fish automatically searches through any directories in the array variable ``$fis By default, Fish searches the following for functions, using the first available file that it finds: - A directory for end-users to keep their own functions, usually ``~/.config/fish/functions`` (controlled by the ``XDG_CONFIG_HOME`` environment variable). -- A directory for systems administrators to install functions for all users on the system, usually ``/etc/fish/functions``. +- A directory for systems administrators to install functions for all users on the system, usually ``/etc/fish/functions`` (really ``$__fish_sysconfdir/functions``). - A directory for third-party software vendors to ship their own functions for their software, usually ``/usr/share/fish/vendor_functions.d``. -- The functions shipped with fish, usually installed in ``/usr/share/fish/functions``. + (set at compile time; by default, ``$__fish_data_dir/vendor_functions.d``) +- The functions shipped with fish, usually installed in ``/usr/share/fish/functions`` (really ``$__fish_data_dir/functions``). These paths are controlled by parameters set at build, install, or run time, and may vary from the defaults listed above. @@ -1581,7 +1582,7 @@ Configuration files are evaluated in the following order: - Configuration snippets in files ending in ``.fish``, in the directories: - ``$__fish_config_dir/conf.d`` (by default, ``~/.config/fish/conf.d/``) - ``$__fish_sysconf_dir/conf.d`` (by default, ``/etc/fish/conf.d``) - - ``/usr/share/fish/vendor_conf.d`` (set at compile time; by default, ``$__fish_data_dir/conf.d``) + - ``/usr/share/fish/vendor_conf.d`` (set at compile time; by default, ``$__fish_data_dir/vendor_conf.d``) If there are multiple files with the same name in these directories, only the first will be executed. They are executed in order of their filename, sorted (like globs) in a natural order (i.e. "01" sorts before "2"). From 805a8db7ef83a1ed409ad8b21095a665cd395d0c Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 18 Mar 2019 22:25:58 +0100 Subject: [PATCH 0103/1732] functions/fish_hg_prompt: Show untracked files Apparently "status --quiet" actually inhibits showing untracked files, which explains why it's 20% faster (though it's quite weird use of that option!) Fixes #5749. [ci skip] --- share/functions/fish_hg_prompt.fish | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/share/functions/fish_hg_prompt.fish b/share/functions/fish_hg_prompt.fish index 584695f54..93c4d102b 100644 --- a/share/functions/fish_hg_prompt.fish +++ b/share/functions/fish_hg_prompt.fish @@ -38,9 +38,8 @@ function fish_hg_prompt --description 'Write out the hg prompt' echo -n '|' - # For some reason, "-q" still prints the same output, but ~20% faster. # Disabling color and pager is always a good idea. - set -l repo_status (hg status -q --color never --pager never | string sub -l 2 | sort -u) + set -l repo_status (hg status --color never --pager never | string sub -l 2 | sort -u) # Show nice color for a clean repo if test -z "$repo_status" From f56bce3f977182710762a1501ec52de3ddaa29d2 Mon Sep 17 00:00:00 2001 From: ykai Date: Tue, 19 Mar 2019 13:55:52 +0800 Subject: [PATCH 0104/1732] Fixed `mount -o` exception --- .../functions/__fish_complete_mount_opts.fish | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/share/functions/__fish_complete_mount_opts.fish b/share/functions/__fish_complete_mount_opts.fish index 9afc4020b..378262d8e 100644 --- a/share/functions/__fish_complete_mount_opts.fish +++ b/share/functions/__fish_complete_mount_opts.fish @@ -140,21 +140,22 @@ function __fish_complete_mount_opts set -l token (commandline -tc | string replace -r '^-o' -- '') set -l args (string split , -- $token) - set -l last_arg $args[-1] - set -e args[-1] + if test (count $args) -ne 0 + set -l last_arg $args[-1] + set -e args[-1] - switch (string replace -r '=.*' '=' -- $last_arg) - case uid= - set -a fish_mount_opts uid=(__fish_print_user_ids) - case gid= - set -a fish_mount_opts gid=(__fish_print_group_ids) - case setuid= - set -a fish_mount_opts setuid=(__fish_print_user_ids) - case setgid= - set -a fish_mount_opts setgid=(__fish_print_group_ids) + switch (string replace -r '=.*' '=' -- $last_arg) + case uid= + set -a fish_mount_opts uid=(__fish_print_user_ids) + case gid= + set -a fish_mount_opts gid=(__fish_print_group_ids) + case setuid= + set -a fish_mount_opts setuid=(__fish_print_user_ids) + case setgid= + set -a fish_mount_opts setgid=(__fish_print_group_ids) + end end - set -l prefix '' if set -q args[1] set prefix (string join , -- $args), From 05ef157757c37db603b71bc9f755af31790d549a Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 19 Mar 2019 10:05:39 +0100 Subject: [PATCH 0105/1732] functions/fish_git_prompt: Let helper functions return useful status If you use these to figure out if there _are_ staged files, or dirty or whatever, you currently need to check the output, which relies on the configured character. Instead, we let them also return a useful status. Notably, this is *not* simply the status of the git call. __fish_git_prompt_X returns 0 if the repo is X. This works for untracked, but the "diff" things return 1 if there is a diff, so we invert the status for them. See #5748. [ci skip] --- share/functions/fish_git_prompt.fish | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/share/functions/fish_git_prompt.fish b/share/functions/fish_git_prompt.fish index 6ee0a8e5c..19effdd62 100644 --- a/share/functions/fish_git_prompt.fish +++ b/share/functions/fish_git_prompt.fish @@ -485,36 +485,45 @@ end function __fish_git_prompt_staged --description "fish_git_prompt helper, tells whether or not the current branch has staged files" set -l sha $argv[1] - set -l staged + set -l ret 0 if test -n "$sha" - command git diff-index --cached --quiet HEAD -- 2>/dev/null - or set staged $___fish_git_prompt_char_stagedstate + # The "diff" functions all return > 0 if there _is_ a diff, + # but we want to return 0 if there are staged changes. + # So we invert the status. + not command git diff-index --cached --quiet HEAD -- 2>/dev/null + and set staged $___fish_git_prompt_char_stagedstate + set ret $status else set staged $___fish_git_prompt_char_invalidstate + set ret 2 end echo $staged + return $ret end function __fish_git_prompt_untracked --description "fish_git_prompt helper, tells whether or not the current repository has untracked files" - set -l untracked + set -l ret 1 if command git ls-files --others --exclude-standard --directory --no-empty-directory --error-unmatch -- :/ >/dev/null 2>&1 + set ret $status set untracked $___fish_git_prompt_char_untrackedfiles end echo $untracked + return $ret end function __fish_git_prompt_dirty --description "fish_git_prompt helper, tells whether or not the current branch has tracked, modified files" set -l dirty - set -l os - command git diff --no-ext-diff --quiet --exit-code 2>/dev/null - set os $status - if test $os -ne 0 + # Like staged, invert the status because we want 0 to mean there are dirty files. + not command git diff --no-ext-diff --quiet --exit-code 2>/dev/null + set -l os $status + if test $os -eq 0 set dirty $___fish_git_prompt_char_dirtystate end echo $dirty + return $os end set -g ___fish_git_prompt_status_order stagedstate invalidstate dirtystate untrackedfiles From 632c47be5466eef6bd503168236ff607ab5dabbd Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 19 Mar 2019 10:24:10 +0100 Subject: [PATCH 0106/1732] functions/fish_git_prompt: Remove literal tabs --- share/functions/fish_git_prompt.fish | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/share/functions/fish_git_prompt.fish b/share/functions/fish_git_prompt.fish index 19effdd62..9b0a20539 100644 --- a/share/functions/fish_git_prompt.fish +++ b/share/functions/fish_git_prompt.fish @@ -281,7 +281,7 @@ function __fish_git_prompt_show_upstream --description "Helper function for fish end # Find how many commits we are ahead/behind our upstream - set count (command git rev-list --count --left-right $upstream...HEAD 2>/dev/null) + set count (command git rev-list --count --left-right $upstream...HEAD 2>/dev/null | string replace \t " ") # calculate the result if test -n "$verbose" @@ -295,11 +295,11 @@ function __fish_git_prompt_show_upstream --description "Helper function for fish echo $count | read -l behind ahead switch "$count" case '' # no upstream - case "0 0" # equal to upstream + case "0 0" # equal to upstream echo "$prefix$___fish_git_prompt_char_upstream_equal" - case "0 *" # ahead of upstream + case "0 *" # ahead of upstream echo "$prefix$___fish_git_prompt_char_upstream_ahead$ahead" - case "* 0" # behind upstream + case "* 0" # behind upstream echo "$prefix$___fish_git_prompt_char_upstream_behind$behind" case '*' # diverged from upstream echo "$prefix$___fish_git_prompt_char_upstream_diverged$ahead-$behind" @@ -311,10 +311,10 @@ function __fish_git_prompt_show_upstream --description "Helper function for fish echo $count | read -l behind ahead switch "$count" case '' # no upstream - case "0 0" # equal to upstream - case "0 *" # ahead of upstream + case "0 0" # equal to upstream + case "0 *" # ahead of upstream echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead" - case "* 0" # behind upstream + case "* 0" # behind upstream echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind" case '*' # diverged from upstream echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead$___fish_git_prompt_char_upstream_behind$behind" @@ -322,11 +322,11 @@ function __fish_git_prompt_show_upstream --description "Helper function for fish else switch "$count" case '' # no upstream - case "0 0" # equal to upstream + case "0 0" # equal to upstream echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_equal" - case "0 *" # ahead of upstream + case "0 *" # ahead of upstream echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead" - case "* 0" # behind upstream + case "* 0" # behind upstream echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind" case '*' # diverged from upstream echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_diverged" From f6226f08027c7b71b72563f94cbd832d2da8d245 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 19 Mar 2019 10:24:40 +0100 Subject: [PATCH 0107/1732] functions/fish_git_prompt: Useful status for show_upstream Returns 0 if there is no diversion, 1 otherwise. --- share/functions/fish_git_prompt.fish | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/functions/fish_git_prompt.fish b/share/functions/fish_git_prompt.fish index 9b0a20539..ef839c611 100644 --- a/share/functions/fish_git_prompt.fish +++ b/share/functions/fish_git_prompt.fish @@ -332,6 +332,9 @@ function __fish_git_prompt_show_upstream --description "Helper function for fish echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_diverged" end end + + # For the return status + test "$count" = "0 0" end function fish_git_prompt --description "Prompt function for Git" From a649c5293e0e03560a4c7c909688a9baae7f2f9b Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 19 Mar 2019 10:27:25 +0100 Subject: [PATCH 0108/1732] functions/fish_git_prompt: Fix space prefix for verbose showupstream This created another local version of the variable just for the if-block. Can't say I love the space prefix, but then I think we have too many of these modes anyway. --- share/functions/fish_git_prompt.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/functions/fish_git_prompt.fish b/share/functions/fish_git_prompt.fish index ef839c611..cf3623bfa 100644 --- a/share/functions/fish_git_prompt.fish +++ b/share/functions/fish_git_prompt.fish @@ -289,7 +289,7 @@ function __fish_git_prompt_show_upstream --description "Helper function for fish set -l prefix "$___fish_git_prompt_char_upstream_prefix" # Using two underscore version to check if user explicitly set to nothing if not set -q __fish_git_prompt_char_upstream_prefix - set -l prefix " " + set prefix " " end echo $count | read -l behind ahead From f8b88d5b98d8f4f9a521b827d1d9527a572161d4 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 19 Mar 2019 21:07:49 +0100 Subject: [PATCH 0109/1732] docs/fish_git_prompt: Better document variables More accurate, also the code example can now be copy-pasted. [ci skip] --- sphinx_doc_src/cmds/fish_git_prompt.rst | 62 +++++++++++++------------ 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/sphinx_doc_src/cmds/fish_git_prompt.rst b/sphinx_doc_src/cmds/fish_git_prompt.rst index 298e436ae..08b1cb9b5 100644 --- a/sphinx_doc_src/cmds/fish_git_prompt.rst +++ b/sphinx_doc_src/cmds/fish_git_prompt.rst @@ -10,20 +10,20 @@ For obvious reasons, it requires having git installed. There are numerous configuration options, either as fish variables or git config variables. If a git config variable is supported, it will be used if set, and the fish variable will only be used if it isn't. +- $__fish_git_prompt_show_informative_status or the git config option "bash.showInformativeStatus" can be set to enable the "informative" display, which will show a large amount of information - the number of untracked files, dirty files, unpushed/unpulled commits, etc... In large repositories, this can take a lot of time, so it is recommended to disable it there, via ``git config bash.showInformativeStatus false``. + - $__fish_git_prompt_showdirtystate or the git config option "bash.showDirtyState" can be set to show if the repository is "dirty", i.e. has uncommitted changes. - $__fish_git_prompt_showuntrackedfiles or the git config option "bash.showUntrackedFiles" can be set to show if the repository has untracked files (that aren't ignored). -- $__fish_git_prompt_show_informative_status or the git config option "bash.showInformativeStatus" can be set to enable the "informative" display, which will show a large amount of information - the number of untracked files, dirty files, unpushed/unpulled commits, etc... In large repositories, this can take a lot of time, so it is recommended to disable it there. - - $__fish_git_prompt_showupstream can be set to a number of values to determine how changes between HEAD and upstream are shown: verbose show number of commits ahead/behind (+/-) upstream name if verbose, then also show the upstream abbrev name - informative similar to verbose, but shows nothing when equal (fish only) + informative similar to verbose, but shows nothing when equal - this is the default if show_informative_status is set. git always compare HEAD to @{upstream} svn always compare HEAD to your SVN upstream - none disables (fish only, useful with show_informative_status) + none disables (useful with show_informative_status) - $__fish_git_prompt_showstashstate can be set to display the state of the stash. @@ -38,44 +38,48 @@ There are numerous configuration options, either as fish variables or git config - $__fish_git_prompt_showcolorhints can be set to enable coloring for certain things. -A number of variables to set characters and color used to indicate things. +A number of variables to set characters and color used to indicate things. Many of these have a different default if used with informative status enabled. -- $__fish_git_prompt_char_cleanstate -- $__fish_git_prompt_char_dirtystate -- $__fish_git_prompt_char_invalidstate -- $__fish_git_prompt_char_stagedstate -- $__fish_git_prompt_char_stashstate - $__fish_git_prompt_char_stateseparator -- $__fish_git_prompt_char_untrackedfiles -- $__fish_git_prompt_char_upstream_ahead -- $__fish_git_prompt_char_upstream_behind -- $__fish_git_prompt_char_upstream_diverged -- $__fish_git_prompt_char_upstream_equal -- $__fish_git_prompt_char_upstream_prefix - $__fish_git_prompt_color - $__fish_git_prompt_color_prefix - $__fish_git_prompt_color_suffix - $__fish_git_prompt_color_bare - $__fish_git_prompt_color_merging + +Some variables are only used in some modes, like when informative status is enabled (by setting $__fish_git_prompt_show_informative_status): +- $__fish_git_prompt_char_cleanstate - $__fish_git_prompt_color_cleanstate + +Variables used with showdirtystate: +- $__fish_git_prompt_char_dirtystate +- $__fish_git_prompt_char_invalidstate +- $__fish_git_prompt_char_stagedstate +- $__fish_git_prompt_color_dirtystate - $__fish_git_prompt_color_invalidstate +- $__fish_git_prompt_color_stagedstate + +Variables used with showstashstate: +- $__fish_git_prompt_char_stashstate +- $__fish_git_prompt_color_stashstate + +Variables used with showuntrackedfiles: +- $__fish_git_prompt_char_untrackedfiles +- $__fish_git_prompt_color_untrackedfiles + +Variables used with showupstream (also implied by informative status): +- $__fish_git_prompt_char_upstream_ahead +- $__fish_git_prompt_char_upstream_behind +- $__fish_git_prompt_char_upstream_diverged +- $__fish_git_prompt_char_upstream_equal +- $__fish_git_prompt_char_upstream_prefix - $__fish_git_prompt_color_upstream Colors used with showcolorhints: - -- $__fish_git_prompt_color_flags - $__fish_git_prompt_color_branch -- $__fish_git_prompt_color_dirtystate -- $__fish_git_prompt_color_stagedstate -- $__fish_git_prompt_color_flags -- $__fish_git_prompt_color_branch -- $__fish_git_prompt_color_dirtystate -- $__fish_git_prompt_color_stagedstate - $__fish_git_prompt_color_branch_detached - -Colors used with their respective flags enabled: -- $__fish_git_prompt_color_stashstate -- $__fish_git_prompt_color_untrackedfiles +- $__fish_git_prompt_color_dirtystate +- $__fish_git_prompt_color_flags Note that all colors can also have a corresponding "_done" color. E.g. $__fish_git_prompt_color_upstream_done, used right _after_ the upstream. @@ -87,7 +91,7 @@ Example A simple prompt that displays git info:: function fish_prompt - ... + # ... set -g __fish_git_prompt_showupstream auto printf '%s %s$' $PWD (fish_git_prompt) end From 1a53bbeb9d35831ee21a9930b17c3c77ebd61ef9 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 20 Mar 2019 08:54:40 +0100 Subject: [PATCH 0110/1732] src/fallback: Include locale.h for the wcstod_l fallback Fixes #5753. --- src/fallback.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fallback.cpp b/src/fallback.cpp index 722338c04..64bbc1920 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -397,6 +397,7 @@ int flock(int fd, int op) { #if !defined(HAVE_WCSTOD_L) && !defined(__NetBSD__) #undef wcstod_l +#include // For platforms without wcstod_l C extension, wrap wcstod after changing the // thread-specific locale. double fish_compat::wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc) { From a8b01e1c996a90cae7f4801ed7206a5913bf1021 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 20 Mar 2019 09:01:20 +0100 Subject: [PATCH 0111/1732] src/output: Unconst-cast tputs Fixes the build on Solaris/OpenIndiana/Illumos. --- src/output.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/output.cpp b/src/output.cpp index ddabac3b4..64db9fba8 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -357,7 +357,9 @@ int outputter_t::term_puts(const char *str, int affcnt) { // scoped_push will restore it. scoped_lock locker{s_tputs_receiver_lock}; scoped_push push(&s_tputs_receiver, this); - return tputs(str, affcnt, tputs_writer); + // On some systems, tputs takes a char*, on others a const char*. + // Like tparm, we just cast it to unconst, that should work everywhere. + return tputs((char *)str, affcnt, tputs_writer); } /// Write a wide character to the outputter. This should only be used when writing characters from From f2896b2d83c473bbd0d429cf08f7f86d9c388733 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 20 Mar 2019 20:51:22 -0500 Subject: [PATCH 0112/1732] Fix junk memory read introduced in 1cd5b2f4e100cc18d70d3e37aca747a61ca42f3f The commit began passing the length of the wide string rather than the length of the narrowed string after conversion via `wcstombs`. We *do* have the actual length, but it's not (necessarily) the same as the original value. We need to pass the result of `wcstombs` instead. --- src/output.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/output.cpp b/src/output.cpp index 64db9fba8..1fadaa34a 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -127,7 +127,7 @@ bool outputter_t::write_color(rgb_color_t color, bool is_fg) { /// Since the terminfo string this function emits can potentially cause the screen to flicker, the /// function takes care to write as little as possible. /// -/// Possible values for colors are rgb_color_t colors or special values like rgb_color_t::normal() +/// Possible values for colors are rgb_color_t colors or special values like rgb_color_t::normal() /// /// In order to set the color to normal, three terminfo strings may have to be written. /// @@ -411,8 +411,9 @@ void outputter_t::writestr(const wchar_t *str) { } else { buffer = new char[len]; } - wcstombs(buffer, str, len); - this->writestr(buffer, len); + + int new_len = wcstombs(buffer, str, len); + this->writestr(buffer, new_len); if (buffer != static_buffer) delete[] buffer; } From 4aded78fc9b21486ce9362b9b56e76e762007aa3 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Tue, 29 Jan 2019 19:59:41 -0600 Subject: [PATCH 0113/1732] Add `is_console_session()` to detect physical vty --- src/common.cpp | 24 ++++++++++++++++++++++++ src/common.h | 4 +++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/common.cpp b/src/common.cpp index 3728ff269..5cd37f06e 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -2482,3 +2482,27 @@ std::string get_path_to_tmp_dir() { return "/tmp"; #endif } + +// This function attempts to distinguish between a console session (at the actual login vty) and a +// session within a terminal emulator inside a desktop environment or over SSH. Unfortunately +// there are few values of $TERM that we can interpret as being exclusively console sessions, and +// most common operating systems do not use them. The value is cached for the duration of the fish +// session. We err on the side of assuming it's not a console session. This approach isn't +// bullet-proof and that's OK. +bool is_console_session() { + static bool console_session = []() { + ASSERT_IS_MAIN_THREAD(); + + const char *tty_name = ttyname(0); + auto len = strlen("/dev/tty"); + const char *TERM = getenv("TERM"); + return + // Test that the tty matches /dev/(console|dcons|tty[uv\d]) + tty_name && ((strncmp(tty_name, "/dev/tty", len) == 0 && + (tty_name[len] == 'u' || tty_name[len] == 'v' || isdigit(tty_name[len]))) + || strcmp(tty_name, "/dev/dcons") == 0 || strcmp(tty_name, "/dev/console") == 0) + // and that $TERM is simple, e.g. `xterm` or `vt100`, not `xterm-something` + && (!TERM || !strchr(TERM, '-') || !strcmp(TERM, "sun-color")); + }(); + return console_session; +} diff --git a/src/common.h b/src/common.h index c5522713d..811901ad1 100644 --- a/src/common.h +++ b/src/common.h @@ -1048,4 +1048,6 @@ struct cleanup_t { } }; -#endif +bool is_console_session(); + +#endif // FISH_COMMON_H From da8e34307658b482532f66ae74165649fb893472 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Tue, 29 Jan 2019 20:00:09 -0600 Subject: [PATCH 0114/1732] Use is_console_session() to signal using system `wcwidth()` The system version of `wcwidth()` reflects the capabilities of the system's own virtual terminal's view of the width of the character in question, while fish's enhanced version (`widechar_wcwidth`) is much too smart for most login terminals, which generally barely support anything beyond ASCII text. If, at startup, it is detected that we are running under a physical console rather than within a terminal emulator running in a desktop environment, take that as a hint to use the system-provided `wcwidth`. --- src/fallback.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/fallback.cpp b/src/fallback.cpp index 64bbc1920..870f81787 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -279,6 +279,13 @@ int fish_wcswidth(const wchar_t *str, size_t n) { return wcswidth(str, n); } #include "widecharwidth/widechar_width.h" int fish_wcwidth(wchar_t wc) { + // The system version of wcwidth should accurately reflect the ability to represent characters + // in the console session, but knows nothing about the capabilities of other terminal emulators + // or ttys. Use it from the start only if we are logged in to the physical console. + if (is_console_session()) { + return wcwidth(wc); + } + // Check for VS16 which selects emoji presentation. This "promotes" a character like U+2764 // (width 1) to an emoji (probably width 2). So treat it as width 1 so the sums work. See #2652. // VS15 selects text presentation. @@ -292,6 +299,7 @@ int fish_wcwidth(wchar_t wc) { // we take the position that the typical way for them to show up is composed. if (wc >= L'\u1160' && wc <= L'\u11FF') return 0; int width = widechar_wcwidth(wc); + switch (width) { case widechar_nonprint: case widechar_combining: From 753d489376d480b92b5e587664229c2fef6f95b9 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 30 Jan 2019 14:31:11 -0600 Subject: [PATCH 0115/1732] Fall back to simpler special characters in console sessions --- src/common.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/common.cpp b/src/common.cpp index 5cd37f06e..11b1ff8d5 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -576,11 +576,15 @@ void fish_setlocale() { ellipsis_char = L'$'; // "horizontal ellipsis" ellipsis_str = L"..."; } + if (is_windows_subsystem_for_linux()) { // neither of \u23CE and \u25CF can be displayed in the default fonts on Windows, though // they can be *encoded* just fine. Use alternative glyphs. omitted_newline_char = can_be_encoded(L'\u00b6') ? L'\u00b6' : L'~'; // "pilcrow" obfuscation_read_char = can_be_encoded(L'\u2022') ? L'\u2022' : L'*'; // "bullet" + } else if (is_console_session()) { + omitted_newline_char = L'@'; + obfuscation_read_char = L'*'; } else { omitted_newline_char = can_be_encoded(L'\u23CE') ? L'\u23CE' : L'~'; // "return" obfuscation_read_char = can_be_encoded(L'\u25CF') ? L'\u25CF' : L'#'; // "black circle" From c50cce298d602cbf2b8cd1b0dd4df838c4415d04 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 30 Jan 2019 15:42:59 -0600 Subject: [PATCH 0116/1732] Allow the omitted new line character to be more than one char The code already allowed for variable width (multicell) *display* of the newline omitted character, but there was no way to define it as being more than one `wchar_t`. This lets us use a string on console sessions (^J aka newline feed) instead of an ambiguous character like `@` (used in some versions of vim for ^M) or `~` (what we were using). --- src/common.cpp | 19 ++++++++++++++----- src/common.h | 3 ++- src/screen.cpp | 6 +++--- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/common.cpp b/src/common.cpp index 11b1ff8d5..b50bcac37 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -70,7 +70,8 @@ static bool thread_asserts_cfg_for_testing = false; wchar_t ellipsis_char; const wchar_t *ellipsis_str = nullptr; -wchar_t omitted_newline_char; +const wchar_t *omitted_newline_str; +int omitted_newline_width; wchar_t obfuscation_read_char; bool g_profiling_active = false; const wchar_t *program_name; @@ -580,13 +581,21 @@ void fish_setlocale() { if (is_windows_subsystem_for_linux()) { // neither of \u23CE and \u25CF can be displayed in the default fonts on Windows, though // they can be *encoded* just fine. Use alternative glyphs. - omitted_newline_char = can_be_encoded(L'\u00b6') ? L'\u00b6' : L'~'; // "pilcrow" - obfuscation_read_char = can_be_encoded(L'\u2022') ? L'\u2022' : L'*'; // "bullet" + omitted_newline_str = L"\u00b6"; // "pilcrow" + omitted_newline_width = 1; + obfuscation_read_char = L'\u2022'; // "bullet" } else if (is_console_session()) { - omitted_newline_char = L'@'; + omitted_newline_str = L"^J"; + omitted_newline_width = 2; obfuscation_read_char = L'*'; } else { - omitted_newline_char = can_be_encoded(L'\u23CE') ? L'\u23CE' : L'~'; // "return" + if (can_be_encoded(L'\u23CE')) { + omitted_newline_str = L"\u23CE"; + omitted_newline_width = 1; + } else { + omitted_newline_str = L"^J"; + omitted_newline_width = 2; + } obfuscation_read_char = can_be_encoded(L'\u25CF') ? L'\u25CF' : L'#'; // "black circle" } } diff --git a/src/common.h b/src/common.h index 811901ad1..e84edaa50 100644 --- a/src/common.h +++ b/src/common.h @@ -201,7 +201,8 @@ extern wchar_t ellipsis_char; extern const wchar_t *ellipsis_str; /// Character representing an omitted newline at the end of text. -extern wchar_t omitted_newline_char; +extern const wchar_t *omitted_newline_str; +extern int omitted_newline_width; /// Character used for the silent mode of the read command extern wchar_t obfuscation_read_char; diff --git a/src/screen.cpp b/src/screen.cpp index ae11033ab..bd34c94a1 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -1102,7 +1102,7 @@ void s_reset(screen_t *s, screen_reset_mode_t mode) { // Don't need to check for fish_wcwidth errors; this is done when setting up // omitted_newline_char in common.cpp. - int non_space_width = fish_wcwidth(omitted_newline_char); + int non_space_width = omitted_newline_width; // We do `>` rather than `>=` because the code below might require one extra space. if (screen_width > non_space_width) { bool justgrey = true; @@ -1129,7 +1129,7 @@ void s_reset(screen_t *s, screen_reset_mode_t mode) { } } - abandon_line_string.push_back(omitted_newline_char); + abandon_line_string.append(omitted_newline_str); if (cur_term && exit_attribute_mode) { abandon_line_string.append( @@ -1141,7 +1141,7 @@ void s_reset(screen_t *s, screen_reset_mode_t mode) { } abandon_line_string.push_back(L'\r'); - abandon_line_string.push_back(omitted_newline_char); + abandon_line_string.append(omitted_newline_str); // Now we are certainly on a new line. But we may have dropped the omitted newline char on // it. So append enough spaces to overwrite the omitted newline char, and then clear all the // spaces from the new line. From a1cba81d13c94479611b761f877a33f201d6bf4d Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 20 Mar 2019 21:13:27 -0500 Subject: [PATCH 0117/1732] Add note about console session improvements to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a476b3fb9..8311bbfde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - fish_clipboard_* now supports wayland by means of [wl-clipboard](https://github.com/bugaevc/wl-clipboard). - Pasting will now strip leading spaces if they would trigger history ignoring (#4327). - New color options for the pager have been added (#5524). +- Better detection and support for using fish from the system console, where limited colors and special characters are supported (#5552 and others) - The default escape delay (to differentiate between the escape key and an alt-combination) has been reduced to 30ms, down from 300ms for the default mode and 100ms for vi-mode (#3904). - The `path_helper` on macOS now only runs in login shells, matching the bash implementation. - The `forward-bigword` binding now interacts correctly with autosuggestions (#5336) From 277a94c118ff2f432b3fa0486d6ddc4e2a41e060 Mon Sep 17 00:00:00 2001 From: GReagle Date: Thu, 21 Mar 2019 05:24:08 -0400 Subject: [PATCH 0118/1732] FAQ: how to check whether variable is defined or not empty (#5732) * FAQ: how to check whether variable is defined or not empty * FAQ: how to check whether variable is not empty: include test in answer --- sphinx_doc_src/faq.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sphinx_doc_src/faq.rst b/sphinx_doc_src/faq.rst index cb1eafa99..7f5871b49 100644 --- a/sphinx_doc_src/faq.rst +++ b/sphinx_doc_src/faq.rst @@ -112,6 +112,34 @@ You can also declare a local variable in a block:: end +How do I check whether a variable is defined? +--------------------------------------------- + +Use ``set -q var``. For example, ``if set -q var; echo variable defined; end``. To check multiple variables you can combine with ``and`` and ``or`` like so:: + + if set -q var1; or set -q var2 + echo either variable defined + end + +Keep in mind that a defined variabled could be empty. Both of these commands define an empty variable: ``set var`` and ``set var ""``. + + +How do I check whether a variable is not empty? +----------------------------------------------- + +Use ``string length -q -- $var``. For example, ``if string length -q -- $var; echo not empty; end``. Note that ``string length`` will interpret a list of multiple variables as a disjunction (meaning any/or):: + + if string length -q -- $var1 $var2 $var3 + echo at least one of these variables is not empty + end + +Alternatively, use ``test -n "$var"``, but remember that **the variable must be double-quoted**. For example, ``if test -n "$var"; echo not empty; end``. The ``test`` command provides its own and (-a) and or (-o):: + + if test -n "$var1" -o -n "$var2" -o -n "$var3" + echo at least one of these variables is not empty + end + + Why doesn't ``set -Ux`` (exported universal variables) seem to work? -------------------------------------------------------------------- A global variable of the same name already exists. From 21c8be8cd1a2c430c53740eabf2f689841b76cdd Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 22 Mar 2019 09:09:16 +0100 Subject: [PATCH 0119/1732] functions/help: Use open command everywhere See #5756. [ci skip] --- share/functions/help.fish | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/share/functions/help.fish b/share/functions/help.fish index e42ad81b7..d1e724377 100644 --- a/share/functions/help.fish +++ b/share/functions/help.fish @@ -65,12 +65,11 @@ function help --description 'Show help for the fish shell' set fish_browser xdg-open end - # On OS X, we go through open by default - if test (uname) = Darwin - if type -q open - set fish_browser open - set need_trampoline 1 - end + # If we have an open _command_ we use it - otherwise it's our function, + # which might not have a backend to use. + if command -sq open + set fish_browser open + set need_trampoline 1 end end end From 4c61691377a33a2f36a78cb041e336b253769669 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 22 Mar 2019 12:38:23 +0100 Subject: [PATCH 0120/1732] functions/help: Don't eval to check for lynx This called `eval $fish_browser --version` to figure out if it is lynx. That's really not worth it just to support edge-cases using a rather unusual browser, to work around a bug in it. Instead we just see if the browser name starts with "lynx", which should work in 99.9% of cases. --- share/functions/help.fish | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/share/functions/help.fish b/share/functions/help.fish index d1e724377..692d7ad0b 100644 --- a/share/functions/help.fish +++ b/share/functions/help.fish @@ -168,8 +168,7 @@ function help --description 'Show help for the fish shell' else # Work around lynx bug where
always has the same formatting as links (unreadable) # by using a custom style sheet. See https://github.com/fish-shell/fish-shell/issues/4170 - set -l local_file 0 - if eval $fish_browser --version 2>/dev/null | string match -qr Lynx + if string match -q 'lynx*' -- $fish_browser set fish_browser $fish_browser -lss={$__fish_data_dir}/lynx.lss end eval $fish_browser $page_url From 25ba16d4b6db690fd4248e88176479768ee7dcbd Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 22 Mar 2019 12:40:39 +0100 Subject: [PATCH 0121/1732] functions/help: Cleanup --- share/functions/help.fish | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/share/functions/help.fish b/share/functions/help.fish index 692d7ad0b..977818ed7 100644 --- a/share/functions/help.fish +++ b/share/functions/help.fish @@ -15,30 +15,28 @@ function help --description 'Show help for the fish shell' set -a help_topics expand-command-substitution expand-process # - # Find a suitable browser for viewing the help pages. This is needed - # by the help function defined below. - # - set -l fish_browser - set -l graphical_browsers htmlview x-www-browser firefox galeon mozilla konqueror epiphany opera netscape rekonq google-chrome chromium-browser + # Find a suitable browser for viewing the help pages. + # The first thing we try is $fish_help_browser. + set -l fish_browser $fish_help_browser + + # A list of graphical browsers we know about. + set -l graphical_browsers htmlview x-www-browser firefox galeon mozilla + set -a graphical_browsers konqueror epiphany opera netscape rekonq google-chrome chromium-browser # On mac we may have to write a temporary file that redirects to the desired # help page, since `open` will drop fragments from file URIs (issue #4480). set -l need_trampoline - if set -q fish_help_browser[1] - # User has set a fish-specific help browser. This overrides the - # browser that may be defined by $BROWSER. The fish_help_browser - # variable may be an array containing a browser name plus options. - set fish_browser $fish_help_browser - else - set -l text_browsers htmlview www-browser links elinks lynx w3m - + if not set -q fish_browser[1] if set -q BROWSER # User has manually set a preferred browser, so we respect that set fish_browser $BROWSER else + # No browser set up, inferring. + # We check a bunch and use the last we find. + # Check for a text-based browser. - for i in $text_browsers + for i in htmlview www-browser links elinks lynx w3m if type -q -f $i set fish_browser $i break @@ -47,7 +45,7 @@ function help --description 'Show help for the fish shell' # If we are in a graphical environment, check if there is a graphical # browser to use instead. - if test "$DISPLAY" -a \( "$XAUTHORITY" = "$HOME/.Xauthority" -o "$XAUTHORITY" = "" \) + if test -n "$DISPLAY" -a \( "$XAUTHORITY" = "$HOME/.Xauthority" -o "$XAUTHORITY" = "" \) for i in $graphical_browsers if type -q -f $i set fish_browser $i @@ -69,6 +67,7 @@ function help --description 'Show help for the fish shell' # which might not have a backend to use. if command -sq open set fish_browser open + # The open command needs a trampoline because the macOS version can't handle #-fragments. set need_trampoline 1 end end From 7a74198aa3cf88585eee879bd608df36fca12ced Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 16 Mar 2019 19:32:07 -0700 Subject: [PATCH 0122/1732] parser: try to avoid some strings being copied --- src/parse_execution.cpp | 4 +--- src/parse_tree.cpp | 2 +- src/parse_tree.h | 2 +- src/parser.cpp | 2 +- src/parser.h | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 3d83c9035..c14aadd7f 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -734,8 +734,6 @@ parse_execution_result_t parse_execution_context_t::expand_command( // Get the unexpanded command string. We expect to always get it here. wcstring unexp_cmd = *command_for_plain_statement(statement, pstree->src); - wcstring cmd; - wcstring_list_t args; // Expand the string to produce completions, and report errors. expand_error_t expand_err = @@ -879,7 +877,7 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process( proc->type = process_type; proc->set_argv(cmd_args); proc->set_io_chain(process_io_chain); - proc->actual_cmd = path_to_external_command; + proc->actual_cmd = std::move(path_to_external_command); return parse_execution_success; } diff --git a/src/parse_tree.cpp b/src/parse_tree.cpp index cd7b35568..d2e3774af 100644 --- a/src/parse_tree.cpp +++ b/src/parse_tree.cpp @@ -1135,7 +1135,7 @@ const parse_node_t *parse_node_tree_t::get_child(const parse_node_t &parent, nod return result; } -parsed_source_ref_t parse_source(wcstring src, parse_tree_flags_t flags, parse_error_list_t *errors, +parsed_source_ref_t parse_source(const wcstring &src, parse_tree_flags_t flags, parse_error_list_t *errors, parse_token_type_t goal) { parse_node_tree_t tree; if (!parse_tree_from_string(src, flags, &tree, errors, goal)) return {}; diff --git a/src/parse_tree.h b/src/parse_tree.h index 9e032f11d..8fc536131 100644 --- a/src/parse_tree.h +++ b/src/parse_tree.h @@ -233,7 +233,7 @@ struct parsed_source_t { }; /// Return a shared pointer to parsed_source_t, or null on failure. using parsed_source_ref_t = std::shared_ptr; -parsed_source_ref_t parse_source(wcstring src, parse_tree_flags_t flags, parse_error_list_t *errors, +parsed_source_ref_t parse_source(const wcstring &src, parse_tree_flags_t flags, parse_error_list_t *errors, parse_token_type_t goal = symbol_job_list); #endif diff --git a/src/parser.cpp b/src/parser.cpp index a8d30e0bf..572f9b5bb 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -629,7 +629,7 @@ profile_item_t *parser_t::create_profile_item() { return result; } -int parser_t::eval(wcstring cmd, const io_chain_t &io, enum block_type_t block_type) { +int parser_t::eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type) { // Parse the source into a tree, if we can. parse_error_list_t error_list; parsed_source_ref_t ps = parse_source(cmd, parse_flag_none, &error_list); diff --git a/src/parser.h b/src/parser.h index ac251a4be..264b09cc8 100644 --- a/src/parser.h +++ b/src/parser.h @@ -222,7 +222,7 @@ class parser_t : public std::enable_shared_from_this { /// \param block_type The type of block to push on the block stack /// /// \return 0 on success, 1 on a parse error. - int eval(wcstring cmd, const io_chain_t &io, enum block_type_t block_type); + int eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type); /// Evaluate the parsed source ps. void eval(parsed_source_ref_t ps, const io_chain_t &io, enum block_type_t block_type); From a2a9709fd93a2a23fa5f350e3dfc04a491bb0f25 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 23 Mar 2019 12:33:03 -0700 Subject: [PATCH 0123/1732] Don't truncate hostnames over 32 characters I believe this was selected to be artificially low for the sake of it displaying well in prompts. But people should expect to get the same output as can be gotten from `hostname`. Fixes #5758 --- src/env_universal_common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/env_universal_common.cpp b/src/env_universal_common.cpp index 7a033f03c..5ab4ad7ad 100644 --- a/src/env_universal_common.cpp +++ b/src/env_universal_common.cpp @@ -926,7 +926,7 @@ void env_universal_t::parse_message_2x_internal(const wcstring &msgstr, var_tabl } /// Maximum length of hostname. Longer hostnames are truncated. -#define HOSTNAME_LEN 32 +#define HOSTNAME_LEN 255 /// Length of a MAC address. #define MAC_ADDRESS_MAX_LEN 6 From 185805641c5b10148598041ed40af5d74722889b Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Fri, 15 Mar 2019 01:11:15 -0700 Subject: [PATCH 0124/1732] Remove R_TIMEOUT Promote timeout to a char_event_type_t, moving it out of the "char" namespace. This will help simplify the readline implementation. --- src/fish_key_reader.cpp | 5 +- src/fish_tests.cpp | 9 ++- src/input.cpp | 144 +++++++++++++++++++--------------------- src/input.h | 5 +- src/input_common.cpp | 125 ++++++++++++++++++---------------- src/input_common.h | 57 +++++++++++++--- src/reader.cpp | 54 ++++++++++----- 7 files changed, 234 insertions(+), 165 deletions(-) diff --git a/src/fish_key_reader.cpp b/src/fish_key_reader.cpp index be845c63b..71e374fbb 100644 --- a/src/fish_key_reader.cpp +++ b/src/fish_key_reader.cpp @@ -208,9 +208,10 @@ static void process_input(bool continuous_mode) { if (reader_test_and_clear_interrupted()) { wc = shell_modes.c_cc[VINTR]; } else { - wc = input_common_readch(true); + auto mwc = input_common_readch_timed(true); + wc = mwc.is_char() ? mwc.get_char() : R_EOF; } - if (wc == R_TIMEOUT || wc == R_EOF) { + if (wc == R_EOF) { output_bind_command(bind_chars); if (first_char_seen && !continuous_mode) { return; diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 364701fe0..151488367 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -2996,9 +2996,12 @@ static void test_input() { } // Now test. - wint_t c = input_readch(); - if (c != R_DOWN_LINE) { - err(L"Expected to read char R_DOWN_LINE, but instead got %ls\n", describe_char(c).c_str()); + auto evt = input_readch(); + if (!evt.is_char()) { + err(L"Event is not a char"); + } else if (evt.get_char() != R_DOWN_LINE) { + err(L"Expected to read char R_DOWN_LINE, but instead got %ls\n", + describe_char(evt.get_char()).c_str()); } } diff --git a/src/input.cpp b/src/input.cpp index 5cece3eeb..7a00faa11 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -51,6 +51,9 @@ struct input_mapping_t { static unsigned int s_last_input_map_spec_order = 0; specification_order = ++s_last_input_map_spec_order; } + + /// \return true if this is a generic mapping, i.e. acts as a fallback. + bool is_generic() const { return seq.empty(); } }; /// A struct representing the mapping from a terminfo key name to a terminfo character sequence. @@ -297,17 +300,19 @@ wchar_t input_function_pop_arg() { return input_function_args[--input_function_a void input_function_push_args(int code) { int arity = input_function_arity(code); - std::vector skipped; + std::vector skipped; for (int i = 0; i < arity; i++) { - wchar_t arg; - // Skip and queue up any function codes. See issue #2357. - while ((arg = input_common_readch(0)) >= R_BEGIN_INPUT_FUNCTIONS && - arg < R_END_INPUT_FUNCTIONS) { - skipped.push_back(arg); + wchar_t arg{}; + for (;;) { + auto evt = input_common_readch(); + if (evt.is_char() && !evt.is_readline()) { + arg = evt.get_char(); + break; + } + skipped.push_back(evt); } - input_function_push_arg(arg); } @@ -384,15 +389,13 @@ static bool input_mapping_is_match(const input_mapping_t &m) { bool timed = false; for (size_t i = 0; i < str.size(); ++i) { - wchar_t read = input_common_readch(timed); - - if (read != str[i]) { - // We didn't match the bind sequence/input mapping, (it timed out or they entered something else) - // Undo consumption of the read characters since we didn't match the bind sequence and abort. - input_common_next_ch(read); - while (i--) { - input_common_next_ch(str[i]); - } + auto evt = timed ? input_common_readch_timed() : input_common_readch(); + if (!evt.is_char() || evt.get_char() != str[i]) { + // We didn't match the bind sequence/input mapping, (it timed out or they entered + // something else) Undo consumption of the read characters since we didn't match the + // bind sequence and abort. + input_common_next_ch(evt); + while (i--) input_common_next_ch(str[i]); return false; } @@ -404,87 +407,77 @@ static bool input_mapping_is_match(const input_mapping_t &m) { return true; } -void input_queue_ch(wint_t ch) { input_common_queue_ch(ch); } +void input_queue_ch(char_event_t ch) { input_common_queue_ch(ch); } -static void input_mapping_execute_matching_or_generic(bool allow_commands) { +/// \return the first mapping that matches, walking first over the user's mapping list, then the +/// preset list. \return null if nothing matches. +static const input_mapping_t *find_mapping() { const input_mapping_t *generic = NULL; - const auto &vars = parser_t::principal_parser().vars(); const wcstring bind_mode = input_get_bind_mode(vars); - for (auto& m : mapping_list) { - if (m.mode != bind_mode) { - continue; - } + const auto lists = {&mapping_list, &preset_mapping_list}; + for (const auto *listp : lists) { + for (const auto &m : *listp) { + if (m.mode != bind_mode) { + continue; + } - if (m.seq.length() == 0) { - generic = &m; - } else if (input_mapping_is_match(m)) { - input_mapping_execute(m, allow_commands); - return; + if (m.is_generic()) { + if (!generic) generic = &m; + } else if (input_mapping_is_match(m)) { + return &m; + } } } + return generic; +} - // HACK: This is ugly duplication. - for (auto& m : preset_mapping_list) { - if (m.mode != bind_mode) { - continue; - } - - if (m.seq.length() == 0) { - // Only use this generic if the user list didn't have one. - if (!generic) generic = &m; - } else if (input_mapping_is_match(m)) { - input_mapping_execute(m, allow_commands); - return; - } - } - - if (generic) { - input_mapping_execute(*generic, allow_commands); +static void input_mapping_execute_matching_or_generic(bool allow_commands) { + const input_mapping_t *mapping = find_mapping(); + if (mapping) { + input_mapping_execute(*mapping, allow_commands); } else { debug(2, L"no generic found, ignoring char..."); - wchar_t c = input_common_readch(0); - if (c == R_EOF) { - input_common_next_ch(c); + auto evt = input_common_readch(); + if (evt.is_char() && evt.get_char() == R_EOF) { + input_common_next_ch(evt); } } } /// Helper function. Picks through the queue of incoming characters until we get to one that's not a /// readline function. -static wchar_t input_read_characters_only() { - std::vector functions_to_put_back; - wchar_t char_to_return; +static char_event_t input_read_characters_only() { + std::vector saved_events; + char_event_t char_to_return{0}; for (;;) { - char_to_return = input_common_readch(0); - bool is_readline_function = - (char_to_return >= R_BEGIN_INPUT_FUNCTIONS && char_to_return < R_END_INPUT_FUNCTIONS); - // R_NULL and R_EOF are more control characters than readline functions, so check specially - // for those. - if (!is_readline_function || char_to_return == R_NULL || char_to_return == R_EOF) { - break; + auto evt = input_common_readch(); + if (evt.is_char()) { + auto c = evt.get_char(); + if (!evt.is_readline() || c == R_NULL || c == R_EOF) { + char_to_return = evt; + break; + } } - // This is a readline function; save it off for later re-enqueing and try again. - functions_to_put_back.push_back(char_to_return); + saved_events.push_back(evt); } // Restore any readline functions, in reverse to preserve their original order. - size_t idx = functions_to_put_back.size(); - while (idx--) { - input_common_next_ch(functions_to_put_back.at(idx)); + for (auto iter = saved_events.rbegin(); iter != saved_events.rend(); ++iter) { + input_common_next_ch(*iter); } return char_to_return; } -wint_t input_readch(bool allow_commands) { +char_event_t input_readch(bool allow_commands) { // Clear the interrupted flag. reader_reset_interrupted(); // Search for sequence in mapping tables. while (true) { - wchar_t c = input_common_readch(0); + auto evt = input_common_readch(); - if (c >= R_BEGIN_INPUT_FUNCTIONS && c < R_END_INPUT_FUNCTIONS) { - switch (c) { + if (evt.is_readline()) { + switch (evt.get_char()) { case R_SELF_INSERT: { // Issue #1595: ensure we only insert characters, not readline functions. The // common case is that this will be empty. @@ -494,21 +487,20 @@ wint_t input_readch(bool allow_commands) { if (input_function_status) { return input_readch(); } - c = input_common_readch(0); - while (c >= R_BEGIN_INPUT_FUNCTIONS && c < R_END_INPUT_FUNCTIONS) { - c = input_common_readch(0); - } - input_common_next_ch(c); + do { + evt = input_common_readch(); + } while (evt.is_readline()); + input_common_next_ch(evt); return input_readch(); } - default: { return c; } + default: { return evt; } } - } else if (c == R_EOF) { + } else if (evt.is_char() && evt.get_char() == R_EOF) { // If we have R_EOF, we need to immediately quit. // There's no need to go through the input functions. - return R_EOF; + return evt; } else { - input_common_next_ch(c); + input_common_next_ch(evt); input_mapping_execute_matching_or_generic(allow_commands); // Regarding allow_commands, we're in a loop, but if a fish command // is executed, R_NULL is unread, so the next pass through the loop diff --git a/src/input.h b/src/input.h index 3ae272239..fc20d24db 100644 --- a/src/input.h +++ b/src/input.h @@ -9,6 +9,7 @@ #include "builtin_bind.h" #include "common.h" +#include "input_common.h" #define FISH_BIND_MODE_VAR L"fish_bind_mode" @@ -32,11 +33,11 @@ void init_input(); /// The argument determines whether fish commands are allowed to be run as bindings. If false, when /// a character is encountered that would invoke a fish command, it is unread and R_NULL is /// returned. -wint_t input_readch(bool allow_commands = true); +char_event_t input_readch(bool allow_commands = true); /// Enqueue a character or a readline function to the queue of unread characters that input_readch /// will return before actually reading from fd 0. -void input_queue_ch(wint_t ch); +void input_queue_ch(char_event_t ch); /// Add a key mapping from the specified sequence to the specified command. /// diff --git a/src/input_common.cpp b/src/input_common.cpp index 765a9d667..8706d8a19 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -33,8 +33,8 @@ #define WAIT_ON_ESCAPE_DEFAULT 30 static int wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT; -/// Characters that have been read and returned by the sequence matching code. -static std::deque lookahead_list; +/// Events which have been read and returned by the sequence matching code. +static std::deque lookahead_list; // Queue of pairs of (function pointer, argument) to be invoked. Expected to be mostly empty. typedef std::list> callback_queue_t; @@ -43,17 +43,24 @@ static void input_flush_callbacks(); static bool has_lookahead() { return !lookahead_list.empty(); } -static wint_t lookahead_pop() { - wint_t result = lookahead_list.front(); +static char_event_t lookahead_pop() { + auto result = lookahead_list.front(); lookahead_list.pop_front(); return result; } -static void lookahead_push_back(wint_t c) { lookahead_list.push_back(c); } +/// \return the next lookahead char, or none if none. Discards timeouts. +static maybe_t lookahead_pop_char() { + while (has_lookahead()) { + auto evt = lookahead_pop(); + if (evt.is_char()) return evt.get_char(); + } + return none(); +} -static void lookahead_push_front(wint_t c) { lookahead_list.push_front(c); } +static void lookahead_push_back(char_event_t c) { lookahead_list.push_back(c); } -static wint_t lookahead_front() { return lookahead_list.front(); } +static void lookahead_push_front(char_event_t c) { lookahead_list.push_front(c); } /// Callback function for handling interrupts on reading. static int (*interrupt_handler)(); @@ -109,7 +116,9 @@ static wint_t readb() { if (interrupt_handler) { int res = interrupt_handler(); if (res) return res; - if (has_lookahead()) return lookahead_pop(); + if (auto mc = lookahead_pop_char()) { + return *mc; + } } do_loop = true; @@ -133,8 +142,8 @@ static wint_t readb() { if (ioport > 0 && FD_ISSET(ioport, &fdset)) { iothread_service_completion(); - if (has_lookahead()) { - return lookahead_pop(); + if (auto mc = lookahead_pop_char()) { + return *mc; } } @@ -173,63 +182,65 @@ void update_wait_on_escape_ms(const environment_t &vars) { } } -wchar_t input_common_readch(int timed) { - if (!has_lookahead()) { - if (timed) { - fd_set fds; - FD_ZERO(&fds); - FD_SET(0, &fds); - struct timeval tm = {wait_on_escape_ms / 1000, 1000 * (wait_on_escape_ms % 1000)}; - int count = select(1, &fds, 0, 0, &tm); - if (count <= 0) { - return R_TIMEOUT; - } +char_event_t input_common_readch() { + if (auto mc = lookahead_pop_char()) { + return *mc; + } + wchar_t res; + mbstate_t state = {}; + while (1) { + wint_t b = readb(); + + if (b >= R_NULL && b < R_END_INPUT_FUNCTIONS) return b; + + if (MB_CUR_MAX == 1) { + return b; // single-byte locale, all values are legal } - wchar_t res; - mbstate_t state = {}; + char bb = b; + size_t sz = std::mbrtowc(&res, &bb, 1, &state); - while (1) { - wint_t b = readb(); - - if (b >= R_NULL && b < R_END_INPUT_FUNCTIONS) return b; - - if (MB_CUR_MAX == 1) { - // return (unsigned char)b; // single-byte locale, all values are legal - return b; // single-byte locale, all values are legal + switch (sz) { + case (size_t)(-1): { + std::memset(&state, '\0', sizeof(state)); + debug(2, L"Illegal input"); + return R_NULL; } - - char bb = b; - size_t sz = std::mbrtowc(&res, &bb, 1, &state); - - switch (sz) { - case (size_t)(-1): { - std::memset(&state, '\0', sizeof(state)); - debug(2, L"Illegal input"); - return R_NULL; - } - case (size_t)(-2): { - break; - } - case 0: { - return 0; - } - default: { return res; } + case (size_t)(-2): { + break; } + case 0: { + return 0; + } + default: { return res; } } - } else { - if (!timed) { - while (has_lookahead() && lookahead_front() == R_TIMEOUT) lookahead_pop(); - if (!has_lookahead()) return input_common_readch(0); - } - - return lookahead_pop(); } } -void input_common_queue_ch(wint_t ch) { lookahead_push_back(ch); } +char_event_t input_common_readch_timed(bool dequeue_timeouts) { + char_event_t result{char_event_type_t::timeout}; + if (has_lookahead()) { + result = lookahead_pop(); + } else { + fd_set fds; + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + struct timeval tm = {wait_on_escape_ms / 1000, 1000 * (wait_on_escape_ms % 1000)}; + if (select(1, &fds, 0, 0, &tm) > 0) { + result = input_common_readch(); + } + } + // If we got a timeout, either through dequeuing or creating, ensure it stays on the queue. + if (result.is_timeout()) { + if (!dequeue_timeouts) lookahead_push_front(char_event_type_t::timeout); + return char_event_type_t::timeout; + } + return result.get_char(); +} -void input_common_next_ch(wint_t ch) { lookahead_push_front(ch); } +void input_common_queue_ch(char_event_t ch) { lookahead_push_back(ch); } + +void input_common_next_ch(char_event_t ch) { lookahead_push_front(ch); } void input_common_add_callback(std::function callback) { ASSERT_IS_MAIN_THREAD(); diff --git a/src/input_common.h b/src/input_common.h index 58d1ac6f6..a0427e665 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -7,6 +7,7 @@ #include #include "common.h" +#include "maybe.h" enum { R_MIN = INPUT_COMMON_BASE, @@ -74,35 +75,75 @@ enum { R_REPEAT_JUMP, R_REVERSE_REPEAT_JUMP, - R_TIMEOUT, // we didn't get interactive input within wait_on_escape_ms - // The range of key codes for inputrc-style keyboard functions that are passed on to the caller // of input_read(). R_BEGIN_INPUT_FUNCTIONS = R_BEGINNING_OF_LINE, R_END_INPUT_FUNCTIONS = R_REVERSE_REPEAT_JUMP + 1 }; +/// Represents an event on the character input stream. +enum class char_event_type_t { + /// A character was entered. + charc, + + /// A timeout was hit. + timeout, +}; + +class char_event_t { + /// Set if the type is charc. + wchar_t c_; + + public: + char_event_type_t type; + + bool is_timeout() const { return type == char_event_type_t::timeout; } + + bool is_char() const { return type == char_event_type_t::charc; } + + bool is_readline() const { + return is_char() && c_ >= R_BEGIN_INPUT_FUNCTIONS && c_ < R_END_INPUT_FUNCTIONS; + } + + wchar_t get_char() const { + assert(type == char_event_type_t::charc && "Not a char type"); + return c_; + } + + /* implicit */ char_event_t(wchar_t c) : c_(c), type(char_event_type_t::charc) {} + + /* implicit */ char_event_t(char_event_type_t type) : c_(0), type(type) { + assert(type != char_event_type_t::charc && + "Cannot create a char event with this constructor"); + } +}; + /// Init the library. void input_common_init(int (*ih)()); /// Adjust the escape timeout. +class environment_t; void update_wait_on_escape_ms(const environment_t &vars); /// Function used by input_readch to read bytes from stdin until enough bytes have been read to /// convert them to a wchar_t. Conversion is done using mbrtowc. If a character has previously been -/// read and then 'unread' using \c input_common_unreadch, that character is returned. If timed is -/// true, readch2 will wait at most WAIT_ON_ESCAPE milliseconds for a character to be available for -/// reading before returning with the value R_EOF. -wchar_t input_common_readch(int timed); +/// read and then 'unread' using \c input_common_unreadch, that character is returned. +/// This function never returns a timeout. +char_event_t input_common_readch(); + +/// Like input_common_readch(), except it will wait at most WAIT_ON_ESCAPE milliseconds for a +/// character to be available for reading. +/// If \p dequeue_timeouts is set, remove any timeout from the queue; otherwise retain them. +char_event_t input_common_readch_timed(bool dequeue_timeouts = false); /// Enqueue a character or a readline function to the queue of unread characters that input_readch /// will return before actually reading from fd 0. -void input_common_queue_ch(wint_t ch); +void input_common_queue_ch(char_event_t ch); /// Add a character or a readline function to the front of the queue of unread characters. This /// will be the first character returned by input_readch (unless this function is called more than /// once). -void input_common_next_ch(wint_t ch); +void input_common_next_ch(char_event_t ch); /// Adds a callback to be invoked at the next turn of the "event loop." The callback function will /// be invoked and passed arg. diff --git a/src/reader.cpp b/src/reader.cpp index 02c5a11bc..63b88ad36 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2382,8 +2382,14 @@ static bool text_ends_in_comment(const wcstring &text) { return token.type == TOK_COMMENT; } +/// \return true if an event is a normal character that should be inserted into the buffer. +static bool event_is_normal_char(const char_event_t &evt) { + if (!evt.is_char()) return false; + auto c = evt.get_char(); + return !fish_reserved_codepoint(c) && c > 31 && c != 127; +} + maybe_t reader_data_t::readline(int nchars) { - wint_t c; int last_char = 0; size_t yank_len = 0; const wchar_t *yank_str; @@ -2436,37 +2442,44 @@ maybe_t reader_data_t::readline(int nchars) { // Sometimes strange input sequences seem to generate a zero byte. I believe these simply // mean a character was pressed but it should be ignored. (Example: Trying to add a tilde // (~) to digit). + maybe_t event_needing_handling{}; while (1) { int was_interactive_read = is_interactive_read; is_interactive_read = 1; - c = input_readch(); + event_needing_handling = input_readch(); is_interactive_read = was_interactive_read; // std::fwprintf(stderr, L"C: %lx\n", (long)c); - if (((!fish_reserved_codepoint(c))) && (c > 31) && (c != 127) && can_read(0)) { - wchar_t arr[READAHEAD_MAX + 1]; - size_t i; + if (event_is_normal_char(*event_needing_handling) && can_read(STDIN_FILENO)) { + // This is a normal character input. + // We are going to handle it directly, accumulating more. + // Clear 'mevt' to mark that we handled this. + char_event_t evt = event_needing_handling.acquire(); size_t limit = 0 < nchars ? std::min((size_t)nchars - command_line.size(), (size_t)READAHEAD_MAX) : READAHEAD_MAX; - std::memset(arr, 0, sizeof(arr)); - arr[0] = c; + wchar_t arr[READAHEAD_MAX + 1] = {}; + arr[0] = evt.get_char(); + last_char = arr[0]; - for (i = 1; i < limit; ++i) { + for (size_t i = 1; i < limit; ++i) { if (!can_read(0)) { - c = 0; break; } // Only allow commands on the first key; otherwise, we might have data we // need to insert on the commandline that the commmand might need to be able // to see. - c = input_readch(false); - if (!fish_reserved_codepoint(c) && c > 31 && c != 127) { - arr[i] = c; - c = 0; - } else + auto next_event = input_readch(false); + if (event_is_normal_char(next_event)) { + arr[i] = next_event.get_char(); + last_char = arr[i]; + } else { + // We need to process this in the outer loop. + assert(!event_needing_handling && "Should not have an unhandled event"); + event_needing_handling = next_event; break; + } } editable_line_t *el = active_edit_line(); @@ -2476,17 +2489,24 @@ maybe_t reader_data_t::readline(int nchars) { if (el == &command_line) { clear_pager(); } - last_char = c; } - if (c != 0) break; + // If there's still an event that we were unable to handle, then end the coalescing + // loop. + if (event_needing_handling.has_value()) break; if (0 < nchars && (size_t)nchars <= command_line.size()) { - c = R_NULL; + event_needing_handling.reset(); break; } } + if (!event_needing_handling) { + event_needing_handling = R_NULL; + } + assert(event_needing_handling->is_char() && "Should have a char event"); + wchar_t c = event_needing_handling->get_char(); + // If we get something other than a repaint, then stop coalescing them. if (c != R_REPAINT) coalescing_repaints = false; From 00f24695fe0c4f301fa17708e97dd64837c08799 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 16 Mar 2019 12:35:49 -0700 Subject: [PATCH 0125/1732] Remove R_EOF Promote R_EOF to a new char_event_type_t instead of keeping it as a char value. --- src/fish_key_reader.cpp | 10 +++++----- src/input.cpp | 18 ++++++++++-------- src/input_common.cpp | 18 ++++++++++++------ src/input_common.h | 6 +++++- src/reader.cpp | 7 +++---- 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/fish_key_reader.cpp b/src/fish_key_reader.cpp index 71e374fbb..ba688b4e7 100644 --- a/src/fish_key_reader.cpp +++ b/src/fish_key_reader.cpp @@ -204,14 +204,13 @@ static void process_input(bool continuous_mode) { std::fwprintf(stderr, L"Press a key\n\n"); while (keep_running) { - wchar_t wc; + char_event_t evt{0}; if (reader_test_and_clear_interrupted()) { - wc = shell_modes.c_cc[VINTR]; + evt = char_event_t{shell_modes.c_cc[VINTR]}; } else { - auto mwc = input_common_readch_timed(true); - wc = mwc.is_char() ? mwc.get_char() : R_EOF; + evt = input_common_readch_timed(true); } - if (wc == R_EOF) { + if (!evt.is_char()) { output_bind_command(bind_chars); if (first_char_seen && !continuous_mode) { return; @@ -219,6 +218,7 @@ static void process_input(bool continuous_mode) { continue; } + wchar_t wc = evt.get_char(); prev_tstamp = output_elapsed_time(prev_tstamp, first_char_seen); add_char_to_bind_command(wc, bind_chars); output_info_about_char(wc); diff --git a/src/input.cpp b/src/input.cpp index 7a00faa11..edcd02910 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -440,22 +440,24 @@ static void input_mapping_execute_matching_or_generic(bool allow_commands) { } else { debug(2, L"no generic found, ignoring char..."); auto evt = input_common_readch(); - if (evt.is_char() && evt.get_char() == R_EOF) { + if (evt.is_eof()) { input_common_next_ch(evt); } } } /// Helper function. Picks through the queue of incoming characters until we get to one that's not a -/// readline function. -static char_event_t input_read_characters_only() { +/// readline function, or EOF. +static char_event_t input_read_characters_eof_only() { std::vector saved_events; char_event_t char_to_return{0}; for (;;) { auto evt = input_common_readch(); - if (evt.is_char()) { + if (evt.is_eof()) { + return evt; + } else if (evt.is_char()) { auto c = evt.get_char(); - if (!evt.is_readline() || c == R_NULL || c == R_EOF) { + if (!evt.is_readline() || c == R_NULL) { char_to_return = evt; break; } @@ -481,7 +483,7 @@ char_event_t input_readch(bool allow_commands) { case R_SELF_INSERT: { // Issue #1595: ensure we only insert characters, not readline functions. The // common case is that this will be empty. - return input_read_characters_only(); + return input_read_characters_eof_only(); } case R_AND: { if (input_function_status) { @@ -495,8 +497,8 @@ char_event_t input_readch(bool allow_commands) { } default: { return evt; } } - } else if (evt.is_char() && evt.get_char() == R_EOF) { - // If we have R_EOF, we need to immediately quit. + } else if (evt.is_eof()) { + // If we have EOF, we need to immediately quit. // There's no need to go through the input functions. return evt; } else { diff --git a/src/input_common.cpp b/src/input_common.cpp index 8706d8a19..c72ba8c7c 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -69,7 +69,8 @@ void input_common_init(int (*ih)()) { interrupt_handler = ih; } /// Internal function used by input_common_readch to read one byte from fd 0. This function should /// only be called by input_common_readch(). -static wint_t readb() { +/// \return the char, or none() on EOF. +static maybe_t readb() { // do_loop must be set on every path through the loop; leaving it uninitialized allows the // static analyzer to assist in catching mistakes. unsigned char arr[1]; @@ -123,8 +124,8 @@ static wint_t readb() { do_loop = true; } else { - // The terminal has been closed. Save and exit. - return R_EOF; + // The terminal has been closed. + return none(); } } else { // Assume we loop unless we see a character in stdin. @@ -149,8 +150,8 @@ static wint_t readb() { if (FD_ISSET(STDIN_FILENO, &fdset)) { if (read_blocked(0, arr, 1) != 1) { - // The teminal has been closed. Save and exit. - return R_EOF; + // The teminal has been closed. + return none(); } // We read from stdin, so don't loop. @@ -189,7 +190,12 @@ char_event_t input_common_readch() { wchar_t res; mbstate_t state = {}; while (1) { - wint_t b = readb(); + auto mb = readb(); + if (!mb) { + // EOF + return char_event_type_t::eof; + } + wint_t b = *mb; if (b >= R_NULL && b < R_END_INPUT_FUNCTIONS) return b; diff --git a/src/input_common.h b/src/input_common.h index a0427e665..1c8a2db6b 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -14,7 +14,6 @@ enum { // R_NULL is sometimes returned by the input when a character was requested but none could be // delivered, or when an exception happened. R_NULL = R_MIN, - R_EOF, R_BEGINNING_OF_LINE, R_END_OF_LINE, @@ -88,6 +87,9 @@ enum class char_event_type_t { /// A timeout was hit. timeout, + + /// end-of-file was reached. + eof }; class char_event_t { @@ -101,6 +103,8 @@ class char_event_t { bool is_char() const { return type == char_event_type_t::charc; } + bool is_eof() const { return type == char_event_type_t::eof; } + bool is_readline() const { return is_char() && c_ >= R_BEGIN_INPUT_FUNCTIONS && c_ < R_END_INPUT_FUNCTIONS; } diff --git a/src/reader.cpp b/src/reader.cpp index 63b88ad36..bf2a871fb 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2503,6 +2503,9 @@ maybe_t reader_data_t::readline(int nchars) { if (!event_needing_handling) { event_needing_handling = R_NULL; + } else if (event_needing_handling->is_eof()) { + reader_force_exit(); + continue; } assert(event_needing_handling->is_char() && "Should have a char event"); wchar_t c = event_needing_handling->get_char(); @@ -2577,10 +2580,6 @@ maybe_t reader_data_t::readline(int nchars) { } break; } - case R_EOF: { - reader_force_exit(); - break; - } case R_COMPLETE: case R_COMPLETE_AND_SEARCH: { if (!complete_func) break; From 1e5c1c82c71abe98ffa4184ef474d635b3c4848a Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 16 Mar 2019 13:33:42 -0700 Subject: [PATCH 0126/1732] Rename and simplify input_read_characters_eof_only Clarify its role. --- src/input.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index edcd02910..d784419dc 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -447,28 +447,24 @@ static void input_mapping_execute_matching_or_generic(bool allow_commands) { } /// Helper function. Picks through the queue of incoming characters until we get to one that's not a -/// readline function, or EOF. -static char_event_t input_read_characters_eof_only() { +/// readline function. +static char_event_t input_read_characters_no_readline() { std::vector saved_events; - char_event_t char_to_return{0}; + char_event_t evt_to_return{0}; for (;;) { auto evt = input_common_readch(); - if (evt.is_eof()) { - return evt; - } else if (evt.is_char()) { - auto c = evt.get_char(); - if (!evt.is_readline() || c == R_NULL) { - char_to_return = evt; - break; - } + if (evt.is_readline()) { + saved_events.push_back(evt); + } else { + evt_to_return = evt; + break; } - saved_events.push_back(evt); } // Restore any readline functions, in reverse to preserve their original order. for (auto iter = saved_events.rbegin(); iter != saved_events.rend(); ++iter) { input_common_next_ch(*iter); } - return char_to_return; + return evt_to_return; } char_event_t input_readch(bool allow_commands) { @@ -483,7 +479,7 @@ char_event_t input_readch(bool allow_commands) { case R_SELF_INSERT: { // Issue #1595: ensure we only insert characters, not readline functions. The // common case is that this will be empty. - return input_read_characters_eof_only(); + return input_read_characters_no_readline(); } case R_AND: { if (input_function_status) { From 46dfad52d97289b95d8dcd7922cc5c206956de86 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 16 Mar 2019 13:52:07 -0700 Subject: [PATCH 0127/1732] Switch the input interrupt function to return maybe_t Allow returning none() to mean do nothing. --- src/input.cpp | 8 ++++++-- src/input_common.cpp | 10 +++++----- src/input_common.h | 8 ++++++-- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index d784419dc..a228a9e44 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -249,14 +249,18 @@ void input_mapping_add(const wchar_t *sequence, const wchar_t *command, const wc /// Handle interruptions to key reading by reaping finshed jobs and propagating the interrupt to the /// reader. -static int interrupt_handler() { +static maybe_t interrupt_handler() { // Fire any pending events. event_fire_delayed(); // Reap stray processes, including printing exit status messages. if (job_reap(true)) reader_repaint_needed(); // Tell the reader an event occured. if (reader_reading_interrupted()) { - return shell_modes.c_cc[VINTR]; + auto vintr = shell_modes.c_cc[VINTR]; + if (vintr == 0) { + return none(); + } + return vintr; } return R_NULL; diff --git a/src/input_common.cpp b/src/input_common.cpp index c72ba8c7c..526a5d9e6 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -63,9 +63,9 @@ static void lookahead_push_back(char_event_t c) { lookahead_list.push_back(c); } static void lookahead_push_front(char_event_t c) { lookahead_list.push_front(c); } /// Callback function for handling interrupts on reading. -static int (*interrupt_handler)(); +static interrupt_func_t interrupt_handler; -void input_common_init(int (*ih)()) { interrupt_handler = ih; } +void input_common_init(interrupt_func_t func) { interrupt_handler = func; } /// Internal function used by input_common_readch to read one byte from fd 0. This function should /// only be called by input_common_readch(). @@ -115,9 +115,9 @@ static maybe_t readb() { if (res == -1) { if (errno == EINTR || errno == EAGAIN) { if (interrupt_handler) { - int res = interrupt_handler(); - if (res) return res; - if (auto mc = lookahead_pop_char()) { + if (auto interrupt_evt = interrupt_handler()) { + return *interrupt_evt; + } else if (auto mc = lookahead_pop_char()) { return *mc; } } diff --git a/src/input_common.h b/src/input_common.h index 1c8a2db6b..81c857d5d 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -122,8 +122,12 @@ class char_event_t { } }; -/// Init the library. -void input_common_init(int (*ih)()); +/// A type of function invoked on interrupt. +/// \return the event which is to be returned to the reader loop, or none if VINTR is 0. +using interrupt_func_t = maybe_t (*)(); + +/// Init the library with an interrupt function. +void input_common_init(interrupt_func_t func); /// Adjust the escape timeout. class environment_t; From 1ef2404e1ca61bc5c47a0693366e7c9cab1b1ca4 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 16 Mar 2019 14:08:00 -0700 Subject: [PATCH 0128/1732] readb to return char_event_t Avoids some annoying type conversions. --- src/input_common.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/input_common.cpp b/src/input_common.cpp index 526a5d9e6..f344232a1 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -69,8 +69,7 @@ void input_common_init(interrupt_func_t func) { interrupt_handler = func; } /// Internal function used by input_common_readch to read one byte from fd 0. This function should /// only be called by input_common_readch(). -/// \return the char, or none() on EOF. -static maybe_t readb() { +static char_event_t readb() { // do_loop must be set on every path through the loop; leaving it uninitialized allows the // static analyzer to assist in catching mistakes. unsigned char arr[1]; @@ -125,7 +124,7 @@ static maybe_t readb() { do_loop = true; } else { // The terminal has been closed. - return none(); + return char_event_type_t::eof; } } else { // Assume we loop unless we see a character in stdin. @@ -151,7 +150,7 @@ static maybe_t readb() { if (FD_ISSET(STDIN_FILENO, &fdset)) { if (read_blocked(0, arr, 1) != 1) { // The teminal has been closed. - return none(); + return char_event_type_t::eof; } // We read from stdin, so don't loop. @@ -190,13 +189,12 @@ char_event_t input_common_readch() { wchar_t res; mbstate_t state = {}; while (1) { - auto mb = readb(); - if (!mb) { - // EOF - return char_event_type_t::eof; + auto evt = readb(); + if (!evt.is_char() || evt.is_readline()) { + return evt; } - wint_t b = *mb; + wint_t b = evt.get_char(); if (b >= R_NULL && b < R_END_INPUT_FUNCTIONS) return b; if (MB_CUR_MAX == 1) { From 70a92a97101b40046f52d2adbf2f4747ef6cf353 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 16 Mar 2019 14:45:36 -0700 Subject: [PATCH 0129/1732] Switch interrupt_handler to return maybe_t Prepares to remove R_NULL --- src/input.cpp | 6 +++--- src/input_common.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index a228a9e44..4687ef283 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -249,7 +249,7 @@ void input_mapping_add(const wchar_t *sequence, const wchar_t *command, const wc /// Handle interruptions to key reading by reaping finshed jobs and propagating the interrupt to the /// reader. -static maybe_t interrupt_handler() { +static maybe_t interrupt_handler() { // Fire any pending events. event_fire_delayed(); // Reap stray processes, including printing exit status messages. @@ -260,10 +260,10 @@ static maybe_t interrupt_handler() { if (vintr == 0) { return none(); } - return vintr; + return char_event_t{vintr}; } - return R_NULL; + return char_event_t{R_NULL}; } static std::atomic input_initialized{false}; diff --git a/src/input_common.h b/src/input_common.h index 81c857d5d..2dc302383 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -124,7 +124,7 @@ class char_event_t { /// A type of function invoked on interrupt. /// \return the event which is to be returned to the reader loop, or none if VINTR is 0. -using interrupt_func_t = maybe_t (*)(); +using interrupt_func_t = maybe_t (*)(); /// Init the library with an interrupt function. void input_common_init(interrupt_func_t func); From 28b79a2c8868430cf536a5a7d356ae33d9afb761 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 16 Mar 2019 15:49:35 -0700 Subject: [PATCH 0130/1732] Some further steps towards removing R_NULL Introduce char_event_type_t::check_exit to represent "check for exit" instead of R_NULL. --- src/input.cpp | 14 +++++++------- src/input.h | 4 ++-- src/input_common.cpp | 14 ++++++++------ src/input_common.h | 10 +++++++--- src/reader.cpp | 2 +- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index 4687ef283..f344694f3 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -348,12 +348,12 @@ static void input_mapping_execute(const input_mapping_t &m, bool allow_commands) } if (has_commands && !allow_commands) { - // We don't want to run commands yet. Put the characters back and return R_NULL. + // We don't want to run commands yet. Put the characters back and return check_exit. for (wcstring::const_reverse_iterator it = m.seq.rbegin(), end = m.seq.rend(); it != end; ++it) { input_common_next_ch(*it); } - input_common_next_ch(R_NULL); + input_common_next_ch(char_event_type_t::check_exit); return; // skip the input_set_bind_mode } else if (has_functions && !has_commands) { // Functions are added at the head of the input queue. @@ -374,11 +374,11 @@ static void input_mapping_execute(const input_mapping_t &m, bool allow_commands) parser_t::principal_parser().eval(cmd, io_chain_t(), TOP); } proc_set_last_statuses(std::move(last_statuses)); - input_common_next_ch(R_NULL); + input_common_next_ch(char_event_type_t::check_exit); } else { // Invalid binding, mixed commands and functions. We would need to execute these one by // one. - input_common_next_ch(R_NULL); + input_common_next_ch(char_event_type_t::check_exit); } // Empty bind mode indicates to not reset the mode (#2871) @@ -504,9 +504,9 @@ char_event_t input_readch(bool allow_commands) { } else { input_common_next_ch(evt); input_mapping_execute_matching_or_generic(allow_commands); - // Regarding allow_commands, we're in a loop, but if a fish command - // is executed, R_NULL is unread, so the next pass through the loop - // we'll break out and return it. + // Regarding allow_commands, we're in a loop, but if a fish command is executed, + // check_exit is unread, so the next pass through the loop we'll break out and return + // it. } } } diff --git a/src/input.h b/src/input.h index fc20d24db..a5d582306 100644 --- a/src/input.h +++ b/src/input.h @@ -31,8 +31,8 @@ void init_input(); /// key press, and is returned as such. /// /// The argument determines whether fish commands are allowed to be run as bindings. If false, when -/// a character is encountered that would invoke a fish command, it is unread and R_NULL is -/// returned. +/// a character is encountered that would invoke a fish command, it is unread and +/// char_event_type_t::check_exit is returned. char_event_t input_readch(bool allow_commands = true); /// Enqueue a character or a readline function to the queue of unread characters that input_readch diff --git a/src/input_common.cpp b/src/input_common.cpp index f344232a1..d71bbb91f 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -50,10 +50,12 @@ static char_event_t lookahead_pop() { } /// \return the next lookahead char, or none if none. Discards timeouts. -static maybe_t lookahead_pop_char() { +static maybe_t lookahead_pop_evt() { while (has_lookahead()) { auto evt = lookahead_pop(); - if (evt.is_char()) return evt.get_char(); + if (! evt.is_timeout()) { + return evt; + } } return none(); } @@ -116,7 +118,7 @@ static char_event_t readb() { if (interrupt_handler) { if (auto interrupt_evt = interrupt_handler()) { return *interrupt_evt; - } else if (auto mc = lookahead_pop_char()) { + } else if (auto mc = lookahead_pop_evt()) { return *mc; } } @@ -142,7 +144,7 @@ static char_event_t readb() { if (ioport > 0 && FD_ISSET(ioport, &fdset)) { iothread_service_completion(); - if (auto mc = lookahead_pop_char()) { + if (auto mc = lookahead_pop_evt()) { return *mc; } } @@ -183,7 +185,7 @@ void update_wait_on_escape_ms(const environment_t &vars) { } char_event_t input_common_readch() { - if (auto mc = lookahead_pop_char()) { + if (auto mc = lookahead_pop_evt()) { return *mc; } wchar_t res; @@ -208,7 +210,7 @@ char_event_t input_common_readch() { case (size_t)(-1): { std::memset(&state, '\0', sizeof(state)); debug(2, L"Illegal input"); - return R_NULL; + return char_event_type_t::check_exit; } case (size_t)(-2): { break; diff --git a/src/input_common.h b/src/input_common.h index 2dc302383..51aa41f60 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -11,8 +11,6 @@ enum { R_MIN = INPUT_COMMON_BASE, - // R_NULL is sometimes returned by the input when a character was requested but none could be - // delivered, or when an exception happened. R_NULL = R_MIN, R_BEGINNING_OF_LINE, @@ -89,7 +87,11 @@ enum class char_event_type_t { timeout, /// end-of-file was reached. - eof + eof, + + /// An event was handled internally, or an interrupt was received. Check to see if the reader + /// loop should exit. + check_exit, }; class char_event_t { @@ -105,6 +107,8 @@ class char_event_t { bool is_eof() const { return type == char_event_type_t::eof; } + bool is_check_exit() const { return type == char_event_type_t::check_exit; } + bool is_readline() const { return is_char() && c_ >= R_BEGIN_INPUT_FUNCTIONS && c_ < R_END_INPUT_FUNCTIONS; } diff --git a/src/reader.cpp b/src/reader.cpp index bf2a871fb..19c455b44 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2501,7 +2501,7 @@ maybe_t reader_data_t::readline(int nchars) { } } - if (!event_needing_handling) { + if (!event_needing_handling || event_needing_handling->is_check_exit()) { event_needing_handling = R_NULL; } else if (event_needing_handling->is_eof()) { reader_force_exit(); From 14663089c87f5acdd44acb90a0e21c3643887e79 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 16 Mar 2019 15:56:37 -0700 Subject: [PATCH 0131/1732] Finish removing R_NULL --- src/input.cpp | 2 +- src/input_common.cpp | 2 -- src/input_common.h | 3 +-- src/reader.cpp | 9 +++------ 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index f344694f3..4b183b80c 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -263,7 +263,7 @@ static maybe_t interrupt_handler() { return char_event_t{vintr}; } - return char_event_t{R_NULL}; + return char_event_t{char_event_type_t::check_exit}; } static std::atomic input_initialized{false}; diff --git a/src/input_common.cpp b/src/input_common.cpp index d71bbb91f..29826459a 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -197,8 +197,6 @@ char_event_t input_common_readch() { } wint_t b = evt.get_char(); - if (b >= R_NULL && b < R_END_INPUT_FUNCTIONS) return b; - if (MB_CUR_MAX == 1) { return b; // single-byte locale, all values are legal } diff --git a/src/input_common.h b/src/input_common.h index 51aa41f60..85db7b5c6 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -11,9 +11,8 @@ enum { R_MIN = INPUT_COMMON_BASE, - R_NULL = R_MIN, - R_BEGINNING_OF_LINE, + R_BEGINNING_OF_LINE = R_MIN, R_END_OF_LINE, R_FORWARD_CHAR, R_BACKWARD_CHAR, diff --git a/src/reader.cpp b/src/reader.cpp index 19c455b44..b911f2a2f 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -1044,7 +1044,6 @@ static bool command_ends_paging(wchar_t c, bool focused_on_search_field) { case R_FORWARD_CHAR: case R_UP_LINE: case R_DOWN_LINE: - case R_NULL: case R_REPAINT: case R_SUPPRESS_AUTOSUGGESTION: case R_BEGINNING_OF_HISTORY: @@ -2502,7 +2501,8 @@ maybe_t reader_data_t::readline(int nchars) { } if (!event_needing_handling || event_needing_handling->is_check_exit()) { - event_needing_handling = R_NULL; + repaint_if_needed(); + continue; } else if (event_needing_handling->is_eof()) { reader_force_exit(); continue; @@ -2562,9 +2562,6 @@ maybe_t reader_data_t::readline(int nchars) { reader_repaint_needed(); break; } - case R_NULL: { - break; - } case R_CANCEL: { // The only thing we can cancel right now is paging, which we handled up above. break; @@ -3267,7 +3264,7 @@ maybe_t reader_data_t::readline(int nchars) { if ((c != R_HISTORY_SEARCH_BACKWARD) && (c != R_HISTORY_SEARCH_FORWARD) && (c != R_HISTORY_TOKEN_SEARCH_BACKWARD) && (c != R_HISTORY_TOKEN_SEARCH_FORWARD) && - (c != R_NULL) && (c != R_REPAINT) && (c != R_FORCE_REPAINT)) { + (c != R_REPAINT) && (c != R_FORCE_REPAINT)) { history_search.reset(); } From c2be5e8986ae7c2f5ffa155be0efea09629548a6 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 16 Mar 2019 16:48:23 -0700 Subject: [PATCH 0132/1732] Introduce char_event_type_t::readline Baby steps towards eliminating readline actions as characters. --- src/fish_tests.cpp | 8 ++++---- src/input.cpp | 4 ++-- src/input_common.cpp | 4 ++-- src/input_common.h | 22 ++++++++++++++++------ src/reader.cpp | 6 ++++-- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 151488367..5ace2a730 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -2997,11 +2997,11 @@ static void test_input() { // Now test. auto evt = input_readch(); - if (!evt.is_char()) { - err(L"Event is not a char"); - } else if (evt.get_char() != R_DOWN_LINE) { + if (!evt.is_readline()) { + err(L"Event is not a readline"); + } else if (evt.get_readline() != R_DOWN_LINE) { err(L"Expected to read char R_DOWN_LINE, but instead got %ls\n", - describe_char(evt.get_char()).c_str()); + describe_char(evt.get_readline()).c_str()); } } diff --git a/src/input.cpp b/src/input.cpp index 4b183b80c..227620dd7 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -311,7 +311,7 @@ void input_function_push_args(int code) { wchar_t arg{}; for (;;) { auto evt = input_common_readch(); - if (evt.is_char() && !evt.is_readline()) { + if (evt.is_char()) { arg = evt.get_char(); break; } @@ -479,7 +479,7 @@ char_event_t input_readch(bool allow_commands) { auto evt = input_common_readch(); if (evt.is_readline()) { - switch (evt.get_char()) { + switch (evt.get_readline()) { case R_SELF_INSERT: { // Issue #1595: ensure we only insert characters, not readline functions. The // common case is that this will be empty. diff --git a/src/input_common.cpp b/src/input_common.cpp index 29826459a..df3bbfcd1 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -192,7 +192,7 @@ char_event_t input_common_readch() { mbstate_t state = {}; while (1) { auto evt = readb(); - if (!evt.is_char() || evt.is_readline()) { + if (!evt.is_char()) { return evt; } @@ -239,7 +239,7 @@ char_event_t input_common_readch_timed(bool dequeue_timeouts) { if (!dequeue_timeouts) lookahead_push_front(char_event_type_t::timeout); return char_event_type_t::timeout; } - return result.get_char(); + return result; } void input_common_queue_ch(char_event_t ch) { lookahead_push_back(ch); } diff --git a/src/input_common.h b/src/input_common.h index 85db7b5c6..550143ce3 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -82,6 +82,9 @@ enum class char_event_type_t { /// A character was entered. charc, + /// A readline event. + readline, + /// A timeout was hit. timeout, @@ -94,7 +97,7 @@ enum class char_event_type_t { }; class char_event_t { - /// Set if the type is charc. + /// Set if the type is charc or readline. wchar_t c_; public: @@ -108,19 +111,26 @@ class char_event_t { bool is_check_exit() const { return type == char_event_type_t::check_exit; } - bool is_readline() const { - return is_char() && c_ >= R_BEGIN_INPUT_FUNCTIONS && c_ < R_END_INPUT_FUNCTIONS; - } + bool is_readline() const { return type == char_event_type_t::readline; } wchar_t get_char() const { assert(type == char_event_type_t::charc && "Not a char type"); return c_; } - /* implicit */ char_event_t(wchar_t c) : c_(c), type(char_event_type_t::charc) {} + wchar_t get_readline() const { + assert(type == char_event_type_t::readline && "Not a readline type"); + return c_; + } + + /* implicit */ char_event_t(wchar_t c) + : c_(c), + type(R_BEGIN_INPUT_FUNCTIONS <= c && c < R_END_INPUT_FUNCTIONS + ? char_event_type_t::readline + : char_event_type_t::charc) {} /* implicit */ char_event_t(char_event_type_t type) : c_(0), type(type) { - assert(type != char_event_type_t::charc && + assert(type != char_event_type_t::charc && type != char_event_type_t::readline && "Cannot create a char event with this constructor"); } }; diff --git a/src/reader.cpp b/src/reader.cpp index b911f2a2f..d2b4ddbad 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2507,8 +2507,10 @@ maybe_t reader_data_t::readline(int nchars) { reader_force_exit(); continue; } - assert(event_needing_handling->is_char() && "Should have a char event"); - wchar_t c = event_needing_handling->get_char(); + assert((event_needing_handling->is_char() || event_needing_handling->is_readline()) && + "Should have a char or readline"); + wchar_t c = event_needing_handling->is_char() ? event_needing_handling->get_char() + : event_needing_handling->get_readline(); // If we get something other than a repaint, then stop coalescing them. if (c != R_REPAINT) coalescing_repaints = false; From b68d3b84de2210862e5900383521a2d4845e4e46 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 16 Mar 2019 17:05:33 -0700 Subject: [PATCH 0133/1732] Switch input_function_get_code() to return maybe_t --- src/builtin_commandline.cpp | 5 ++--- src/input.cpp | 8 ++++---- src/input.h | 3 +-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/builtin_commandline.cpp b/src/builtin_commandline.cpp index 5f7c27a16..a4fb80f46 100644 --- a/src/builtin_commandline.cpp +++ b/src/builtin_commandline.cpp @@ -325,11 +325,10 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) } for (i = w.woptind; i < argc; i++) { - wchar_t c = input_function_get_code(argv[i]); - if (c != INPUT_CODE_NONE) { + if (auto mc = input_function_get_code(argv[i])) { // input_unreadch inserts the specified keypress or readline function at the back of // the queue of unused keypresses. - input_queue_ch(c); + input_queue_ch(*mc); } else { streams.err.append_format(_(L"%ls: Unknown input function '%ls'"), cmd, argv[i]); builtin_print_help(parser, streams, cmd, streams.err); diff --git a/src/input.cpp b/src/input.cpp index 227620dd7..f68c5f179 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -335,7 +335,7 @@ static void input_mapping_execute(const input_mapping_t &m, bool allow_commands) bool has_commands = false, has_functions = false; for (const wcstring &cmd : m.commands) { - if (input_function_get_code(cmd) != INPUT_CODE_NONE) + if (input_function_get_code(cmd)) has_functions = true; else has_commands = true; @@ -360,7 +360,7 @@ static void input_mapping_execute(const input_mapping_t &m, bool allow_commands) for (wcstring_list_t::const_reverse_iterator it = m.commands.rbegin(), end = m.commands.rend(); it != end; ++it) { - wchar_t code = input_function_get_code(*it); + wchar_t code = input_function_get_code(*it).value(); input_function_push_args(code); input_common_next_ch(code); } @@ -794,11 +794,11 @@ wcstring_list_t input_function_get_names() { return result; } -wchar_t input_function_get_code(const wcstring &name) { +maybe_t input_function_get_code(const wcstring &name) { for (const auto &md : input_function_metadata) { if (name == md.name) { return md.code; } } - return INPUT_CODE_NONE; + return none(); } diff --git a/src/input.h b/src/input.h index a5d582306..bd3df452b 100644 --- a/src/input.h +++ b/src/input.h @@ -95,8 +95,7 @@ bool input_terminfo_get_name(const wcstring &seq, wcstring *out_name); wcstring_list_t input_terminfo_get_names(bool skip_null); /// Returns the input function code for the given input function name. -#define INPUT_CODE_NONE (wchar_t(-1)) -wchar_t input_function_get_code(const wcstring &name); +maybe_t input_function_get_code(const wcstring &name); /// Returns a list of all existing input function names. wcstring_list_t input_function_get_names(void); From 08410724620d184416133108def8ccc3b3c16525 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 16 Mar 2019 17:26:42 -0700 Subject: [PATCH 0134/1732] Minor cleanup of kill ring --- src/kill.cpp | 19 ++++++++++--------- src/kill.h | 6 +++--- src/reader.cpp | 9 ++++----- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/kill.cpp b/src/kill.cpp index b005ba824..89fa8124c 100644 --- a/src/kill.cpp +++ b/src/kill.cpp @@ -17,10 +17,11 @@ typedef std::list kill_list_t; static kill_list_t kill_list; -void kill_add(const wcstring &str) { +void kill_add(wcstring str) { ASSERT_IS_MAIN_THREAD(); - if (str.empty()) return; - kill_list.push_front(str); + if (!str.empty()) { + kill_list.push_front(std::move(str)); + } } /// Remove first match for specified string from circular list. @@ -35,19 +36,19 @@ void kill_replace(const wcstring &old, const wcstring &newv) { kill_add(newv); } -const wchar_t *kill_yank_rotate() { +wcstring kill_yank_rotate() { ASSERT_IS_MAIN_THREAD(); // Move the first element to the end. if (kill_list.empty()) { - return NULL; + return {}; } kill_list.splice(kill_list.end(), kill_list, kill_list.begin()); - return kill_list.front().c_str(); + return kill_list.front(); } -const wchar_t *kill_yank() { +wcstring kill_yank() { if (kill_list.empty()) { - return L""; + return {}; } - return kill_list.front().c_str(); + return kill_list.front(); } diff --git a/src/kill.h b/src/kill.h index e22fb57f6..8e959ca50 100644 --- a/src/kill.h +++ b/src/kill.h @@ -11,12 +11,12 @@ void kill_replace(const wcstring &old, const wcstring &newv); /// Add a string to the top of the killring. -void kill_add(const wcstring &str); +void kill_add(wcstring str); /// Rotate the killring. -const wchar_t *kill_yank_rotate(); +wcstring kill_yank_rotate(); /// Paste from the killring. -const wchar_t *kill_yank(); +wcstring kill_yank(); #endif diff --git a/src/reader.cpp b/src/reader.cpp index d2b4ddbad..f50c4bc5d 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2391,7 +2391,6 @@ static bool event_is_normal_char(const char_event_t &evt) { maybe_t reader_data_t::readline(int nchars) { int last_char = 0; size_t yank_len = 0; - const wchar_t *yank_str; bool comp_empty = true; std::vector comp; int finished = 0; @@ -2746,18 +2745,18 @@ maybe_t reader_data_t::readline(int nchars) { break; } case R_YANK: { - yank_str = kill_yank(); + wcstring yank_str = kill_yank(); insert_string(active_edit_line(), yank_str); - yank_len = std::wcslen(yank_str); + yank_len = yank_str.size(); break; } case R_YANK_POP: { if (yank_len) { for (size_t i = 0; i < yank_len; i++) remove_backward(); - yank_str = kill_yank_rotate(); + wcstring yank_str = kill_yank_rotate(); insert_string(active_edit_line(), yank_str); - yank_len = std::wcslen(yank_str); + yank_len = yank_str.size(); } break; } From 2c56e27d374e09f9b18e2aad13a1d873c7bcb223 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 16 Mar 2019 17:56:35 -0700 Subject: [PATCH 0135/1732] Switch readline commands to readline_cmd_t enum class --- src/fish_tests.cpp | 5 +- src/input.cpp | 139 +++++++-------- src/input.h | 2 +- src/input_common.h | 44 ++--- src/maybe.h | 6 + src/reader.cpp | 413 ++++++++++++++++++++++++--------------------- 6 files changed, 323 insertions(+), 286 deletions(-) diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 5ace2a730..7d6a7109e 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -2999,9 +2999,8 @@ static void test_input() { auto evt = input_readch(); if (!evt.is_readline()) { err(L"Event is not a readline"); - } else if (evt.get_readline() != R_DOWN_LINE) { - err(L"Expected to read char R_DOWN_LINE, but instead got %ls\n", - describe_char(evt.get_readline()).c_str()); + } else if (evt.get_readline() != readline_cmd_t::R_DOWN_LINE) { + err(L"Expected to read char R_DOWN_LINE"); } } diff --git a/src/input.cpp b/src/input.cpp index f68c5f179..860edb2b4 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -67,68 +67,69 @@ static constexpr size_t input_function_count = R_END_INPUT_FUNCTIONS - R_BEGIN_I /// Input function metadata. This list should be kept in sync with the key code list in /// input_common.h. struct input_function_metadata_t { - wchar_t code; + readline_cmd_t code; const wchar_t *name; }; + static const input_function_metadata_t input_function_metadata[] = { - {R_BEGINNING_OF_LINE, L"beginning-of-line"}, - {R_END_OF_LINE, L"end-of-line"}, - {R_FORWARD_CHAR, L"forward-char"}, - {R_BACKWARD_CHAR, L"backward-char"}, - {R_FORWARD_WORD, L"forward-word"}, - {R_BACKWARD_WORD, L"backward-word"}, - {R_FORWARD_BIGWORD, L"forward-bigword"}, - {R_BACKWARD_BIGWORD, L"backward-bigword"}, - {R_HISTORY_SEARCH_BACKWARD, L"history-search-backward"}, - {R_HISTORY_SEARCH_FORWARD, L"history-search-forward"}, - {R_DELETE_CHAR, L"delete-char"}, - {R_BACKWARD_DELETE_CHAR, L"backward-delete-char"}, - {R_KILL_LINE, L"kill-line"}, - {R_YANK, L"yank"}, - {R_YANK_POP, L"yank-pop"}, - {R_COMPLETE, L"complete"}, - {R_COMPLETE_AND_SEARCH, L"complete-and-search"}, - {R_PAGER_TOGGLE_SEARCH, L"pager-toggle-search"}, - {R_BEGINNING_OF_HISTORY, L"beginning-of-history"}, - {R_END_OF_HISTORY, L"end-of-history"}, - {R_BACKWARD_KILL_LINE, L"backward-kill-line"}, - {R_KILL_WHOLE_LINE, L"kill-whole-line"}, - {R_KILL_WORD, L"kill-word"}, - {R_KILL_BIGWORD, L"kill-bigword"}, - {R_BACKWARD_KILL_WORD, L"backward-kill-word"}, - {R_BACKWARD_KILL_PATH_COMPONENT, L"backward-kill-path-component"}, - {R_BACKWARD_KILL_BIGWORD, L"backward-kill-bigword"}, - {R_HISTORY_TOKEN_SEARCH_BACKWARD, L"history-token-search-backward"}, - {R_HISTORY_TOKEN_SEARCH_FORWARD, L"history-token-search-forward"}, - {R_SELF_INSERT, L"self-insert"}, - {R_TRANSPOSE_CHARS, L"transpose-chars"}, - {R_TRANSPOSE_WORDS, L"transpose-words"}, - {R_UPCASE_WORD, L"upcase-word"}, - {R_DOWNCASE_WORD, L"downcase-word"}, - {R_CAPITALIZE_WORD, L"capitalize-word"}, - {R_VI_ARG_DIGIT, L"vi-arg-digit"}, - {R_VI_DELETE_TO, L"vi-delete-to"}, - {R_EXECUTE, L"execute"}, - {R_BEGINNING_OF_BUFFER, L"beginning-of-buffer"}, - {R_END_OF_BUFFER, L"end-of-buffer"}, - {R_REPAINT, L"repaint"}, - {R_FORCE_REPAINT, L"force-repaint"}, - {R_UP_LINE, L"up-line"}, - {R_DOWN_LINE, L"down-line"}, - {R_SUPPRESS_AUTOSUGGESTION, L"suppress-autosuggestion"}, - {R_ACCEPT_AUTOSUGGESTION, L"accept-autosuggestion"}, - {R_BEGIN_SELECTION, L"begin-selection"}, - {R_SWAP_SELECTION_START_STOP, L"swap-selection-start-stop"}, - {R_END_SELECTION, L"end-selection"}, - {R_KILL_SELECTION, L"kill-selection"}, - {R_FORWARD_JUMP, L"forward-jump"}, - {R_BACKWARD_JUMP, L"backward-jump"}, - {R_FORWARD_JUMP_TILL, L"forward-jump-till"}, - {R_BACKWARD_JUMP_TILL, L"backward-jump-till"}, - {R_REPEAT_JUMP, L"repeat-jump"}, - {R_REVERSE_REPEAT_JUMP, L"repeat-jump-reverse"}, - {R_AND, L"and"}, - {R_CANCEL, L"cancel"}}; + {readline_cmd_t::R_BEGINNING_OF_LINE, L"beginning-of-line"}, + {readline_cmd_t::R_END_OF_LINE, L"end-of-line"}, + {readline_cmd_t::R_FORWARD_CHAR, L"forward-char"}, + {readline_cmd_t::R_BACKWARD_CHAR, L"backward-char"}, + {readline_cmd_t::R_FORWARD_WORD, L"forward-word"}, + {readline_cmd_t::R_BACKWARD_WORD, L"backward-word"}, + {readline_cmd_t::R_FORWARD_BIGWORD, L"forward-bigword"}, + {readline_cmd_t::R_BACKWARD_BIGWORD, L"backward-bigword"}, + {readline_cmd_t::R_HISTORY_SEARCH_BACKWARD, L"history-search-backward"}, + {readline_cmd_t::R_HISTORY_SEARCH_FORWARD, L"history-search-forward"}, + {readline_cmd_t::R_DELETE_CHAR, L"delete-char"}, + {readline_cmd_t::R_BACKWARD_DELETE_CHAR, L"backward-delete-char"}, + {readline_cmd_t::R_KILL_LINE, L"kill-line"}, + {readline_cmd_t::R_YANK, L"yank"}, + {readline_cmd_t::R_YANK_POP, L"yank-pop"}, + {readline_cmd_t::R_COMPLETE, L"complete"}, + {readline_cmd_t::R_COMPLETE_AND_SEARCH, L"complete-and-search"}, + {readline_cmd_t::R_PAGER_TOGGLE_SEARCH, L"pager-toggle-search"}, + {readline_cmd_t::R_BEGINNING_OF_HISTORY, L"beginning-of-history"}, + {readline_cmd_t::R_END_OF_HISTORY, L"end-of-history"}, + {readline_cmd_t::R_BACKWARD_KILL_LINE, L"backward-kill-line"}, + {readline_cmd_t::R_KILL_WHOLE_LINE, L"kill-whole-line"}, + {readline_cmd_t::R_KILL_WORD, L"kill-word"}, + {readline_cmd_t::R_KILL_BIGWORD, L"kill-bigword"}, + {readline_cmd_t::R_BACKWARD_KILL_WORD, L"backward-kill-word"}, + {readline_cmd_t::R_BACKWARD_KILL_PATH_COMPONENT, L"backward-kill-path-component"}, + {readline_cmd_t::R_BACKWARD_KILL_BIGWORD, L"backward-kill-bigword"}, + {readline_cmd_t::R_HISTORY_TOKEN_SEARCH_BACKWARD, L"history-token-search-backward"}, + {readline_cmd_t::R_HISTORY_TOKEN_SEARCH_FORWARD, L"history-token-search-forward"}, + {readline_cmd_t::R_SELF_INSERT, L"self-insert"}, + {readline_cmd_t::R_TRANSPOSE_CHARS, L"transpose-chars"}, + {readline_cmd_t::R_TRANSPOSE_WORDS, L"transpose-words"}, + {readline_cmd_t::R_UPCASE_WORD, L"upcase-word"}, + {readline_cmd_t::R_DOWNCASE_WORD, L"downcase-word"}, + {readline_cmd_t::R_CAPITALIZE_WORD, L"capitalize-word"}, + {readline_cmd_t::R_VI_ARG_DIGIT, L"vi-arg-digit"}, + {readline_cmd_t::R_VI_DELETE_TO, L"vi-delete-to"}, + {readline_cmd_t::R_EXECUTE, L"execute"}, + {readline_cmd_t::R_BEGINNING_OF_BUFFER, L"beginning-of-buffer"}, + {readline_cmd_t::R_END_OF_BUFFER, L"end-of-buffer"}, + {readline_cmd_t::R_REPAINT, L"repaint"}, + {readline_cmd_t::R_FORCE_REPAINT, L"force-repaint"}, + {readline_cmd_t::R_UP_LINE, L"up-line"}, + {readline_cmd_t::R_DOWN_LINE, L"down-line"}, + {readline_cmd_t::R_SUPPRESS_AUTOSUGGESTION, L"suppress-autosuggestion"}, + {readline_cmd_t::R_ACCEPT_AUTOSUGGESTION, L"accept-autosuggestion"}, + {readline_cmd_t::R_BEGIN_SELECTION, L"begin-selection"}, + {readline_cmd_t::R_SWAP_SELECTION_START_STOP, L"swap-selection-start-stop"}, + {readline_cmd_t::R_END_SELECTION, L"end-selection"}, + {readline_cmd_t::R_KILL_SELECTION, L"kill-selection"}, + {readline_cmd_t::R_FORWARD_JUMP, L"forward-jump"}, + {readline_cmd_t::R_BACKWARD_JUMP, L"backward-jump"}, + {readline_cmd_t::R_FORWARD_JUMP_TILL, L"forward-jump-till"}, + {readline_cmd_t::R_BACKWARD_JUMP_TILL, L"backward-jump-till"}, + {readline_cmd_t::R_REPEAT_JUMP, L"repeat-jump"}, + {readline_cmd_t::R_REVERSE_REPEAT_JUMP, L"repeat-jump-reverse"}, + {readline_cmd_t::R_AND, L"and"}, + {readline_cmd_t::R_CANCEL, L"cancel"}}; static_assert(sizeof(input_function_metadata) / sizeof(input_function_metadata[0]) == input_function_count, @@ -182,12 +183,12 @@ void input_set_bind_mode(const wcstring &bm) { } /// Returns the arity of a given input function. -static int input_function_arity(int function) { +static int input_function_arity(readline_cmd_t function) { switch (function) { - case R_FORWARD_JUMP: - case R_BACKWARD_JUMP: - case R_FORWARD_JUMP_TILL: - case R_BACKWARD_JUMP_TILL: + case readline_cmd_t::R_FORWARD_JUMP: + case readline_cmd_t::R_BACKWARD_JUMP: + case readline_cmd_t::R_FORWARD_JUMP_TILL: + case readline_cmd_t::R_BACKWARD_JUMP_TILL: return 1; default: return 0; @@ -302,7 +303,7 @@ void input_function_push_arg(wchar_t arg) { wchar_t input_function_pop_arg() { return input_function_args[--input_function_args_index]; } -void input_function_push_args(int code) { +void input_function_push_args(readline_cmd_t code) { int arity = input_function_arity(code); std::vector skipped; @@ -360,7 +361,7 @@ static void input_mapping_execute(const input_mapping_t &m, bool allow_commands) for (wcstring_list_t::const_reverse_iterator it = m.commands.rbegin(), end = m.commands.rend(); it != end; ++it) { - wchar_t code = input_function_get_code(*it).value(); + readline_cmd_t code = input_function_get_code(*it).value(); input_function_push_args(code); input_common_next_ch(code); } @@ -480,12 +481,12 @@ char_event_t input_readch(bool allow_commands) { if (evt.is_readline()) { switch (evt.get_readline()) { - case R_SELF_INSERT: { + case readline_cmd_t::R_SELF_INSERT: { // Issue #1595: ensure we only insert characters, not readline functions. The // common case is that this will be empty. return input_read_characters_no_readline(); } - case R_AND: { + case readline_cmd_t::R_AND: { if (input_function_status) { return input_readch(); } @@ -794,7 +795,7 @@ wcstring_list_t input_function_get_names() { return result; } -maybe_t input_function_get_code(const wcstring &name) { +maybe_t input_function_get_code(const wcstring &name) { for (const auto &md : input_function_metadata) { if (name == md.name) { return md.code; diff --git a/src/input.h b/src/input.h index bd3df452b..f76cede6a 100644 --- a/src/input.h +++ b/src/input.h @@ -95,7 +95,7 @@ bool input_terminfo_get_name(const wcstring &seq, wcstring *out_name); wcstring_list_t input_terminfo_get_names(bool skip_null); /// Returns the input function code for the given input function name. -maybe_t input_function_get_code(const wcstring &name); +maybe_t input_function_get_code(const wcstring &name); /// Returns a list of all existing input function names. wcstring_list_t input_function_get_names(void); diff --git a/src/input_common.h b/src/input_common.h index 550143ce3..7bbf5bed7 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -9,10 +9,8 @@ #include "common.h" #include "maybe.h" -enum { - R_MIN = INPUT_COMMON_BASE, - - R_BEGINNING_OF_LINE = R_MIN, +enum class readline_cmd_t { + R_BEGINNING_OF_LINE = INPUT_COMMON_BASE, R_END_OF_LINE, R_FORWARD_CHAR, R_BACKWARD_CHAR, @@ -70,15 +68,16 @@ enum { R_CANCEL, R_REPEAT_JUMP, R_REVERSE_REPEAT_JUMP, +}; - // The range of key codes for inputrc-style keyboard functions that are passed on to the caller - // of input_read(). - R_BEGIN_INPUT_FUNCTIONS = R_BEGINNING_OF_LINE, - R_END_INPUT_FUNCTIONS = R_REVERSE_REPEAT_JUMP + 1 +// The range of key codes for inputrc-style keyboard functions. +enum { + R_BEGIN_INPUT_FUNCTIONS = static_cast(readline_cmd_t::R_BEGINNING_OF_LINE), + R_END_INPUT_FUNCTIONS = static_cast(readline_cmd_t::R_REVERSE_REPEAT_JUMP) + 1 }; /// Represents an event on the character input stream. -enum class char_event_type_t { +enum class char_event_type_t : uint8_t { /// A character was entered. charc, @@ -97,8 +96,13 @@ enum class char_event_type_t { }; class char_event_t { - /// Set if the type is charc or readline. - wchar_t c_; + union { + /// Set if the type is charc. + wchar_t c; + + /// Set if the type is readline. + readline_cmd_t rl; + } v_{}; public: char_event_type_t type; @@ -115,21 +119,21 @@ class char_event_t { wchar_t get_char() const { assert(type == char_event_type_t::charc && "Not a char type"); - return c_; + return v_.c; } - wchar_t get_readline() const { + readline_cmd_t get_readline() const { assert(type == char_event_type_t::readline && "Not a readline type"); - return c_; + return v_.rl; } - /* implicit */ char_event_t(wchar_t c) - : c_(c), - type(R_BEGIN_INPUT_FUNCTIONS <= c && c < R_END_INPUT_FUNCTIONS - ? char_event_type_t::readline - : char_event_type_t::charc) {} + /* implicit */ char_event_t(wchar_t c) : type(char_event_type_t::charc) { v_.c = c; } - /* implicit */ char_event_t(char_event_type_t type) : c_(0), type(type) { + /* implicit */ char_event_t(readline_cmd_t rl) : type(char_event_type_t::readline) { + v_.rl = rl; + } + + /* implicit */ char_event_t(char_event_type_t type) : type(type) { assert(type != char_event_type_t::charc && type != char_event_type_t::readline && "Cannot create a char event with this constructor"); } diff --git a/src/maybe.h b/src/maybe.h index a3e5cebda..b86b1c1ee 100644 --- a/src/maybe.h +++ b/src/maybe.h @@ -203,6 +203,12 @@ class maybe_t : private maybe_detail::conditionally_copyable_t { } bool operator!=(const maybe_t &rhs) const { return !(*this == rhs); } + + bool operator==(const T &rhs) const { return this->has_value() && this->value() == rhs; } + + bool operator!=(const T &rhs) const { return !(*this == rhs); } + + ~maybe_t() { reset(); } }; #endif diff --git a/src/reader.cpp b/src/reader.cpp index f50c4bc5d..8b663c2e7 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -1027,67 +1027,83 @@ void reader_force_exit() { } /// Indicates if the given command char ends paging. -static bool command_ends_paging(wchar_t c, bool focused_on_search_field) { +static bool command_ends_paging(readline_cmd_t c, bool focused_on_search_field) { + using rl = readline_cmd_t; switch (c) { - case R_HISTORY_SEARCH_BACKWARD: - case R_HISTORY_SEARCH_FORWARD: - case R_HISTORY_TOKEN_SEARCH_BACKWARD: - case R_HISTORY_TOKEN_SEARCH_FORWARD: - case R_ACCEPT_AUTOSUGGESTION: - case R_CANCEL: { + case rl::R_HISTORY_SEARCH_BACKWARD: + case rl::R_HISTORY_SEARCH_FORWARD: + case rl::R_HISTORY_TOKEN_SEARCH_BACKWARD: + case rl::R_HISTORY_TOKEN_SEARCH_FORWARD: + case rl::R_ACCEPT_AUTOSUGGESTION: + case rl::R_CANCEL: { // These commands always end paging. return true; } - case R_COMPLETE: - case R_COMPLETE_AND_SEARCH: - case R_BACKWARD_CHAR: - case R_FORWARD_CHAR: - case R_UP_LINE: - case R_DOWN_LINE: - case R_REPAINT: - case R_SUPPRESS_AUTOSUGGESTION: - case R_BEGINNING_OF_HISTORY: - case R_END_OF_HISTORY: { + case rl::R_COMPLETE: + case rl::R_COMPLETE_AND_SEARCH: + case rl::R_BACKWARD_CHAR: + case rl::R_FORWARD_CHAR: + case rl::R_UP_LINE: + case rl::R_DOWN_LINE: + case rl::R_REPAINT: + case rl::R_SUPPRESS_AUTOSUGGESTION: + case rl::R_BEGINNING_OF_HISTORY: + case rl::R_END_OF_HISTORY: { // These commands never end paging. return false; } - case R_EXECUTE: { + case rl::R_EXECUTE: { // R_EXECUTE does end paging, but only executes if it was not paging. So it's handled // specially. return false; } - case R_BEGINNING_OF_LINE: - case R_END_OF_LINE: - case R_FORWARD_WORD: - case R_BACKWARD_WORD: - case R_FORWARD_BIGWORD: - case R_BACKWARD_BIGWORD: - case R_DELETE_CHAR: - case R_BACKWARD_DELETE_CHAR: - case R_KILL_LINE: - case R_YANK: - case R_YANK_POP: - case R_BACKWARD_KILL_LINE: - case R_KILL_WHOLE_LINE: - case R_KILL_WORD: - case R_KILL_BIGWORD: - case R_BACKWARD_KILL_WORD: - case R_BACKWARD_KILL_PATH_COMPONENT: - case R_BACKWARD_KILL_BIGWORD: - case R_SELF_INSERT: - case R_TRANSPOSE_CHARS: - case R_TRANSPOSE_WORDS: - case R_UPCASE_WORD: - case R_DOWNCASE_WORD: - case R_CAPITALIZE_WORD: - case R_VI_ARG_DIGIT: - case R_VI_DELETE_TO: - case R_BEGINNING_OF_BUFFER: - case R_END_OF_BUFFER: { + case rl::R_BEGINNING_OF_LINE: + case rl::R_END_OF_LINE: + case rl::R_FORWARD_WORD: + case rl::R_BACKWARD_WORD: + case rl::R_FORWARD_BIGWORD: + case rl::R_BACKWARD_BIGWORD: + case rl::R_DELETE_CHAR: + case rl::R_BACKWARD_DELETE_CHAR: + case rl::R_KILL_LINE: + case rl::R_YANK: + case rl::R_YANK_POP: + case rl::R_BACKWARD_KILL_LINE: + case rl::R_KILL_WHOLE_LINE: + case rl::R_KILL_WORD: + case rl::R_KILL_BIGWORD: + case rl::R_BACKWARD_KILL_WORD: + case rl::R_BACKWARD_KILL_PATH_COMPONENT: + case rl::R_BACKWARD_KILL_BIGWORD: + case rl::R_SELF_INSERT: + case rl::R_TRANSPOSE_CHARS: + case rl::R_TRANSPOSE_WORDS: + case rl::R_UPCASE_WORD: + case rl::R_DOWNCASE_WORD: + case rl::R_CAPITALIZE_WORD: + case rl::R_VI_ARG_DIGIT: + case rl::R_VI_DELETE_TO: + case rl::R_BEGINNING_OF_BUFFER: + case rl::R_END_OF_BUFFER: // These commands operate on the search field if that's where the focus is. return !focused_on_search_field; - } - default: { return false; } + default: + return false; + } +} + +/// Indicates if the given command ends the history search. +static bool command_ends_history_search(readline_cmd_t c) { + switch (c) { + case readline_cmd_t::R_HISTORY_SEARCH_BACKWARD: + case readline_cmd_t::R_HISTORY_SEARCH_FORWARD: + case readline_cmd_t::R_HISTORY_TOKEN_SEARCH_BACKWARD: + case readline_cmd_t::R_HISTORY_TOKEN_SEARCH_FORWARD: + case readline_cmd_t::R_REPAINT: + case readline_cmd_t::R_FORCE_REPAINT: + return false; + default: + return true; } } @@ -2389,7 +2405,8 @@ static bool event_is_normal_char(const char_event_t &evt) { } maybe_t reader_data_t::readline(int nchars) { - int last_char = 0; + using rl = readline_cmd_t; + maybe_t last_cmd{}; size_t yank_len = 0; bool comp_empty = true; std::vector comp; @@ -2459,7 +2476,6 @@ maybe_t reader_data_t::readline(int nchars) { wchar_t arr[READAHEAD_MAX + 1] = {}; arr[0] = evt.get_char(); - last_char = arr[0]; for (size_t i = 1; i < limit; ++i) { if (!can_read(0)) { @@ -2471,7 +2487,6 @@ maybe_t reader_data_t::readline(int nchars) { auto next_event = input_readch(false); if (event_is_normal_char(next_event)) { arr[i] = next_event.get_char(); - last_char = arr[i]; } else { // We need to process this in the outer loop. assert(!event_needing_handling && "Should not have an unhandled event"); @@ -2487,6 +2502,9 @@ maybe_t reader_data_t::readline(int nchars) { if (el == &command_line) { clear_pager(); } + + // Since we handled a normal character, we don't have a last command. + last_cmd.reset(); } // If there's still an event that we were unable to handle, then end the coalescing @@ -2508,29 +2526,38 @@ maybe_t reader_data_t::readline(int nchars) { } assert((event_needing_handling->is_char() || event_needing_handling->is_readline()) && "Should have a char or readline"); - wchar_t c = event_needing_handling->is_char() ? event_needing_handling->get_char() - : event_needing_handling->get_readline(); + maybe_t readline_cmd{}; + maybe_t ordinary_char{}; + if (event_needing_handling->is_readline()) { + readline_cmd = event_needing_handling->get_readline(); + } else { + ordinary_char = event_needing_handling->get_char(); + } // If we get something other than a repaint, then stop coalescing them. - if (c != R_REPAINT) coalescing_repaints = false; + if (readline_cmd != rl::R_REPAINT) coalescing_repaints = false; - if (last_char != R_YANK && last_char != R_YANK_POP) yank_len = 0; + if (last_cmd != rl::R_YANK && last_cmd != rl::R_YANK_POP) { + yank_len = 0; + } // Restore the text. - if (c == R_CANCEL && is_navigating_pager_contents()) { - set_command_line_and_position(&command_line, cycle_command_line, cycle_cursor_pos); + if (readline_cmd) { + if (*readline_cmd == rl::R_CANCEL && is_navigating_pager_contents()) { + set_command_line_and_position(&command_line, cycle_command_line, cycle_cursor_pos); + } + + // Clear the pager if necessary. + bool focused_on_search_field = (active_edit_line() == &pager.search_field_line); + if (command_ends_paging(*readline_cmd, focused_on_search_field)) { + clear_pager(); + } } - // Clear the pager if necessary. - bool focused_on_search_field = (active_edit_line() == &pager.search_field_line); - if (command_ends_paging(c, focused_on_search_field)) { - clear_pager(); - } - // std::fwprintf(stderr, L"\n\nchar: %ls\n\n", describe_char(c).c_str()); - + readline_cmd_t c = readline_cmd ? *readline_cmd : static_cast(0); switch (c) { // Go to beginning of line. - case R_BEGINNING_OF_LINE: { + case rl::R_BEGINNING_OF_LINE: { editable_line_t *el = active_edit_line(); while (el->position > 0 && el->text.at(el->position - 1) != L'\n') { update_buff_pos(el, el->position - 1); @@ -2539,7 +2566,7 @@ maybe_t reader_data_t::readline(int nchars) { reader_repaint_needed(); break; } - case R_END_OF_LINE: { + case rl::R_END_OF_LINE: { editable_line_t *el = active_edit_line(); if (el->position < el->size()) { const wchar_t *buff = el->text.c_str(); @@ -2553,22 +2580,22 @@ maybe_t reader_data_t::readline(int nchars) { reader_repaint_needed(); break; } - case R_BEGINNING_OF_BUFFER: { + case rl::R_BEGINNING_OF_BUFFER: { update_buff_pos(&command_line, 0); reader_repaint_needed(); break; } - case R_END_OF_BUFFER: { + case rl::R_END_OF_BUFFER: { update_buff_pos(&command_line, command_line.size()); reader_repaint_needed(); break; } - case R_CANCEL: { + case rl::R_CANCEL: { // The only thing we can cancel right now is paging, which we handled up above. break; } - case R_FORCE_REPAINT: - case R_REPAINT: { + case rl::R_FORCE_REPAINT: + case rl::R_REPAINT: { if (!coalescing_repaints) { coalescing_repaints = true; exec_prompt(); @@ -2578,21 +2605,21 @@ maybe_t reader_data_t::readline(int nchars) { } break; } - case R_COMPLETE: - case R_COMPLETE_AND_SEARCH: { + case rl::R_COMPLETE: + case rl::R_COMPLETE_AND_SEARCH: { if (!complete_func) break; // Use the command line only; it doesn't make sense to complete in any other line. editable_line_t *el = &command_line; - if (is_navigating_pager_contents() || (!comp_empty && last_char == R_COMPLETE)) { + if (is_navigating_pager_contents() || (!comp_empty && last_cmd == rl::R_COMPLETE)) { // The user typed R_COMPLETE more than once in a row. If we are not yet fully // disclosed, then become so; otherwise cycle through our available completions. if (current_page_rendering.remaining_to_disclose > 0) { pager.set_fully_disclosed(true); reader_repaint_needed(); } else { - select_completion_in_direction(c == R_COMPLETE ? direction_next - : direction_prev); + select_completion_in_direction(c == rl::R_COMPLETE ? direction_next + : direction_prev); } } else { // Either the user hit tab only once, or we had no visible completion list. @@ -2651,11 +2678,11 @@ maybe_t reader_data_t::readline(int nchars) { cycle_command_line = el->text; cycle_cursor_pos = el->position; - bool cont_after_prefix_insertion = (c == R_COMPLETE_AND_SEARCH); + bool cont_after_prefix_insertion = (c == rl::R_COMPLETE_AND_SEARCH); comp_empty = handle_completions(comp, cont_after_prefix_insertion); // Show the search field if requested and if we printed a list of completions. - if (c == R_COMPLETE_AND_SEARCH && !comp_empty && !pager.empty()) { + if (c == rl::R_COMPLETE_AND_SEARCH && !comp_empty && !pager.empty()) { pager.set_search_field_shown(true); select_completion_in_direction(direction_next); reader_repaint_needed(); @@ -2663,7 +2690,7 @@ maybe_t reader_data_t::readline(int nchars) { } break; } - case R_PAGER_TOGGLE_SEARCH: { + case rl::R_PAGER_TOGGLE_SEARCH: { if (!pager.empty()) { // Toggle search, and begin navigating if we are now searching. bool sfs = pager.is_search_field_shown(); @@ -2676,7 +2703,7 @@ maybe_t reader_data_t::readline(int nchars) { } break; } - case R_KILL_LINE: { + case rl::R_KILL_LINE: { editable_line_t *el = active_edit_line(); const wchar_t *buff = el->text.c_str(); const wchar_t *begin = &buff[el->position]; @@ -2688,11 +2715,11 @@ maybe_t reader_data_t::readline(int nchars) { size_t len = end - begin; if (len) { - kill(el, begin - buff, len, KILL_APPEND, last_char != R_KILL_LINE); + kill(el, begin - buff, len, KILL_APPEND, last_cmd != rl::R_KILL_LINE); } break; } - case R_BACKWARD_KILL_LINE: { + case rl::R_BACKWARD_KILL_LINE: { editable_line_t *el = active_edit_line(); if (el->position <= 0) { break; @@ -2711,10 +2738,10 @@ maybe_t reader_data_t::readline(int nchars) { assert(end >= begin); size_t len = std::max(end - begin, 1); begin = end - len; - kill(el, begin - buff, len, KILL_PREPEND, last_char != R_BACKWARD_KILL_LINE); + kill(el, begin - buff, len, KILL_PREPEND, last_cmd != rl::R_BACKWARD_KILL_LINE); break; } - case R_KILL_WHOLE_LINE: { + case rl::R_KILL_WHOLE_LINE: { // We match the emacs behavior here: "kills the entire line including the following // newline". editable_line_t *el = active_edit_line(); @@ -2740,17 +2767,17 @@ maybe_t reader_data_t::readline(int nchars) { assert(end >= begin); if (end > begin) { - kill(el, begin, end - begin, KILL_APPEND, last_char != R_KILL_WHOLE_LINE); + kill(el, begin, end - begin, KILL_APPEND, last_cmd != rl::R_KILL_WHOLE_LINE); } break; } - case R_YANK: { + case rl::R_YANK: { wcstring yank_str = kill_yank(); insert_string(active_edit_line(), yank_str); yank_len = yank_str.size(); break; } - case R_YANK_POP: { + case rl::R_YANK_POP: { if (yank_len) { for (size_t i = 0; i < yank_len; i++) remove_backward(); @@ -2760,21 +2787,11 @@ maybe_t reader_data_t::readline(int nchars) { } break; } - // Escape was pressed. - case L'\x1B': { - if (history_search.active()) { - history_search.go_to_end(); - update_command_line_from_history_search(); - history_search.reset(); - } - assert(!history_search.active()); - break; - } - case R_BACKWARD_DELETE_CHAR: { + case rl::R_BACKWARD_DELETE_CHAR: { remove_backward(); break; } - case R_DELETE_CHAR: { + case rl::R_DELETE_CHAR: { // Remove the current character in the character buffer and on the screen using // syntax highlighting, etc. editable_line_t *el = active_edit_line(); @@ -2784,9 +2801,9 @@ maybe_t reader_data_t::readline(int nchars) { } break; } - // Evaluate. If the current command is unfinished, or if the charater is escaped using a - // backslash, insert a newline. - case R_EXECUTE: { + // Evaluate. If the current command is unfinished, or if the charater is escaped + // using a backslash, insert a newline. + case rl::R_EXECUTE: { // If the user hits return while navigating the pager, it only clears the pager. if (is_navigating_pager_contents()) { clear_pager(); @@ -2870,14 +2887,14 @@ maybe_t reader_data_t::readline(int nchars) { break; } - case R_HISTORY_SEARCH_BACKWARD: - case R_HISTORY_TOKEN_SEARCH_BACKWARD: - case R_HISTORY_SEARCH_FORWARD: - case R_HISTORY_TOKEN_SEARCH_FORWARD: { + case rl::R_HISTORY_SEARCH_BACKWARD: + case rl::R_HISTORY_TOKEN_SEARCH_BACKWARD: + case rl::R_HISTORY_SEARCH_FORWARD: + case rl::R_HISTORY_TOKEN_SEARCH_FORWARD: { if (history_search.is_at_end()) { const editable_line_t *el = &command_line; - bool by_token = (c == R_HISTORY_TOKEN_SEARCH_BACKWARD) || - (c == R_HISTORY_TOKEN_SEARCH_FORWARD); + bool by_token = (c == rl::R_HISTORY_TOKEN_SEARCH_BACKWARD) || + (c == rl::R_HISTORY_TOKEN_SEARCH_FORWARD); if (by_token) { // Searching by token. const wchar_t *begin, *end; @@ -2904,16 +2921,16 @@ maybe_t reader_data_t::readline(int nchars) { } } if (history_search.active()) { - history_search_direction_t dir = - (c == R_HISTORY_SEARCH_BACKWARD || c == R_HISTORY_TOKEN_SEARCH_BACKWARD) - ? history_search_direction_t::backward - : history_search_direction_t::forward; + history_search_direction_t dir = (c == rl::R_HISTORY_SEARCH_BACKWARD || + c == rl::R_HISTORY_TOKEN_SEARCH_BACKWARD) + ? history_search_direction_t::backward + : history_search_direction_t::forward; history_search.move_in_direction(dir); update_command_line_from_history_search(); } break; } - case R_BACKWARD_CHAR: { + case rl::R_BACKWARD_CHAR: { editable_line_t *el = active_edit_line(); if (is_navigating_pager_contents()) { select_completion_in_direction(direction_west); @@ -2923,7 +2940,7 @@ maybe_t reader_data_t::readline(int nchars) { } break; } - case R_FORWARD_CHAR: { + case rl::R_FORWARD_CHAR: { editable_line_t *el = active_edit_line(); if (is_navigating_pager_contents()) { select_completion_in_direction(direction_east); @@ -2935,51 +2952,54 @@ maybe_t reader_data_t::readline(int nchars) { } break; } - case R_BACKWARD_KILL_WORD: - case R_BACKWARD_KILL_PATH_COMPONENT: - case R_BACKWARD_KILL_BIGWORD: { + case rl::R_BACKWARD_KILL_WORD: + case rl::R_BACKWARD_KILL_PATH_COMPONENT: + case rl::R_BACKWARD_KILL_BIGWORD: { move_word_style_t style = - (c == R_BACKWARD_KILL_BIGWORD + (c == rl::R_BACKWARD_KILL_BIGWORD ? move_word_style_whitespace - : c == R_BACKWARD_KILL_PATH_COMPONENT ? move_word_style_path_components - : move_word_style_punctuation); + : c == rl::R_BACKWARD_KILL_PATH_COMPONENT ? move_word_style_path_components + : move_word_style_punctuation); // Is this the same killring item as the last kill? - bool newv = (last_char != R_BACKWARD_KILL_WORD && - last_char != R_BACKWARD_KILL_PATH_COMPONENT && - last_char != R_BACKWARD_KILL_BIGWORD); + bool newv = (last_cmd != rl::R_BACKWARD_KILL_WORD && + last_cmd != rl::R_BACKWARD_KILL_PATH_COMPONENT && + last_cmd != rl::R_BACKWARD_KILL_BIGWORD); move_word(active_edit_line(), MOVE_DIR_LEFT, true /* erase */, style, newv); break; } - case R_KILL_WORD: - case R_KILL_BIGWORD: { - // The "bigword" functions differ only in that they move to the next whitespace, not punctuation. - auto move_style = (c == R_KILL_WORD) ? move_word_style_punctuation : move_word_style_whitespace; + case rl::R_KILL_WORD: + case rl::R_KILL_BIGWORD: { + // The "bigword" functions differ only in that they move to the next whitespace, not + // punctuation. + auto move_style = (c == rl::R_KILL_WORD) ? move_word_style_punctuation + : move_word_style_whitespace; move_word(active_edit_line(), MOVE_DIR_RIGHT, true /* erase */, move_style, - last_char != c /* same kill item if same movement */); + last_cmd != c /* same kill item if same movement */); break; } - case R_BACKWARD_WORD: - case R_BACKWARD_BIGWORD: { - auto move_style = (c == R_BACKWARD_WORD) ? move_word_style_punctuation : move_word_style_whitespace; + case rl::R_BACKWARD_WORD: + case rl::R_BACKWARD_BIGWORD: { + auto move_style = (c == rl::R_BACKWARD_WORD) ? move_word_style_punctuation + : move_word_style_whitespace; move_word(active_edit_line(), MOVE_DIR_LEFT, false /* do not erase */, move_style, false); break; } - case R_FORWARD_WORD: - case R_FORWARD_BIGWORD: { - auto move_style = (c == R_FORWARD_WORD) ? move_word_style_punctuation : move_word_style_whitespace; + case rl::R_FORWARD_WORD: + case rl::R_FORWARD_BIGWORD: { + auto move_style = (c == rl::R_FORWARD_WORD) ? move_word_style_punctuation + : move_word_style_whitespace; editable_line_t *el = active_edit_line(); if (el->position < el->size()) { - move_word(el, MOVE_DIR_RIGHT, false /* do not erase */, - move_style, false); + move_word(el, MOVE_DIR_RIGHT, false /* do not erase */, move_style, false); } else { accept_autosuggestion(false, move_style); } break; } - case R_BEGINNING_OF_HISTORY: - case R_END_OF_HISTORY: { - bool up = (c == R_BEGINNING_OF_HISTORY); + case rl::R_BEGINNING_OF_HISTORY: + case rl::R_END_OF_HISTORY: { + bool up = (c == rl::R_BEGINNING_OF_HISTORY); if (is_navigating_pager_contents()) { select_completion_in_direction(up ? direction_page_north : direction_page_south); @@ -2993,12 +3013,12 @@ maybe_t reader_data_t::readline(int nchars) { } break; } - case R_UP_LINE: - case R_DOWN_LINE: { + case rl::R_UP_LINE: + case rl::R_DOWN_LINE: { if (is_navigating_pager_contents()) { // We are already navigating pager contents. selection_direction_t direction; - if (c == R_DOWN_LINE) { + if (c == rl::R_DOWN_LINE) { // Down arrow is always south. direction = direction_south; } else if (selection_is_at_top()) { @@ -3013,15 +3033,15 @@ maybe_t reader_data_t::readline(int nchars) { select_completion_in_direction(direction); } else if (!pager.empty()) { // We pressed a direction with a non-empty pager, begin navigation. - select_completion_in_direction(c == R_DOWN_LINE ? direction_south - : direction_north); + select_completion_in_direction(c == rl::R_DOWN_LINE ? direction_south + : direction_north); } else { // Not navigating the pager contents. editable_line_t *el = active_edit_line(); int line_old = parse_util_get_line_from_offset(el->text, el->position); int line_new; - if (c == R_UP_LINE) + if (c == rl::R_UP_LINE) line_new = line_old - 1; else line_new = line_old + 1; @@ -3055,17 +3075,17 @@ maybe_t reader_data_t::readline(int nchars) { } break; } - case R_SUPPRESS_AUTOSUGGESTION: { + case rl::R_SUPPRESS_AUTOSUGGESTION: { suppress_autosuggestion = true; autosuggestion.clear(); reader_repaint_needed(); break; } - case R_ACCEPT_AUTOSUGGESTION: { + case rl::R_ACCEPT_AUTOSUGGESTION: { accept_autosuggestion(true); break; } - case R_TRANSPOSE_CHARS: { + case rl::R_TRANSPOSE_CHARS: { editable_line_t *el = active_edit_line(); if (el->size() < 2) { break; @@ -3085,7 +3105,7 @@ maybe_t reader_data_t::readline(int nchars) { } break; } - case R_TRANSPOSE_WORDS: { + case rl::R_TRANSPOSE_WORDS: { editable_line_t *el = active_edit_line(); size_t len = el->size(); const wchar_t *buff = el->text.c_str(); @@ -3126,9 +3146,9 @@ maybe_t reader_data_t::readline(int nchars) { } break; } - case R_UPCASE_WORD: - case R_DOWNCASE_WORD: - case R_CAPITALIZE_WORD: { + case rl::R_UPCASE_WORD: + case rl::R_DOWNCASE_WORD: + case rl::R_CAPITALIZE_WORD: { editable_line_t *el = active_edit_line(); // For capitalize_word, whether we've capitalized a character so far. bool capitalized_first = false; @@ -3142,10 +3162,10 @@ maybe_t reader_data_t::readline(int nchars) { // We always change the case; this decides whether we go uppercase (true) or // lowercase (false). bool make_uppercase; - if (c == R_CAPITALIZE_WORD) + if (c == rl::R_CAPITALIZE_WORD) make_uppercase = !capitalized_first && iswalnum(chr); else - make_uppercase = (c == R_UPCASE_WORD); + make_uppercase = (c == rl::R_UPCASE_WORD); // Apply the operation and then record what we did. if (make_uppercase) @@ -3161,11 +3181,11 @@ maybe_t reader_data_t::readline(int nchars) { reader_repaint_needed(); break; } - case R_BEGIN_SELECTION: - case R_END_SELECTION: { + case rl::R_BEGIN_SELECTION: + case rl::R_END_SELECTION: { sel_start_pos = command_line.position; sel_stop_pos = command_line.position; - if (c == R_BEGIN_SELECTION) { + if (c == rl::R_BEGIN_SELECTION) { sel_active = true; sel_begin_pos = command_line.position; } else { @@ -3174,7 +3194,7 @@ maybe_t reader_data_t::readline(int nchars) { break; } - case R_SWAP_SELECTION_START_STOP: { + case rl::R_SWAP_SELECTION_START_STOP: { if (!sel_active) break; size_t tmp = sel_begin_pos; sel_begin_pos = command_line.position; @@ -3183,22 +3203,24 @@ maybe_t reader_data_t::readline(int nchars) { update_buff_pos(el, tmp); break; } - case R_KILL_SELECTION: { - bool newv = (last_char != R_KILL_SELECTION); + case rl::R_KILL_SELECTION: { + bool newv = (last_cmd != rl::R_KILL_SELECTION); size_t start, len; if (reader_get_selection(&start, &len)) { kill(&command_line, start, len, KILL_APPEND, newv); } break; } - case R_FORWARD_JUMP: - case R_BACKWARD_JUMP: - case R_FORWARD_JUMP_TILL: - case R_BACKWARD_JUMP_TILL: { - auto direction = (c == R_FORWARD_JUMP || c == R_FORWARD_JUMP_TILL) ? - jump_direction_t::forward : jump_direction_t::backward; - auto precision = (c == R_FORWARD_JUMP || c == R_BACKWARD_JUMP) ? - jump_precision_t::to : jump_precision_t::till; + case rl::R_FORWARD_JUMP: + case rl::R_BACKWARD_JUMP: + case rl::R_FORWARD_JUMP_TILL: + case rl::R_BACKWARD_JUMP_TILL: { + auto direction = (c == rl::R_FORWARD_JUMP || c == rl::R_FORWARD_JUMP_TILL) + ? jump_direction_t::forward + : jump_direction_t::backward; + auto precision = (c == rl::R_FORWARD_JUMP || c == rl::R_BACKWARD_JUMP) + ? jump_precision_t::to + : jump_precision_t::till; editable_line_t *el = active_edit_line(); wchar_t target = input_function_pop_arg(); bool success = jump(direction, precision, el, target); @@ -3207,7 +3229,7 @@ maybe_t reader_data_t::readline(int nchars) { reader_repaint_needed(); break; } - case R_REPEAT_JUMP: { + case rl::R_REPEAT_JUMP: { editable_line_t *el = active_edit_line(); bool success = false; @@ -3219,7 +3241,7 @@ maybe_t reader_data_t::readline(int nchars) { reader_repaint_needed(); break; } - case R_REVERSE_REPEAT_JUMP: { + case rl::R_REVERSE_REPEAT_JUMP: { editable_line_t *el = active_edit_line(); bool success = false; jump_direction_t original_dir, dir; @@ -3241,36 +3263,41 @@ maybe_t reader_data_t::readline(int nchars) { reader_repaint_needed(); break; } - default: { - // Other, if a normal character, we add it to the command. - if (!fish_reserved_codepoint(c) && (c >= L' ' || c == L'\n' || c == L'\r') && - c != 0x7F) { - // Regular character. - editable_line_t *el = active_edit_line(); - bool allow_expand_abbreviations = (el == &command_line); - insert_char(active_edit_line(), c, allow_expand_abbreviations); + } - // End paging upon inserting into the normal command line. - if (el == &command_line) { - clear_pager(); - } - } else { - // This can happen if the user presses a control char we don't recognize. No - // reason to report this to the user unless they've enabled debugging output. - debug(2, _(L"Unknown key binding 0x%X"), c); + if (ordinary_char) { + wchar_t c = *ordinary_char; + + if (c == L'\x1B') { + // Escape was pressed. + if (history_search.active()) { + history_search.go_to_end(); + update_command_line_from_history_search(); + history_search.reset(); } - break; + assert(!history_search.active()); + } else if (!fish_reserved_codepoint(c) && (c >= L' ' || c == L'\n' || c == L'\r') && + c != 0x7F) { + // Regular character. + editable_line_t *el = active_edit_line(); + bool allow_expand_abbreviations = (el == &command_line); + insert_char(active_edit_line(), c, allow_expand_abbreviations); + + // End paging upon inserting into the normal command line. + if (el == &command_line) { + clear_pager(); + } + } else { + // This can happen if the user presses a control char we don't recognize. No + // reason to report this to the user unless they've enabled debugging output. + debug(2, _(L"Unknown key binding 0x%X"), c); } } - if ((c != R_HISTORY_SEARCH_BACKWARD) && (c != R_HISTORY_SEARCH_FORWARD) && - (c != R_HISTORY_TOKEN_SEARCH_BACKWARD) && (c != R_HISTORY_TOKEN_SEARCH_FORWARD) && - (c != R_REPAINT) && (c != R_FORCE_REPAINT)) { + if (!readline_cmd || command_ends_history_search(*readline_cmd)) { history_search.reset(); } - - last_char = c; - + last_cmd = readline_cmd; repaint_if_needed(); } From 6aba28ad3d098c7991d8698a3b11969d7e6ea526 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 17 Mar 2019 11:25:16 -0700 Subject: [PATCH 0136/1732] Add missing cases to readline loop Handle all readline commands in our switch. --- src/reader.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/reader.cpp b/src/reader.cpp index 8b663c2e7..769857847 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -3263,6 +3263,19 @@ maybe_t reader_data_t::readline(int nchars) { reader_repaint_needed(); break; } + + // Some commands should have been handled internally by input_readch(). + case rl::R_SELF_INSERT: { + DIE("self-insert should have been handled by input_readch"); + } + case rl::R_AND: { + DIE("self-insert should have been handled by input_readch"); + } + case rl::R_VI_ARG_DIGIT: + case rl::R_VI_DELETE_TO: { + // TODO: what needs to happen with these? + break; + } } if (ordinary_char) { From 7ae78650716e88b87c3e4f9abbc8031d3991574b Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 17 Mar 2019 11:44:47 -0700 Subject: [PATCH 0137/1732] Factor reader_data_t::readline state into a new struct Will help break up this monster. --- src/reader.cpp | 95 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 38 deletions(-) diff --git a/src/reader.cpp b/src/reader.cpp index 769857847..5ff59577b 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2404,19 +2404,35 @@ static bool event_is_normal_char(const char_event_t &evt) { return !fish_reserved_codepoint(c) && c > 31 && c != 127; } +/// readline_loop_state_t encapsulates the state used in a readline loop. +/// It is always stack allocated transient. This state should not be "publicly visible;" public +/// state should be in reader_data_t. +struct readline_loop_state_t { + /// The last command that was executed. + maybe_t last_cmd{}; + + /// If the last command was a yank, the length of yanking that occurred. + size_t yank_len{0}; + + /// If set, it means nothing has been inserted into the command line via completion machinery. + bool comp_empty{true}; + + /// List of completions. + std::vector comp; + + /// Whether we are skipping redundant repaints. + bool coalescing_repaints = false; + + /// Whether the loop has finished, due to reaching the character limit or through executing a + /// command. + bool finished{false}; +}; + maybe_t reader_data_t::readline(int nchars) { using rl = readline_cmd_t; - maybe_t last_cmd{}; - size_t yank_len = 0; - bool comp_empty = true; - std::vector comp; - int finished = 0; + readline_loop_state_t rls{}; struct termios old_modes; - // Coalesce redundant repaints. When we get a repaint, we set this to true, and skip repaints - // until we get something else. - bool coalescing_repaints = false; - // The command line before completion. cycle_command_line.clear(); cycle_cursor_pos = 0; @@ -2433,6 +2449,7 @@ maybe_t reader_data_t::readline(int nchars) { // Get the current terminal modes. These will be restored when the function returns. if (tcgetattr(STDIN_FILENO, &old_modes) == -1 && errno == EIO) redirect_tty_output(); + // Set the new modes. if (tcsetattr(0, TCSANOW, &shell_modes) == -1) { int err = errno; @@ -2447,10 +2464,10 @@ maybe_t reader_data_t::readline(int nchars) { } } - while (!finished && !shell_is_exiting()) { + while (!rls.finished && !shell_is_exiting()) { if (0 < nchars && (size_t)nchars <= command_line.size()) { // We've already hit the specified character limit. - finished = 1; + rls.finished = true; break; } @@ -2504,7 +2521,7 @@ maybe_t reader_data_t::readline(int nchars) { } // Since we handled a normal character, we don't have a last command. - last_cmd.reset(); + rls.last_cmd.reset(); } // If there's still an event that we were unable to handle, then end the coalescing @@ -2535,10 +2552,10 @@ maybe_t reader_data_t::readline(int nchars) { } // If we get something other than a repaint, then stop coalescing them. - if (readline_cmd != rl::R_REPAINT) coalescing_repaints = false; + if (readline_cmd != rl::R_REPAINT) rls.coalescing_repaints = false; - if (last_cmd != rl::R_YANK && last_cmd != rl::R_YANK_POP) { - yank_len = 0; + if (rls.last_cmd != rl::R_YANK && rls.last_cmd != rl::R_YANK_POP) { + rls.yank_len = 0; } // Restore the text. @@ -2596,8 +2613,8 @@ maybe_t reader_data_t::readline(int nchars) { } case rl::R_FORCE_REPAINT: case rl::R_REPAINT: { - if (!coalescing_repaints) { - coalescing_repaints = true; + if (!rls.coalescing_repaints) { + rls.coalescing_repaints = true; exec_prompt(); s_reset(&screen, screen_reset_current_line_and_prompt); screen_reset_needed = false; @@ -2611,7 +2628,8 @@ maybe_t reader_data_t::readline(int nchars) { // Use the command line only; it doesn't make sense to complete in any other line. editable_line_t *el = &command_line; - if (is_navigating_pager_contents() || (!comp_empty && last_cmd == rl::R_COMPLETE)) { + if (is_navigating_pager_contents() || + (!rls.comp_empty && rls.last_cmd == rl::R_COMPLETE)) { // The user typed R_COMPLETE more than once in a row. If we are not yet fully // disclosed, then become so; otherwise cycle through our available completions. if (current_page_rendering.remaining_to_disclose > 0) { @@ -2633,7 +2651,7 @@ maybe_t reader_data_t::readline(int nchars) { const wchar_t *const buff = el->text.c_str(); // Clear the completion list. - comp.clear(); + rls.comp.clear(); // Figure out the extent of the command substitution surrounding the cursor. // This is because we only look at the current command substitution to form @@ -2669,20 +2687,20 @@ maybe_t reader_data_t::readline(int nchars) { complete_flags_t complete_flags = COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_DESCRIPTIONS | COMPLETION_REQUEST_FUZZY_MATCH; - complete_func(buffcpy, &comp, complete_flags, vars); + complete_func(buffcpy, &rls.comp, complete_flags, vars); // Munge our completions. - completions_sort_and_prioritize(&comp); + completions_sort_and_prioritize(&rls.comp); // Record our cycle_command_line. cycle_command_line = el->text; cycle_cursor_pos = el->position; bool cont_after_prefix_insertion = (c == rl::R_COMPLETE_AND_SEARCH); - comp_empty = handle_completions(comp, cont_after_prefix_insertion); + rls.comp_empty = handle_completions(rls.comp, cont_after_prefix_insertion); // Show the search field if requested and if we printed a list of completions. - if (c == rl::R_COMPLETE_AND_SEARCH && !comp_empty && !pager.empty()) { + if (c == rl::R_COMPLETE_AND_SEARCH && !rls.comp_empty && !pager.empty()) { pager.set_search_field_shown(true); select_completion_in_direction(direction_next); reader_repaint_needed(); @@ -2715,7 +2733,7 @@ maybe_t reader_data_t::readline(int nchars) { size_t len = end - begin; if (len) { - kill(el, begin - buff, len, KILL_APPEND, last_cmd != rl::R_KILL_LINE); + kill(el, begin - buff, len, KILL_APPEND, rls.last_cmd != rl::R_KILL_LINE); } break; } @@ -2738,7 +2756,7 @@ maybe_t reader_data_t::readline(int nchars) { assert(end >= begin); size_t len = std::max(end - begin, 1); begin = end - len; - kill(el, begin - buff, len, KILL_PREPEND, last_cmd != rl::R_BACKWARD_KILL_LINE); + kill(el, begin - buff, len, KILL_PREPEND, rls.last_cmd != rl::R_BACKWARD_KILL_LINE); break; } case rl::R_KILL_WHOLE_LINE: { @@ -2767,23 +2785,24 @@ maybe_t reader_data_t::readline(int nchars) { assert(end >= begin); if (end > begin) { - kill(el, begin, end - begin, KILL_APPEND, last_cmd != rl::R_KILL_WHOLE_LINE); + kill(el, begin, end - begin, KILL_APPEND, + rls.last_cmd != rl::R_KILL_WHOLE_LINE); } break; } case rl::R_YANK: { wcstring yank_str = kill_yank(); insert_string(active_edit_line(), yank_str); - yank_len = yank_str.size(); + rls.yank_len = yank_str.size(); break; } case rl::R_YANK_POP: { - if (yank_len) { - for (size_t i = 0; i < yank_len; i++) remove_backward(); + if (rls.yank_len) { + for (size_t i = 0; i < rls.yank_len; i++) remove_backward(); wcstring yank_str = kill_yank_rotate(); insert_string(active_edit_line(), yank_str); - yank_len = yank_str.size(); + rls.yank_len = yank_str.size(); } break; } @@ -2871,7 +2890,7 @@ maybe_t reader_data_t::readline(int nchars) { if (history != NULL && !el->empty() && el->text.at(0) != L' ') { history->add_pending_with_file_detection(el->text, vars.get_pwd_slash()); } - finished = 1; + rls.finished = true; update_buff_pos(&command_line, command_line.size()); repaint(); } else if (command_test_result == PARSER_TEST_INCOMPLETE) { @@ -2961,9 +2980,9 @@ maybe_t reader_data_t::readline(int nchars) { : c == rl::R_BACKWARD_KILL_PATH_COMPONENT ? move_word_style_path_components : move_word_style_punctuation); // Is this the same killring item as the last kill? - bool newv = (last_cmd != rl::R_BACKWARD_KILL_WORD && - last_cmd != rl::R_BACKWARD_KILL_PATH_COMPONENT && - last_cmd != rl::R_BACKWARD_KILL_BIGWORD); + bool newv = (rls.last_cmd != rl::R_BACKWARD_KILL_WORD && + rls.last_cmd != rl::R_BACKWARD_KILL_PATH_COMPONENT && + rls.last_cmd != rl::R_BACKWARD_KILL_BIGWORD); move_word(active_edit_line(), MOVE_DIR_LEFT, true /* erase */, style, newv); break; } @@ -2974,7 +2993,7 @@ maybe_t reader_data_t::readline(int nchars) { auto move_style = (c == rl::R_KILL_WORD) ? move_word_style_punctuation : move_word_style_whitespace; move_word(active_edit_line(), MOVE_DIR_RIGHT, true /* erase */, move_style, - last_cmd != c /* same kill item if same movement */); + rls.last_cmd != c /* same kill item if same movement */); break; } case rl::R_BACKWARD_WORD: @@ -3204,7 +3223,7 @@ maybe_t reader_data_t::readline(int nchars) { break; } case rl::R_KILL_SELECTION: { - bool newv = (last_cmd != rl::R_KILL_SELECTION); + bool newv = (rls.last_cmd != rl::R_KILL_SELECTION); size_t start, len; if (reader_get_selection(&start, &len)) { kill(&command_line, start, len, KILL_APPEND, newv); @@ -3310,7 +3329,7 @@ maybe_t reader_data_t::readline(int nchars) { if (!readline_cmd || command_ends_history_search(*readline_cmd)) { history_search.reset(); } - last_cmd = readline_cmd; + rls.last_cmd = readline_cmd; repaint_if_needed(); } @@ -3334,7 +3353,7 @@ maybe_t reader_data_t::readline(int nchars) { outputter_t::stdoutput().set_color(rgb_color_t::reset(), rgb_color_t::reset()); } - return finished ? maybe_t{command_line.text} : none(); + return rls.finished ? maybe_t{command_line.text} : none(); } bool reader_data_t::jump(jump_direction_t dir, jump_precision_t precision, editable_line_t *el, From 42f4d2bd86c70e5c7ca87059ddd63a9ca00deb55 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 17 Mar 2019 23:37:46 -0700 Subject: [PATCH 0138/1732] Factor out the "read coalescing" part of reader_data_t::readline --- src/reader.cpp | 124 ++++++++++++++++++++++++++----------------------- 1 file changed, 67 insertions(+), 57 deletions(-) diff --git a/src/reader.cpp b/src/reader.cpp index 5ff59577b..7d1668072 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -105,7 +105,7 @@ /// The maximum number of characters to read from the keyboard without repainting. Note that this /// readahead will only occur if new characters are available for reading, fish will never block for /// more input without repainting. -#define READAHEAD_MAX 256 +static constexpr size_t READAHEAD_MAX = 256; /// A mode for calling the reader_kill function. In this mode, the new string is appended to the /// current contents of the kill buffer. @@ -316,6 +316,8 @@ struct highlight_result_t { } // namespace +struct readline_loop_state_t; + /// A struct describing the state of the interactive reader. These states can be stacked, in case /// reader_readline() calls are nested. This happens when the 'read' builtin is used. class reader_data_t : public std::enable_shared_from_this { @@ -441,6 +443,7 @@ class reader_data_t : public std::enable_shared_from_this { bool newv); maybe_t readline(int nchars); + maybe_t read_normal_chars(readline_loop_state_t &rls); void clear_pager(); void select_completion_in_direction(enum selection_direction_t dir); @@ -2426,13 +2429,72 @@ struct readline_loop_state_t { /// Whether the loop has finished, due to reaching the character limit or through executing a /// command. bool finished{false}; + + /// Maximum number of characters to read. + size_t nchars{std::numeric_limits::max()}; }; -maybe_t reader_data_t::readline(int nchars) { +/// Read normal characters, inserting them into the command line. +/// \return the next unhandled event. +maybe_t reader_data_t::read_normal_chars(readline_loop_state_t &rls) { + int was_interactive_read = is_interactive_read; + is_interactive_read = 1; + maybe_t event_needing_handling = input_readch(); + is_interactive_read = was_interactive_read; + + if (!event_is_normal_char(*event_needing_handling) || !can_read(STDIN_FILENO)) + return event_needing_handling; + + // This is a normal character input. + // We are going to handle it directly, accumulating more. + char_event_t evt = event_needing_handling.acquire(); + size_t limit = std::min(rls.nchars - command_line.size(), READAHEAD_MAX); + + wchar_t arr[READAHEAD_MAX + 1] = {}; + arr[0] = evt.get_char(); + + for (size_t i = 1; i < limit; ++i) { + if (!can_read(0)) { + break; + } + // Only allow commands on the first key; otherwise, we might have data we + // need to insert on the commandline that the commmand might need to be able + // to see. + auto next_event = input_readch(false); + if (event_is_normal_char(next_event)) { + arr[i] = next_event.get_char(); + } else { + // We need to process this in the outer loop. + assert(!event_needing_handling && "Should not have an unhandled event"); + event_needing_handling = next_event; + break; + } + } + + editable_line_t *el = active_edit_line(); + insert_string(el, arr, true); + + // End paging upon inserting into the normal command line. + if (el == &command_line) { + clear_pager(); + } + + // Since we handled a normal character, we don't have a last command. + rls.last_cmd.reset(); + return event_needing_handling; +} + +maybe_t reader_data_t::readline(int nchars_or_0) { using rl = readline_cmd_t; readline_loop_state_t rls{}; struct termios old_modes; + // If nchars_or_0 is positive, then that's the maximum number of chars. Otherwise keep it at + // SIZE_MAX. + if (nchars_or_0 > 0) { + rls.nchars = static_cast(nchars_or_0); + } + // The command line before completion. cycle_command_line.clear(); cycle_cursor_pos = 0; @@ -2465,70 +2527,18 @@ maybe_t reader_data_t::readline(int nchars) { } while (!rls.finished && !shell_is_exiting()) { - if (0 < nchars && (size_t)nchars <= command_line.size()) { + if (rls.nchars <= command_line.size()) { // We've already hit the specified character limit. rls.finished = true; break; } - // Sometimes strange input sequences seem to generate a zero byte. I believe these simply - // mean a character was pressed but it should be ignored. (Example: Trying to add a tilde - // (~) to digit). maybe_t event_needing_handling{}; while (1) { - int was_interactive_read = is_interactive_read; - is_interactive_read = 1; - event_needing_handling = input_readch(); - is_interactive_read = was_interactive_read; - // std::fwprintf(stderr, L"C: %lx\n", (long)c); - - if (event_is_normal_char(*event_needing_handling) && can_read(STDIN_FILENO)) { - // This is a normal character input. - // We are going to handle it directly, accumulating more. - // Clear 'mevt' to mark that we handled this. - char_event_t evt = event_needing_handling.acquire(); - size_t limit = 0 < nchars ? std::min((size_t)nchars - command_line.size(), - (size_t)READAHEAD_MAX) - : READAHEAD_MAX; - - wchar_t arr[READAHEAD_MAX + 1] = {}; - arr[0] = evt.get_char(); - - for (size_t i = 1; i < limit; ++i) { - if (!can_read(0)) { - break; - } - // Only allow commands on the first key; otherwise, we might have data we - // need to insert on the commandline that the commmand might need to be able - // to see. - auto next_event = input_readch(false); - if (event_is_normal_char(next_event)) { - arr[i] = next_event.get_char(); - } else { - // We need to process this in the outer loop. - assert(!event_needing_handling && "Should not have an unhandled event"); - event_needing_handling = next_event; - break; - } - } - - editable_line_t *el = active_edit_line(); - insert_string(el, arr, true); - - // End paging upon inserting into the normal command line. - if (el == &command_line) { - clear_pager(); - } - - // Since we handled a normal character, we don't have a last command. - rls.last_cmd.reset(); - } - - // If there's still an event that we were unable to handle, then end the coalescing - // loop. + event_needing_handling = read_normal_chars(rls); if (event_needing_handling.has_value()) break; - if (0 < nchars && (size_t)nchars <= command_line.size()) { + if (rls.nchars <= command_line.size()) { event_needing_handling.reset(); break; } From 6ba94fd81b1a11623258d0c2763e9edd5c811e59 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Mon, 18 Mar 2019 20:06:16 -0700 Subject: [PATCH 0139/1732] Factor readline command handling into new function handle_readline_command() --- src/reader.cpp | 1459 ++++++++++++++++++++++++------------------------ 1 file changed, 730 insertions(+), 729 deletions(-) diff --git a/src/reader.cpp b/src/reader.cpp index 7d1668072..a6f6a0644 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -444,6 +444,7 @@ class reader_data_t : public std::enable_shared_from_this { maybe_t readline(int nchars); maybe_t read_normal_chars(readline_loop_state_t &rls); + void handle_readline_command(readline_cmd_t cmd, readline_loop_state_t &rls); void clear_pager(); void select_completion_in_direction(enum selection_direction_t dir); @@ -2484,6 +2485,731 @@ maybe_t reader_data_t::read_normal_chars(readline_loop_state_t &rl return event_needing_handling; } +/// Handle a readline command \p c, updating the state \p rls. +void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_state_t &rls) { + const auto &vars = parser_t::principal_parser().vars(); + using rl = readline_cmd_t; + switch (c) { + // Go to beginning of line. + case rl::R_BEGINNING_OF_LINE: { + editable_line_t *el = active_edit_line(); + while (el->position > 0 && el->text.at(el->position - 1) != L'\n') { + update_buff_pos(el, el->position - 1); + } + + reader_repaint_needed(); + break; + } + case rl::R_END_OF_LINE: { + editable_line_t *el = active_edit_line(); + if (el->position < el->size()) { + const wchar_t *buff = el->text.c_str(); + while (buff[el->position] && buff[el->position] != L'\n') { + update_buff_pos(el, el->position + 1); + } + } else { + accept_autosuggestion(true); + } + + reader_repaint_needed(); + break; + } + case rl::R_BEGINNING_OF_BUFFER: { + update_buff_pos(&command_line, 0); + reader_repaint_needed(); + break; + } + case rl::R_END_OF_BUFFER: { + update_buff_pos(&command_line, command_line.size()); + reader_repaint_needed(); + break; + } + case rl::R_CANCEL: { + // The only thing we can cancel right now is paging, which we handled up above. + break; + } + case rl::R_FORCE_REPAINT: + case rl::R_REPAINT: { + if (!rls.coalescing_repaints) { + rls.coalescing_repaints = true; + exec_prompt(); + s_reset(&screen, screen_reset_current_line_and_prompt); + screen_reset_needed = false; + repaint(); + } + break; + } + case rl::R_COMPLETE: + case rl::R_COMPLETE_AND_SEARCH: { + if (!complete_func) break; + + // Use the command line only; it doesn't make sense to complete in any other line. + editable_line_t *el = &command_line; + if (is_navigating_pager_contents() || + (!rls.comp_empty && rls.last_cmd == rl::R_COMPLETE)) { + // The user typed R_COMPLETE more than once in a row. If we are not yet fully + // disclosed, then become so; otherwise cycle through our available completions. + if (current_page_rendering.remaining_to_disclose > 0) { + pager.set_fully_disclosed(true); + reader_repaint_needed(); + } else { + select_completion_in_direction(c == rl::R_COMPLETE ? direction_next + : direction_prev); + } + } else { + // Either the user hit tab only once, or we had no visible completion list. + // Remove a trailing backslash. This may trigger an extra repaint, but this is + // rare. + if (is_backslashed(el->text, el->position)) { + remove_backward(); + } + + // Get the string; we have to do this after removing any trailing backslash. + const wchar_t *const buff = el->text.c_str(); + + // Clear the completion list. + rls.comp.clear(); + + // Figure out the extent of the command substitution surrounding the cursor. + // This is because we only look at the current command substitution to form + // completions - stuff happening outside of it is not interesting. + const wchar_t *cmdsub_begin, *cmdsub_end; + parse_util_cmdsubst_extent(buff, el->position, &cmdsub_begin, &cmdsub_end); + + // Figure out the extent of the token within the command substitution. Note we + // pass cmdsub_begin here, not buff. + const wchar_t *token_begin, *token_end; + parse_util_token_extent(cmdsub_begin, el->position - (cmdsub_begin - buff), + &token_begin, &token_end, 0, 0); + + // Hack: the token may extend past the end of the command substitution, e.g. in + // (echo foo) the last token is 'foo)'. Don't let that happen. + if (token_end > cmdsub_end) token_end = cmdsub_end; + + // Figure out how many steps to get from the current position to the end of the + // current token. + size_t end_of_token_offset = token_end - buff; + + // Move the cursor to the end. + if (el->position != end_of_token_offset) { + update_buff_pos(el, end_of_token_offset); + repaint(); + } + + // Construct a copy of the string from the beginning of the command substitution + // up to the end of the token we're completing. + const wcstring buffcpy = wcstring(cmdsub_begin, token_end); + + // std::fwprintf(stderr, L"Complete (%ls)\n", buffcpy.c_str()); + complete_flags_t complete_flags = COMPLETION_REQUEST_DEFAULT | + COMPLETION_REQUEST_DESCRIPTIONS | + COMPLETION_REQUEST_FUZZY_MATCH; + complete_func(buffcpy, &rls.comp, complete_flags, vars); + + // Munge our completions. + completions_sort_and_prioritize(&rls.comp); + + // Record our cycle_command_line. + cycle_command_line = el->text; + cycle_cursor_pos = el->position; + + bool cont_after_prefix_insertion = (c == rl::R_COMPLETE_AND_SEARCH); + rls.comp_empty = handle_completions(rls.comp, cont_after_prefix_insertion); + + // Show the search field if requested and if we printed a list of completions. + if (c == rl::R_COMPLETE_AND_SEARCH && !rls.comp_empty && !pager.empty()) { + pager.set_search_field_shown(true); + select_completion_in_direction(direction_next); + reader_repaint_needed(); + } + } + break; + } + case rl::R_PAGER_TOGGLE_SEARCH: { + if (!pager.empty()) { + // Toggle search, and begin navigating if we are now searching. + bool sfs = pager.is_search_field_shown(); + pager.set_search_field_shown(!sfs); + pager.set_fully_disclosed(true); + if (pager.is_search_field_shown() && !is_navigating_pager_contents()) { + select_completion_in_direction(direction_south); + } + reader_repaint_needed(); + } + break; + } + case rl::R_KILL_LINE: { + editable_line_t *el = active_edit_line(); + const wchar_t *buff = el->text.c_str(); + const wchar_t *begin = &buff[el->position]; + const wchar_t *end = begin; + + while (*end && *end != L'\n') end++; + + if (end == begin && *end) end++; + + size_t len = end - begin; + if (len) { + kill(el, begin - buff, len, KILL_APPEND, rls.last_cmd != rl::R_KILL_LINE); + } + break; + } + case rl::R_BACKWARD_KILL_LINE: { + editable_line_t *el = active_edit_line(); + if (el->position <= 0) { + break; + } + const wchar_t *buff = el->text.c_str(); + const wchar_t *end = &buff[el->position]; + const wchar_t *begin = end; + + begin--; // make sure we delete at least one character (see issue #580) + + // Delete until we hit a newline, or the beginning of the string. + while (begin > buff && *begin != L'\n') begin--; + + // If we landed on a newline, don't delete it. + if (*begin == L'\n') begin++; + assert(end >= begin); + size_t len = std::max(end - begin, 1); + begin = end - len; + kill(el, begin - buff, len, KILL_PREPEND, rls.last_cmd != rl::R_BACKWARD_KILL_LINE); + break; + } + case rl::R_KILL_WHOLE_LINE: { + // We match the emacs behavior here: "kills the entire line including the following + // newline". + editable_line_t *el = active_edit_line(); + const wchar_t *buff = el->text.c_str(); + + // Back up to the character just past the previous newline, or go to the beginning + // of the command line. Note that if the position is on a newline, visually this + // looks like the cursor is at the end of a line. Therefore that newline is NOT the + // beginning of a line; this justifies the -1 check. + size_t begin = el->position; + while (begin > 0 && buff[begin - 1] != L'\n') { + begin--; + } + + // Push end forwards to just past the next newline, or just past the last char. + size_t end = el->position; + while (buff[end] != L'\0') { + end++; + if (buff[end - 1] == L'\n') { + break; + } + } + assert(end >= begin); + + if (end > begin) { + kill(el, begin, end - begin, KILL_APPEND, rls.last_cmd != rl::R_KILL_WHOLE_LINE); + } + break; + } + case rl::R_YANK: { + wcstring yank_str = kill_yank(); + insert_string(active_edit_line(), yank_str); + rls.yank_len = yank_str.size(); + break; + } + case rl::R_YANK_POP: { + if (rls.yank_len) { + for (size_t i = 0; i < rls.yank_len; i++) remove_backward(); + + wcstring yank_str = kill_yank_rotate(); + insert_string(active_edit_line(), yank_str); + rls.yank_len = yank_str.size(); + } + break; + } + case rl::R_BACKWARD_DELETE_CHAR: { + remove_backward(); + break; + } + case rl::R_DELETE_CHAR: { + // Remove the current character in the character buffer and on the screen using + // syntax highlighting, etc. + editable_line_t *el = active_edit_line(); + if (el->position < el->size()) { + update_buff_pos(el, el->position + 1); + remove_backward(); + } + break; + } + // Evaluate. If the current command is unfinished, or if the charater is escaped + // using a backslash, insert a newline. + case rl::R_EXECUTE: { + // If the user hits return while navigating the pager, it only clears the pager. + if (is_navigating_pager_contents()) { + clear_pager(); + break; + } + + // Delete any autosuggestion. + autosuggestion.clear(); + + // The user may have hit return with pager contents, but while not navigating them. + // Clear the pager in that event. + clear_pager(); + + // We only execute the command line. + editable_line_t *el = &command_line; + + // Allow backslash-escaped newlines. + bool continue_on_next_line = false; + if (el->position >= el->size()) { + // We're at the end of the text and not in a comment (issue #1225). + continue_on_next_line = + is_backslashed(el->text, el->position) && !text_ends_in_comment(el->text); + } else { + // Allow mid line split if the following character is whitespace (issue #613). + if (is_backslashed(el->text, el->position) && iswspace(el->text.at(el->position))) { + continue_on_next_line = true; + // Check if the end of the line is backslashed (issue #4467). + } else if (is_backslashed(el->text, el->size()) && + !text_ends_in_comment(el->text)) { + // Move the cursor to the end of the line. + el->position = el->size(); + continue_on_next_line = true; + } + } + // If the conditions are met, insert a new line at the position of the cursor. + if (continue_on_next_line) { + insert_char(el, '\n'); + break; + } + + // See if this command is valid. + int command_test_result = test_func(el->text); + if (command_test_result == 0 || command_test_result == PARSER_TEST_INCOMPLETE) { + // This command is valid, but an abbreviation may make it invalid. If so, we + // will have to test again. + bool abbreviation_expanded = expand_abbreviation_as_necessary(1); + if (abbreviation_expanded) { + // It's our reponsibility to rehighlight and repaint. But everything we do + // below triggers a repaint. + command_test_result = test_func(el->text.c_str()); + + // If the command is OK, then we're going to execute it. We still want to do + // syntax highlighting, but a synchronous variant that performs no I/O, so + // as not to block the user. + bool skip_io = (command_test_result == 0); + super_highlight_me_plenty(0, skip_io); + } + } + + if (command_test_result == 0) { + // Finished command, execute it. Don't add items that start with a leading + // space. + const editable_line_t *el = &command_line; + if (history != NULL && !el->empty() && el->text.at(0) != L' ') { + history->add_pending_with_file_detection(el->text, vars.get_pwd_slash()); + } + rls.finished = true; + update_buff_pos(&command_line, command_line.size()); + repaint(); + } else if (command_test_result == PARSER_TEST_INCOMPLETE) { + // We are incomplete, continue editing. + insert_char(el, '\n'); + } else { + // Result must be some combination including an error. The error message will + // already be printed, all we need to do is repaint. + s_reset(&screen, screen_reset_abandon_line); + reader_repaint_needed(); + } + + break; + } + + case rl::R_HISTORY_SEARCH_BACKWARD: + case rl::R_HISTORY_TOKEN_SEARCH_BACKWARD: + case rl::R_HISTORY_SEARCH_FORWARD: + case rl::R_HISTORY_TOKEN_SEARCH_FORWARD: { + if (history_search.is_at_end()) { + const editable_line_t *el = &command_line; + bool by_token = (c == rl::R_HISTORY_TOKEN_SEARCH_BACKWARD) || + (c == rl::R_HISTORY_TOKEN_SEARCH_FORWARD); + if (by_token) { + // Searching by token. + const wchar_t *begin, *end; + const wchar_t *buff = el->text.c_str(); + parse_util_token_extent(buff, el->position, &begin, &end, 0, 0); + if (begin) { + wcstring token(begin, end); + history_search.reset_to_mode(token, history, + reader_history_search_t::token); + } else { + // No current token, refuse to do a token search. + history_search.reset(); + } + } else { + // Searching by line. + history_search.reset_to_mode(el->text, history, reader_history_search_t::line); + + // Skip the autosuggestion in the history unless it was truncated. + const wcstring &suggest = autosuggestion; + if (!suggest.empty() && !screen.autosuggestion_is_truncated) { + history_search.add_skip(suggest); + } + } + } + if (history_search.active()) { + history_search_direction_t dir = + (c == rl::R_HISTORY_SEARCH_BACKWARD || c == rl::R_HISTORY_TOKEN_SEARCH_BACKWARD) + ? history_search_direction_t::backward + : history_search_direction_t::forward; + history_search.move_in_direction(dir); + update_command_line_from_history_search(); + } + break; + } + case rl::R_BACKWARD_CHAR: { + editable_line_t *el = active_edit_line(); + if (is_navigating_pager_contents()) { + select_completion_in_direction(direction_west); + } else if (el->position > 0) { + update_buff_pos(el, el->position - 1); + reader_repaint_needed(); + } + break; + } + case rl::R_FORWARD_CHAR: { + editable_line_t *el = active_edit_line(); + if (is_navigating_pager_contents()) { + select_completion_in_direction(direction_east); + } else if (el->position < el->size()) { + update_buff_pos(el, el->position + 1); + reader_repaint_needed(); + } else { + accept_autosuggestion(true); + } + break; + } + case rl::R_BACKWARD_KILL_WORD: + case rl::R_BACKWARD_KILL_PATH_COMPONENT: + case rl::R_BACKWARD_KILL_BIGWORD: { + move_word_style_t style = + (c == rl::R_BACKWARD_KILL_BIGWORD + ? move_word_style_whitespace + : c == rl::R_BACKWARD_KILL_PATH_COMPONENT ? move_word_style_path_components + : move_word_style_punctuation); + // Is this the same killring item as the last kill? + bool newv = (rls.last_cmd != rl::R_BACKWARD_KILL_WORD && + rls.last_cmd != rl::R_BACKWARD_KILL_PATH_COMPONENT && + rls.last_cmd != rl::R_BACKWARD_KILL_BIGWORD); + move_word(active_edit_line(), MOVE_DIR_LEFT, true /* erase */, style, newv); + break; + } + case rl::R_KILL_WORD: + case rl::R_KILL_BIGWORD: { + // The "bigword" functions differ only in that they move to the next whitespace, not + // punctuation. + auto move_style = + (c == rl::R_KILL_WORD) ? move_word_style_punctuation : move_word_style_whitespace; + move_word(active_edit_line(), MOVE_DIR_RIGHT, true /* erase */, move_style, + rls.last_cmd != c /* same kill item if same movement */); + break; + } + case rl::R_BACKWARD_WORD: + case rl::R_BACKWARD_BIGWORD: { + auto move_style = (c == rl::R_BACKWARD_WORD) ? move_word_style_punctuation + : move_word_style_whitespace; + move_word(active_edit_line(), MOVE_DIR_LEFT, false /* do not erase */, move_style, + false); + break; + } + case rl::R_FORWARD_WORD: + case rl::R_FORWARD_BIGWORD: { + auto move_style = (c == rl::R_FORWARD_WORD) ? move_word_style_punctuation + : move_word_style_whitespace; + editable_line_t *el = active_edit_line(); + if (el->position < el->size()) { + move_word(el, MOVE_DIR_RIGHT, false /* do not erase */, move_style, false); + } else { + accept_autosuggestion(false, move_style); + } + break; + } + case rl::R_BEGINNING_OF_HISTORY: + case rl::R_END_OF_HISTORY: { + bool up = (c == rl::R_BEGINNING_OF_HISTORY); + if (is_navigating_pager_contents()) { + select_completion_in_direction(up ? direction_page_north : direction_page_south); + } else { + if (up) { + history_search.go_to_beginning(); + } else { + history_search.go_to_end(); + } + update_command_line_from_history_search(); + } + break; + } + case rl::R_UP_LINE: + case rl::R_DOWN_LINE: { + if (is_navigating_pager_contents()) { + // We are already navigating pager contents. + selection_direction_t direction; + if (c == rl::R_DOWN_LINE) { + // Down arrow is always south. + direction = direction_south; + } else if (selection_is_at_top()) { + // Up arrow, but we are in the first column and first row. End navigation. + direction = direction_deselect; + } else { + // Up arrow, go north. + direction = direction_north; + } + + // Now do the selection. + select_completion_in_direction(direction); + } else if (!pager.empty()) { + // We pressed a direction with a non-empty pager, begin navigation. + select_completion_in_direction(c == rl::R_DOWN_LINE ? direction_south + : direction_north); + } else { + // Not navigating the pager contents. + editable_line_t *el = active_edit_line(); + int line_old = parse_util_get_line_from_offset(el->text, el->position); + int line_new; + + if (c == rl::R_UP_LINE) + line_new = line_old - 1; + else + line_new = line_old + 1; + + int line_count = parse_util_lineno(el->text.c_str(), el->size()) - 1; + + if (line_new >= 0 && line_new <= line_count) { + size_t base_pos_new; + size_t base_pos_old; + + int indent_old; + int indent_new; + size_t line_offset_old; + size_t total_offset_new; + + base_pos_new = parse_util_get_offset_from_line(el->text, line_new); + + base_pos_old = parse_util_get_offset_from_line(el->text, line_old); + + assert(base_pos_new != (size_t)(-1) && base_pos_old != (size_t)(-1)); + indent_old = indents.at(base_pos_old); + indent_new = indents.at(base_pos_new); + + line_offset_old = + el->position - parse_util_get_offset_from_line(el->text, line_old); + total_offset_new = parse_util_get_offset( + el->text, line_new, line_offset_old - 4 * (indent_new - indent_old)); + update_buff_pos(el, total_offset_new); + reader_repaint_needed(); + } + } + break; + } + case rl::R_SUPPRESS_AUTOSUGGESTION: { + suppress_autosuggestion = true; + autosuggestion.clear(); + reader_repaint_needed(); + break; + } + case rl::R_ACCEPT_AUTOSUGGESTION: { + accept_autosuggestion(true); + break; + } + case rl::R_TRANSPOSE_CHARS: { + editable_line_t *el = active_edit_line(); + if (el->size() < 2) { + break; + } + + // If the cursor is at the end, transpose the last two characters of the line. + if (el->position == el->size()) { + update_buff_pos(el, el->position - 1); + } + + // Drag the character before the cursor forward over the character at the cursor, + // moving the cursor forward as well. + if (el->position > 0) { + wcstring local_cmd = el->text; + std::swap(local_cmd.at(el->position), local_cmd.at(el->position - 1)); + set_command_line_and_position(el, local_cmd, el->position + 1); + } + break; + } + case rl::R_TRANSPOSE_WORDS: { + editable_line_t *el = active_edit_line(); + size_t len = el->size(); + const wchar_t *buff = el->text.c_str(); + const wchar_t *tok_begin, *tok_end, *prev_begin, *prev_end; + + // If we are not in a token, look for one ahead. + size_t buff_pos = el->position; + while (buff_pos != len && !iswalnum(buff[buff_pos])) buff_pos++; + + update_buff_pos(el, buff_pos); + + parse_util_token_extent(buff, el->position, &tok_begin, &tok_end, &prev_begin, + &prev_end); + + // In case we didn't find a token at or after the cursor... + if (tok_begin == &buff[len]) { + // ...retry beginning from the previous token. + size_t pos = prev_end - &buff[0]; + parse_util_token_extent(buff, pos, &tok_begin, &tok_end, &prev_begin, &prev_end); + } + + // Make sure we have two tokens. + if (prev_begin < prev_end && tok_begin < tok_end && tok_begin > prev_begin) { + const wcstring prev(prev_begin, prev_end - prev_begin); + const wcstring sep(prev_end, tok_begin - prev_end); + const wcstring tok(tok_begin, tok_end - tok_begin); + const wcstring trail(tok_end, &buff[len] - tok_end); + + // Compose new command line with swapped tokens. + wcstring new_buff(buff, prev_begin - buff); + new_buff.append(tok); + new_buff.append(sep); + new_buff.append(prev); + new_buff.append(trail); + // Put cursor right after the second token. + set_command_line_and_position(el, new_buff, tok_end - buff); + } + break; + } + case rl::R_UPCASE_WORD: + case rl::R_DOWNCASE_WORD: + case rl::R_CAPITALIZE_WORD: { + editable_line_t *el = active_edit_line(); + // For capitalize_word, whether we've capitalized a character so far. + bool capitalized_first = false; + + // We apply the operation from the current location to the end of the word. + size_t pos = el->position; + move_word(el, MOVE_DIR_RIGHT, false, move_word_style_punctuation, false); + for (; pos < el->position; pos++) { + wchar_t chr = el->text.at(pos); + + // We always change the case; this decides whether we go uppercase (true) or + // lowercase (false). + bool make_uppercase; + if (c == rl::R_CAPITALIZE_WORD) + make_uppercase = !capitalized_first && iswalnum(chr); + else + make_uppercase = (c == rl::R_UPCASE_WORD); + + // Apply the operation and then record what we did. + if (make_uppercase) + chr = towupper(chr); + else + chr = towlower(chr); + + command_line.text.at(pos) = chr; + capitalized_first = capitalized_first || make_uppercase; + } + command_line_changed(el); + super_highlight_me_plenty(); + reader_repaint_needed(); + break; + } + case rl::R_BEGIN_SELECTION: + case rl::R_END_SELECTION: { + sel_start_pos = command_line.position; + sel_stop_pos = command_line.position; + if (c == rl::R_BEGIN_SELECTION) { + sel_active = true; + sel_begin_pos = command_line.position; + } else { + sel_active = false; + } + + break; + } + case rl::R_SWAP_SELECTION_START_STOP: { + if (!sel_active) break; + size_t tmp = sel_begin_pos; + sel_begin_pos = command_line.position; + sel_start_pos = command_line.position; + editable_line_t *el = active_edit_line(); + update_buff_pos(el, tmp); + break; + } + case rl::R_KILL_SELECTION: { + bool newv = (rls.last_cmd != rl::R_KILL_SELECTION); + size_t start, len; + if (reader_get_selection(&start, &len)) { + kill(&command_line, start, len, KILL_APPEND, newv); + } + break; + } + case rl::R_FORWARD_JUMP: + case rl::R_BACKWARD_JUMP: + case rl::R_FORWARD_JUMP_TILL: + case rl::R_BACKWARD_JUMP_TILL: { + auto direction = (c == rl::R_FORWARD_JUMP || c == rl::R_FORWARD_JUMP_TILL) + ? jump_direction_t::forward + : jump_direction_t::backward; + auto precision = (c == rl::R_FORWARD_JUMP || c == rl::R_BACKWARD_JUMP) + ? jump_precision_t::to + : jump_precision_t::till; + editable_line_t *el = active_edit_line(); + wchar_t target = input_function_pop_arg(); + bool success = jump(direction, precision, el, target); + + input_function_set_status(success); + reader_repaint_needed(); + break; + } + case rl::R_REPEAT_JUMP: { + editable_line_t *el = active_edit_line(); + bool success = false; + + if (last_jump_target) { + success = jump(last_jump_direction, last_jump_precision, el, last_jump_target); + } + + input_function_set_status(success); + reader_repaint_needed(); + break; + } + case rl::R_REVERSE_REPEAT_JUMP: { + editable_line_t *el = active_edit_line(); + bool success = false; + jump_direction_t original_dir, dir; + original_dir = dir = last_jump_direction; + + if (last_jump_direction == jump_direction_t::forward) { + dir = jump_direction_t::backward; + } else { + dir = jump_direction_t::forward; + } + + if (last_jump_target) { + success = jump(dir, last_jump_precision, el, last_jump_target); + } + + last_jump_direction = original_dir; + + input_function_set_status(success); + reader_repaint_needed(); + break; + } + + // Some commands should have been handled internally by input_readch(). + case rl::R_SELF_INSERT: { + DIE("self-insert should have been handled by input_readch"); + } + case rl::R_AND: { + DIE("self-insert should have been handled by input_readch"); + } + case rl::R_VI_ARG_DIGIT: + case rl::R_VI_DELETE_TO: { + // TODO: what needs to happen with these? + break; + } + } +} + maybe_t reader_data_t::readline(int nchars_or_0) { using rl = readline_cmd_t; readline_loop_state_t rls{}; @@ -2507,8 +3233,6 @@ maybe_t reader_data_t::readline(int nchars_or_0) { s_reset(&screen, screen_reset_abandon_line); repaint(); - const auto &vars = parser_t::principal_parser().vars(); - // Get the current terminal modes. These will be restored when the function returns. if (tcgetattr(STDIN_FILENO, &old_modes) == -1 && errno == EIO) redirect_tty_output(); @@ -2579,732 +3303,13 @@ maybe_t reader_data_t::readline(int nchars_or_0) { if (command_ends_paging(*readline_cmd, focused_on_search_field)) { clear_pager(); } - } - readline_cmd_t c = readline_cmd ? *readline_cmd : static_cast(0); - switch (c) { - // Go to beginning of line. - case rl::R_BEGINNING_OF_LINE: { - editable_line_t *el = active_edit_line(); - while (el->position > 0 && el->text.at(el->position - 1) != L'\n') { - update_buff_pos(el, el->position - 1); - } + handle_readline_command(*readline_cmd, rls); - reader_repaint_needed(); - break; - } - case rl::R_END_OF_LINE: { - editable_line_t *el = active_edit_line(); - if (el->position < el->size()) { - const wchar_t *buff = el->text.c_str(); - while (buff[el->position] && buff[el->position] != L'\n') { - update_buff_pos(el, el->position + 1); - } - } else { - accept_autosuggestion(true); - } - - reader_repaint_needed(); - break; - } - case rl::R_BEGINNING_OF_BUFFER: { - update_buff_pos(&command_line, 0); - reader_repaint_needed(); - break; - } - case rl::R_END_OF_BUFFER: { - update_buff_pos(&command_line, command_line.size()); - reader_repaint_needed(); - break; - } - case rl::R_CANCEL: { - // The only thing we can cancel right now is paging, which we handled up above. - break; - } - case rl::R_FORCE_REPAINT: - case rl::R_REPAINT: { - if (!rls.coalescing_repaints) { - rls.coalescing_repaints = true; - exec_prompt(); - s_reset(&screen, screen_reset_current_line_and_prompt); - screen_reset_needed = false; - repaint(); - } - break; - } - case rl::R_COMPLETE: - case rl::R_COMPLETE_AND_SEARCH: { - if (!complete_func) break; - - // Use the command line only; it doesn't make sense to complete in any other line. - editable_line_t *el = &command_line; - if (is_navigating_pager_contents() || - (!rls.comp_empty && rls.last_cmd == rl::R_COMPLETE)) { - // The user typed R_COMPLETE more than once in a row. If we are not yet fully - // disclosed, then become so; otherwise cycle through our available completions. - if (current_page_rendering.remaining_to_disclose > 0) { - pager.set_fully_disclosed(true); - reader_repaint_needed(); - } else { - select_completion_in_direction(c == rl::R_COMPLETE ? direction_next - : direction_prev); - } - } else { - // Either the user hit tab only once, or we had no visible completion list. - // Remove a trailing backslash. This may trigger an extra repaint, but this is - // rare. - if (is_backslashed(el->text, el->position)) { - remove_backward(); - } - - // Get the string; we have to do this after removing any trailing backslash. - const wchar_t *const buff = el->text.c_str(); - - // Clear the completion list. - rls.comp.clear(); - - // Figure out the extent of the command substitution surrounding the cursor. - // This is because we only look at the current command substitution to form - // completions - stuff happening outside of it is not interesting. - const wchar_t *cmdsub_begin, *cmdsub_end; - parse_util_cmdsubst_extent(buff, el->position, &cmdsub_begin, &cmdsub_end); - - // Figure out the extent of the token within the command substitution. Note we - // pass cmdsub_begin here, not buff. - const wchar_t *token_begin, *token_end; - parse_util_token_extent(cmdsub_begin, el->position - (cmdsub_begin - buff), - &token_begin, &token_end, 0, 0); - - // Hack: the token may extend past the end of the command substitution, e.g. in - // (echo foo) the last token is 'foo)'. Don't let that happen. - if (token_end > cmdsub_end) token_end = cmdsub_end; - - // Figure out how many steps to get from the current position to the end of the - // current token. - size_t end_of_token_offset = token_end - buff; - - // Move the cursor to the end. - if (el->position != end_of_token_offset) { - update_buff_pos(el, end_of_token_offset); - repaint(); - } - - // Construct a copy of the string from the beginning of the command substitution - // up to the end of the token we're completing. - const wcstring buffcpy = wcstring(cmdsub_begin, token_end); - - // std::fwprintf(stderr, L"Complete (%ls)\n", buffcpy.c_str()); - complete_flags_t complete_flags = COMPLETION_REQUEST_DEFAULT | - COMPLETION_REQUEST_DESCRIPTIONS | - COMPLETION_REQUEST_FUZZY_MATCH; - complete_func(buffcpy, &rls.comp, complete_flags, vars); - - // Munge our completions. - completions_sort_and_prioritize(&rls.comp); - - // Record our cycle_command_line. - cycle_command_line = el->text; - cycle_cursor_pos = el->position; - - bool cont_after_prefix_insertion = (c == rl::R_COMPLETE_AND_SEARCH); - rls.comp_empty = handle_completions(rls.comp, cont_after_prefix_insertion); - - // Show the search field if requested and if we printed a list of completions. - if (c == rl::R_COMPLETE_AND_SEARCH && !rls.comp_empty && !pager.empty()) { - pager.set_search_field_shown(true); - select_completion_in_direction(direction_next); - reader_repaint_needed(); - } - } - break; - } - case rl::R_PAGER_TOGGLE_SEARCH: { - if (!pager.empty()) { - // Toggle search, and begin navigating if we are now searching. - bool sfs = pager.is_search_field_shown(); - pager.set_search_field_shown(!sfs); - pager.set_fully_disclosed(true); - if (pager.is_search_field_shown() && !is_navigating_pager_contents()) { - select_completion_in_direction(direction_south); - } - reader_repaint_needed(); - } - break; - } - case rl::R_KILL_LINE: { - editable_line_t *el = active_edit_line(); - const wchar_t *buff = el->text.c_str(); - const wchar_t *begin = &buff[el->position]; - const wchar_t *end = begin; - - while (*end && *end != L'\n') end++; - - if (end == begin && *end) end++; - - size_t len = end - begin; - if (len) { - kill(el, begin - buff, len, KILL_APPEND, rls.last_cmd != rl::R_KILL_LINE); - } - break; - } - case rl::R_BACKWARD_KILL_LINE: { - editable_line_t *el = active_edit_line(); - if (el->position <= 0) { - break; - } - const wchar_t *buff = el->text.c_str(); - const wchar_t *end = &buff[el->position]; - const wchar_t *begin = end; - - begin--; // make sure we delete at least one character (see issue #580) - - // Delete until we hit a newline, or the beginning of the string. - while (begin > buff && *begin != L'\n') begin--; - - // If we landed on a newline, don't delete it. - if (*begin == L'\n') begin++; - assert(end >= begin); - size_t len = std::max(end - begin, 1); - begin = end - len; - kill(el, begin - buff, len, KILL_PREPEND, rls.last_cmd != rl::R_BACKWARD_KILL_LINE); - break; - } - case rl::R_KILL_WHOLE_LINE: { - // We match the emacs behavior here: "kills the entire line including the following - // newline". - editable_line_t *el = active_edit_line(); - const wchar_t *buff = el->text.c_str(); - - // Back up to the character just past the previous newline, or go to the beginning - // of the command line. Note that if the position is on a newline, visually this - // looks like the cursor is at the end of a line. Therefore that newline is NOT the - // beginning of a line; this justifies the -1 check. - size_t begin = el->position; - while (begin > 0 && buff[begin - 1] != L'\n') { - begin--; - } - - // Push end forwards to just past the next newline, or just past the last char. - size_t end = el->position; - while (buff[end] != L'\0') { - end++; - if (buff[end - 1] == L'\n') { - break; - } - } - assert(end >= begin); - - if (end > begin) { - kill(el, begin, end - begin, KILL_APPEND, - rls.last_cmd != rl::R_KILL_WHOLE_LINE); - } - break; - } - case rl::R_YANK: { - wcstring yank_str = kill_yank(); - insert_string(active_edit_line(), yank_str); - rls.yank_len = yank_str.size(); - break; - } - case rl::R_YANK_POP: { - if (rls.yank_len) { - for (size_t i = 0; i < rls.yank_len; i++) remove_backward(); - - wcstring yank_str = kill_yank_rotate(); - insert_string(active_edit_line(), yank_str); - rls.yank_len = yank_str.size(); - } - break; - } - case rl::R_BACKWARD_DELETE_CHAR: { - remove_backward(); - break; - } - case rl::R_DELETE_CHAR: { - // Remove the current character in the character buffer and on the screen using - // syntax highlighting, etc. - editable_line_t *el = active_edit_line(); - if (el->position < el->size()) { - update_buff_pos(el, el->position + 1); - remove_backward(); - } - break; - } - // Evaluate. If the current command is unfinished, or if the charater is escaped - // using a backslash, insert a newline. - case rl::R_EXECUTE: { - // If the user hits return while navigating the pager, it only clears the pager. - if (is_navigating_pager_contents()) { - clear_pager(); - break; - } - - // Delete any autosuggestion. - autosuggestion.clear(); - - // The user may have hit return with pager contents, but while not navigating them. - // Clear the pager in that event. - clear_pager(); - - // We only execute the command line. - editable_line_t *el = &command_line; - - // Allow backslash-escaped newlines. - bool continue_on_next_line = false; - if (el->position >= el->size()) { - // We're at the end of the text and not in a comment (issue #1225). - continue_on_next_line = - is_backslashed(el->text, el->position) && !text_ends_in_comment(el->text); - } else { - // Allow mid line split if the following character is whitespace (issue #613). - if (is_backslashed(el->text, el->position) && - iswspace(el->text.at(el->position))) { - continue_on_next_line = true; - // Check if the end of the line is backslashed (issue #4467). - } else if (is_backslashed(el->text, el->size()) && - !text_ends_in_comment(el->text)) { - // Move the cursor to the end of the line. - el->position = el->size(); - continue_on_next_line = true; - } - } - // If the conditions are met, insert a new line at the position of the cursor. - if (continue_on_next_line) { - insert_char(el, '\n'); - break; - } - - // See if this command is valid. - int command_test_result = test_func(el->text); - if (command_test_result == 0 || command_test_result == PARSER_TEST_INCOMPLETE) { - // This command is valid, but an abbreviation may make it invalid. If so, we - // will have to test again. - bool abbreviation_expanded = expand_abbreviation_as_necessary(1); - if (abbreviation_expanded) { - // It's our reponsibility to rehighlight and repaint. But everything we do - // below triggers a repaint. - command_test_result = test_func(el->text.c_str()); - - // If the command is OK, then we're going to execute it. We still want to do - // syntax highlighting, but a synchronous variant that performs no I/O, so - // as not to block the user. - bool skip_io = (command_test_result == 0); - super_highlight_me_plenty(0, skip_io); - } - } - - if (command_test_result == 0) { - // Finished command, execute it. Don't add items that start with a leading - // space. - const editable_line_t *el = &command_line; - if (history != NULL && !el->empty() && el->text.at(0) != L' ') { - history->add_pending_with_file_detection(el->text, vars.get_pwd_slash()); - } - rls.finished = true; - update_buff_pos(&command_line, command_line.size()); - repaint(); - } else if (command_test_result == PARSER_TEST_INCOMPLETE) { - // We are incomplete, continue editing. - insert_char(el, '\n'); - } else { - // Result must be some combination including an error. The error message will - // already be printed, all we need to do is repaint. - s_reset(&screen, screen_reset_abandon_line); - reader_repaint_needed(); - } - - break; - } - - case rl::R_HISTORY_SEARCH_BACKWARD: - case rl::R_HISTORY_TOKEN_SEARCH_BACKWARD: - case rl::R_HISTORY_SEARCH_FORWARD: - case rl::R_HISTORY_TOKEN_SEARCH_FORWARD: { - if (history_search.is_at_end()) { - const editable_line_t *el = &command_line; - bool by_token = (c == rl::R_HISTORY_TOKEN_SEARCH_BACKWARD) || - (c == rl::R_HISTORY_TOKEN_SEARCH_FORWARD); - if (by_token) { - // Searching by token. - const wchar_t *begin, *end; - const wchar_t *buff = el->text.c_str(); - parse_util_token_extent(buff, el->position, &begin, &end, 0, 0); - if (begin) { - wcstring token(begin, end); - history_search.reset_to_mode(token, history, - reader_history_search_t::token); - } else { - // No current token, refuse to do a token search. - history_search.reset(); - } - } else { - // Searching by line. - history_search.reset_to_mode(el->text, history, - reader_history_search_t::line); - - // Skip the autosuggestion in the history unless it was truncated. - const wcstring &suggest = autosuggestion; - if (!suggest.empty() && !screen.autosuggestion_is_truncated) { - history_search.add_skip(suggest); - } - } - } - if (history_search.active()) { - history_search_direction_t dir = (c == rl::R_HISTORY_SEARCH_BACKWARD || - c == rl::R_HISTORY_TOKEN_SEARCH_BACKWARD) - ? history_search_direction_t::backward - : history_search_direction_t::forward; - history_search.move_in_direction(dir); - update_command_line_from_history_search(); - } - break; - } - case rl::R_BACKWARD_CHAR: { - editable_line_t *el = active_edit_line(); - if (is_navigating_pager_contents()) { - select_completion_in_direction(direction_west); - } else if (el->position > 0) { - update_buff_pos(el, el->position - 1); - reader_repaint_needed(); - } - break; - } - case rl::R_FORWARD_CHAR: { - editable_line_t *el = active_edit_line(); - if (is_navigating_pager_contents()) { - select_completion_in_direction(direction_east); - } else if (el->position < el->size()) { - update_buff_pos(el, el->position + 1); - reader_repaint_needed(); - } else { - accept_autosuggestion(true); - } - break; - } - case rl::R_BACKWARD_KILL_WORD: - case rl::R_BACKWARD_KILL_PATH_COMPONENT: - case rl::R_BACKWARD_KILL_BIGWORD: { - move_word_style_t style = - (c == rl::R_BACKWARD_KILL_BIGWORD - ? move_word_style_whitespace - : c == rl::R_BACKWARD_KILL_PATH_COMPONENT ? move_word_style_path_components - : move_word_style_punctuation); - // Is this the same killring item as the last kill? - bool newv = (rls.last_cmd != rl::R_BACKWARD_KILL_WORD && - rls.last_cmd != rl::R_BACKWARD_KILL_PATH_COMPONENT && - rls.last_cmd != rl::R_BACKWARD_KILL_BIGWORD); - move_word(active_edit_line(), MOVE_DIR_LEFT, true /* erase */, style, newv); - break; - } - case rl::R_KILL_WORD: - case rl::R_KILL_BIGWORD: { - // The "bigword" functions differ only in that they move to the next whitespace, not - // punctuation. - auto move_style = (c == rl::R_KILL_WORD) ? move_word_style_punctuation - : move_word_style_whitespace; - move_word(active_edit_line(), MOVE_DIR_RIGHT, true /* erase */, move_style, - rls.last_cmd != c /* same kill item if same movement */); - break; - } - case rl::R_BACKWARD_WORD: - case rl::R_BACKWARD_BIGWORD: { - auto move_style = (c == rl::R_BACKWARD_WORD) ? move_word_style_punctuation - : move_word_style_whitespace; - move_word(active_edit_line(), MOVE_DIR_LEFT, false /* do not erase */, move_style, - false); - break; - } - case rl::R_FORWARD_WORD: - case rl::R_FORWARD_BIGWORD: { - auto move_style = (c == rl::R_FORWARD_WORD) ? move_word_style_punctuation - : move_word_style_whitespace; - editable_line_t *el = active_edit_line(); - if (el->position < el->size()) { - move_word(el, MOVE_DIR_RIGHT, false /* do not erase */, move_style, false); - } else { - accept_autosuggestion(false, move_style); - } - break; - } - case rl::R_BEGINNING_OF_HISTORY: - case rl::R_END_OF_HISTORY: { - bool up = (c == rl::R_BEGINNING_OF_HISTORY); - if (is_navigating_pager_contents()) { - select_completion_in_direction(up ? direction_page_north - : direction_page_south); - } else { - if (up) { - history_search.go_to_beginning(); - } else { - history_search.go_to_end(); - } - update_command_line_from_history_search(); - } - break; - } - case rl::R_UP_LINE: - case rl::R_DOWN_LINE: { - if (is_navigating_pager_contents()) { - // We are already navigating pager contents. - selection_direction_t direction; - if (c == rl::R_DOWN_LINE) { - // Down arrow is always south. - direction = direction_south; - } else if (selection_is_at_top()) { - // Up arrow, but we are in the first column and first row. End navigation. - direction = direction_deselect; - } else { - // Up arrow, go north. - direction = direction_north; - } - - // Now do the selection. - select_completion_in_direction(direction); - } else if (!pager.empty()) { - // We pressed a direction with a non-empty pager, begin navigation. - select_completion_in_direction(c == rl::R_DOWN_LINE ? direction_south - : direction_north); - } else { - // Not navigating the pager contents. - editable_line_t *el = active_edit_line(); - int line_old = parse_util_get_line_from_offset(el->text, el->position); - int line_new; - - if (c == rl::R_UP_LINE) - line_new = line_old - 1; - else - line_new = line_old + 1; - - int line_count = parse_util_lineno(el->text.c_str(), el->size()) - 1; - - if (line_new >= 0 && line_new <= line_count) { - size_t base_pos_new; - size_t base_pos_old; - - int indent_old; - int indent_new; - size_t line_offset_old; - size_t total_offset_new; - - base_pos_new = parse_util_get_offset_from_line(el->text, line_new); - - base_pos_old = parse_util_get_offset_from_line(el->text, line_old); - - assert(base_pos_new != (size_t)(-1) && base_pos_old != (size_t)(-1)); - indent_old = indents.at(base_pos_old); - indent_new = indents.at(base_pos_new); - - line_offset_old = - el->position - parse_util_get_offset_from_line(el->text, line_old); - total_offset_new = parse_util_get_offset( - el->text, line_new, line_offset_old - 4 * (indent_new - indent_old)); - update_buff_pos(el, total_offset_new); - reader_repaint_needed(); - } - } - break; - } - case rl::R_SUPPRESS_AUTOSUGGESTION: { - suppress_autosuggestion = true; - autosuggestion.clear(); - reader_repaint_needed(); - break; - } - case rl::R_ACCEPT_AUTOSUGGESTION: { - accept_autosuggestion(true); - break; - } - case rl::R_TRANSPOSE_CHARS: { - editable_line_t *el = active_edit_line(); - if (el->size() < 2) { - break; - } - - // If the cursor is at the end, transpose the last two characters of the line. - if (el->position == el->size()) { - update_buff_pos(el, el->position - 1); - } - - // Drag the character before the cursor forward over the character at the cursor, - // moving the cursor forward as well. - if (el->position > 0) { - wcstring local_cmd = el->text; - std::swap(local_cmd.at(el->position), local_cmd.at(el->position - 1)); - set_command_line_and_position(el, local_cmd, el->position + 1); - } - break; - } - case rl::R_TRANSPOSE_WORDS: { - editable_line_t *el = active_edit_line(); - size_t len = el->size(); - const wchar_t *buff = el->text.c_str(); - const wchar_t *tok_begin, *tok_end, *prev_begin, *prev_end; - - // If we are not in a token, look for one ahead. - size_t buff_pos = el->position; - while (buff_pos != len && !iswalnum(buff[buff_pos])) buff_pos++; - - update_buff_pos(el, buff_pos); - - parse_util_token_extent(buff, el->position, &tok_begin, &tok_end, &prev_begin, - &prev_end); - - // In case we didn't find a token at or after the cursor... - if (tok_begin == &buff[len]) { - // ...retry beginning from the previous token. - size_t pos = prev_end - &buff[0]; - parse_util_token_extent(buff, pos, &tok_begin, &tok_end, &prev_begin, - &prev_end); - } - - // Make sure we have two tokens. - if (prev_begin < prev_end && tok_begin < tok_end && tok_begin > prev_begin) { - const wcstring prev(prev_begin, prev_end - prev_begin); - const wcstring sep(prev_end, tok_begin - prev_end); - const wcstring tok(tok_begin, tok_end - tok_begin); - const wcstring trail(tok_end, &buff[len] - tok_end); - - // Compose new command line with swapped tokens. - wcstring new_buff(buff, prev_begin - buff); - new_buff.append(tok); - new_buff.append(sep); - new_buff.append(prev); - new_buff.append(trail); - // Put cursor right after the second token. - set_command_line_and_position(el, new_buff, tok_end - buff); - } - break; - } - case rl::R_UPCASE_WORD: - case rl::R_DOWNCASE_WORD: - case rl::R_CAPITALIZE_WORD: { - editable_line_t *el = active_edit_line(); - // For capitalize_word, whether we've capitalized a character so far. - bool capitalized_first = false; - - // We apply the operation from the current location to the end of the word. - size_t pos = el->position; - move_word(el, MOVE_DIR_RIGHT, false, move_word_style_punctuation, false); - for (; pos < el->position; pos++) { - wchar_t chr = el->text.at(pos); - - // We always change the case; this decides whether we go uppercase (true) or - // lowercase (false). - bool make_uppercase; - if (c == rl::R_CAPITALIZE_WORD) - make_uppercase = !capitalized_first && iswalnum(chr); - else - make_uppercase = (c == rl::R_UPCASE_WORD); - - // Apply the operation and then record what we did. - if (make_uppercase) - chr = towupper(chr); - else - chr = towlower(chr); - - command_line.text.at(pos) = chr; - capitalized_first = capitalized_first || make_uppercase; - } - command_line_changed(el); - super_highlight_me_plenty(); - reader_repaint_needed(); - break; - } - case rl::R_BEGIN_SELECTION: - case rl::R_END_SELECTION: { - sel_start_pos = command_line.position; - sel_stop_pos = command_line.position; - if (c == rl::R_BEGIN_SELECTION) { - sel_active = true; - sel_begin_pos = command_line.position; - } else { - sel_active = false; - } - - break; - } - case rl::R_SWAP_SELECTION_START_STOP: { - if (!sel_active) break; - size_t tmp = sel_begin_pos; - sel_begin_pos = command_line.position; - sel_start_pos = command_line.position; - editable_line_t *el = active_edit_line(); - update_buff_pos(el, tmp); - break; - } - case rl::R_KILL_SELECTION: { - bool newv = (rls.last_cmd != rl::R_KILL_SELECTION); - size_t start, len; - if (reader_get_selection(&start, &len)) { - kill(&command_line, start, len, KILL_APPEND, newv); - } - break; - } - case rl::R_FORWARD_JUMP: - case rl::R_BACKWARD_JUMP: - case rl::R_FORWARD_JUMP_TILL: - case rl::R_BACKWARD_JUMP_TILL: { - auto direction = (c == rl::R_FORWARD_JUMP || c == rl::R_FORWARD_JUMP_TILL) - ? jump_direction_t::forward - : jump_direction_t::backward; - auto precision = (c == rl::R_FORWARD_JUMP || c == rl::R_BACKWARD_JUMP) - ? jump_precision_t::to - : jump_precision_t::till; - editable_line_t *el = active_edit_line(); - wchar_t target = input_function_pop_arg(); - bool success = jump(direction, precision, el, target); - - input_function_set_status(success); - reader_repaint_needed(); - break; - } - case rl::R_REPEAT_JUMP: { - editable_line_t *el = active_edit_line(); - bool success = false; - - if (last_jump_target) { - success = jump(last_jump_direction, last_jump_precision, el, last_jump_target); - } - - input_function_set_status(success); - reader_repaint_needed(); - break; - } - case rl::R_REVERSE_REPEAT_JUMP: { - editable_line_t *el = active_edit_line(); - bool success = false; - jump_direction_t original_dir, dir; - original_dir = dir = last_jump_direction; - - if (last_jump_direction == jump_direction_t::forward) { - dir = jump_direction_t::backward; - } else { - dir = jump_direction_t::forward; - } - - if (last_jump_target) { - success = jump(dir, last_jump_precision, el, last_jump_target); - } - - last_jump_direction = original_dir; - - input_function_set_status(success); - reader_repaint_needed(); - break; - } - - // Some commands should have been handled internally by input_readch(). - case rl::R_SELF_INSERT: { - DIE("self-insert should have been handled by input_readch"); - } - case rl::R_AND: { - DIE("self-insert should have been handled by input_readch"); - } - case rl::R_VI_ARG_DIGIT: - case rl::R_VI_DELETE_TO: { - // TODO: what needs to happen with these? - break; + if (!readline_cmd || command_ends_history_search(*readline_cmd)) { + history_search.reset(); } + rls.last_cmd = readline_cmd; } if (ordinary_char) { @@ -3336,10 +3341,6 @@ maybe_t reader_data_t::readline(int nchars_or_0) { } } - if (!readline_cmd || command_ends_history_search(*readline_cmd)) { - history_search.reset(); - } - rls.last_cmd = readline_cmd; repaint_if_needed(); } From 9187458d51442e065d9a80d092fab377f72e1cad Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Wed, 20 Mar 2019 21:10:07 -0700 Subject: [PATCH 0140/1732] Continued refactoring of reader_data_t::readline --- src/reader.cpp | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/reader.cpp b/src/reader.cpp index a6f6a0644..d11b72124 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -3277,44 +3277,35 @@ maybe_t reader_data_t::readline(int nchars_or_0) { } assert((event_needing_handling->is_char() || event_needing_handling->is_readline()) && "Should have a char or readline"); - maybe_t readline_cmd{}; - maybe_t ordinary_char{}; - if (event_needing_handling->is_readline()) { - readline_cmd = event_needing_handling->get_readline(); - } else { - ordinary_char = event_needing_handling->get_char(); - } - - // If we get something other than a repaint, then stop coalescing them. - if (readline_cmd != rl::R_REPAINT) rls.coalescing_repaints = false; if (rls.last_cmd != rl::R_YANK && rls.last_cmd != rl::R_YANK_POP) { rls.yank_len = 0; } - // Restore the text. - if (readline_cmd) { - if (*readline_cmd == rl::R_CANCEL && is_navigating_pager_contents()) { + if (event_needing_handling->is_readline()) { + readline_cmd_t readline_cmd = event_needing_handling->get_readline(); + // If we get something other than a repaint, then stop coalescing them. + if (readline_cmd != rl::R_REPAINT) rls.coalescing_repaints = false; + + if (readline_cmd == rl::R_CANCEL && is_navigating_pager_contents()) { set_command_line_and_position(&command_line, cycle_command_line, cycle_cursor_pos); } // Clear the pager if necessary. bool focused_on_search_field = (active_edit_line() == &pager.search_field_line); - if (command_ends_paging(*readline_cmd, focused_on_search_field)) { + if (command_ends_paging(readline_cmd, focused_on_search_field)) { clear_pager(); } - handle_readline_command(*readline_cmd, rls); + handle_readline_command(readline_cmd, rls); - if (!readline_cmd || command_ends_history_search(*readline_cmd)) { + if (command_ends_history_search(readline_cmd)) { history_search.reset(); } rls.last_cmd = readline_cmd; - } - - if (ordinary_char) { - wchar_t c = *ordinary_char; - + } else { + // Ordinary char. + wchar_t c = event_needing_handling->get_char(); if (c == L'\x1B') { // Escape was pressed. if (history_search.active()) { @@ -3339,6 +3330,7 @@ maybe_t reader_data_t::readline(int nchars_or_0) { // reason to report this to the user unless they've enabled debugging output. debug(2, _(L"Unknown key binding 0x%X"), c); } + rls.last_cmd = none(); } repaint_if_needed(); From e7d7eff0eeee5966d485b6e72f8794c0353a8bfa Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 23 Mar 2019 17:32:39 -0700 Subject: [PATCH 0141/1732] Rename all readline commands to lowercase and remove R_ prefix --- src/fish_tests.cpp | 4 +- src/input.cpp | 128 ++++++++++---------- src/input_common.h | 120 +++++++++---------- src/reader.cpp | 284 ++++++++++++++++++++++----------------------- 4 files changed, 268 insertions(+), 268 deletions(-) diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 7d6a7109e..dfee85398 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -2999,8 +2999,8 @@ static void test_input() { auto evt = input_readch(); if (!evt.is_readline()) { err(L"Event is not a readline"); - } else if (evt.get_readline() != readline_cmd_t::R_DOWN_LINE) { - err(L"Expected to read char R_DOWN_LINE"); + } else if (evt.get_readline() != readline_cmd_t::down_line) { + err(L"Expected to read char down_line"); } } diff --git a/src/input.cpp b/src/input.cpp index 860edb2b4..256e0f62c 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -72,64 +72,64 @@ struct input_function_metadata_t { }; static const input_function_metadata_t input_function_metadata[] = { - {readline_cmd_t::R_BEGINNING_OF_LINE, L"beginning-of-line"}, - {readline_cmd_t::R_END_OF_LINE, L"end-of-line"}, - {readline_cmd_t::R_FORWARD_CHAR, L"forward-char"}, - {readline_cmd_t::R_BACKWARD_CHAR, L"backward-char"}, - {readline_cmd_t::R_FORWARD_WORD, L"forward-word"}, - {readline_cmd_t::R_BACKWARD_WORD, L"backward-word"}, - {readline_cmd_t::R_FORWARD_BIGWORD, L"forward-bigword"}, - {readline_cmd_t::R_BACKWARD_BIGWORD, L"backward-bigword"}, - {readline_cmd_t::R_HISTORY_SEARCH_BACKWARD, L"history-search-backward"}, - {readline_cmd_t::R_HISTORY_SEARCH_FORWARD, L"history-search-forward"}, - {readline_cmd_t::R_DELETE_CHAR, L"delete-char"}, - {readline_cmd_t::R_BACKWARD_DELETE_CHAR, L"backward-delete-char"}, - {readline_cmd_t::R_KILL_LINE, L"kill-line"}, - {readline_cmd_t::R_YANK, L"yank"}, - {readline_cmd_t::R_YANK_POP, L"yank-pop"}, - {readline_cmd_t::R_COMPLETE, L"complete"}, - {readline_cmd_t::R_COMPLETE_AND_SEARCH, L"complete-and-search"}, - {readline_cmd_t::R_PAGER_TOGGLE_SEARCH, L"pager-toggle-search"}, - {readline_cmd_t::R_BEGINNING_OF_HISTORY, L"beginning-of-history"}, - {readline_cmd_t::R_END_OF_HISTORY, L"end-of-history"}, - {readline_cmd_t::R_BACKWARD_KILL_LINE, L"backward-kill-line"}, - {readline_cmd_t::R_KILL_WHOLE_LINE, L"kill-whole-line"}, - {readline_cmd_t::R_KILL_WORD, L"kill-word"}, - {readline_cmd_t::R_KILL_BIGWORD, L"kill-bigword"}, - {readline_cmd_t::R_BACKWARD_KILL_WORD, L"backward-kill-word"}, - {readline_cmd_t::R_BACKWARD_KILL_PATH_COMPONENT, L"backward-kill-path-component"}, - {readline_cmd_t::R_BACKWARD_KILL_BIGWORD, L"backward-kill-bigword"}, - {readline_cmd_t::R_HISTORY_TOKEN_SEARCH_BACKWARD, L"history-token-search-backward"}, - {readline_cmd_t::R_HISTORY_TOKEN_SEARCH_FORWARD, L"history-token-search-forward"}, - {readline_cmd_t::R_SELF_INSERT, L"self-insert"}, - {readline_cmd_t::R_TRANSPOSE_CHARS, L"transpose-chars"}, - {readline_cmd_t::R_TRANSPOSE_WORDS, L"transpose-words"}, - {readline_cmd_t::R_UPCASE_WORD, L"upcase-word"}, - {readline_cmd_t::R_DOWNCASE_WORD, L"downcase-word"}, - {readline_cmd_t::R_CAPITALIZE_WORD, L"capitalize-word"}, - {readline_cmd_t::R_VI_ARG_DIGIT, L"vi-arg-digit"}, - {readline_cmd_t::R_VI_DELETE_TO, L"vi-delete-to"}, - {readline_cmd_t::R_EXECUTE, L"execute"}, - {readline_cmd_t::R_BEGINNING_OF_BUFFER, L"beginning-of-buffer"}, - {readline_cmd_t::R_END_OF_BUFFER, L"end-of-buffer"}, - {readline_cmd_t::R_REPAINT, L"repaint"}, - {readline_cmd_t::R_FORCE_REPAINT, L"force-repaint"}, - {readline_cmd_t::R_UP_LINE, L"up-line"}, - {readline_cmd_t::R_DOWN_LINE, L"down-line"}, - {readline_cmd_t::R_SUPPRESS_AUTOSUGGESTION, L"suppress-autosuggestion"}, - {readline_cmd_t::R_ACCEPT_AUTOSUGGESTION, L"accept-autosuggestion"}, - {readline_cmd_t::R_BEGIN_SELECTION, L"begin-selection"}, - {readline_cmd_t::R_SWAP_SELECTION_START_STOP, L"swap-selection-start-stop"}, - {readline_cmd_t::R_END_SELECTION, L"end-selection"}, - {readline_cmd_t::R_KILL_SELECTION, L"kill-selection"}, - {readline_cmd_t::R_FORWARD_JUMP, L"forward-jump"}, - {readline_cmd_t::R_BACKWARD_JUMP, L"backward-jump"}, - {readline_cmd_t::R_FORWARD_JUMP_TILL, L"forward-jump-till"}, - {readline_cmd_t::R_BACKWARD_JUMP_TILL, L"backward-jump-till"}, - {readline_cmd_t::R_REPEAT_JUMP, L"repeat-jump"}, - {readline_cmd_t::R_REVERSE_REPEAT_JUMP, L"repeat-jump-reverse"}, - {readline_cmd_t::R_AND, L"and"}, - {readline_cmd_t::R_CANCEL, L"cancel"}}; + {readline_cmd_t::beginning_of_line, L"beginning-of-line"}, + {readline_cmd_t::end_of_line, L"end-of-line"}, + {readline_cmd_t::forward_char, L"forward-char"}, + {readline_cmd_t::backward_char, L"backward-char"}, + {readline_cmd_t::forward_word, L"forward-word"}, + {readline_cmd_t::backward_word, L"backward-word"}, + {readline_cmd_t::forward_bigword, L"forward-bigword"}, + {readline_cmd_t::backward_bigword, L"backward-bigword"}, + {readline_cmd_t::history_search_backward, L"history-search-backward"}, + {readline_cmd_t::history_search_forward, L"history-search-forward"}, + {readline_cmd_t::delete_char, L"delete-char"}, + {readline_cmd_t::backward_delete_char, L"backward-delete-char"}, + {readline_cmd_t::kill_line, L"kill-line"}, + {readline_cmd_t::yank, L"yank"}, + {readline_cmd_t::yank_POP, L"yank-pop"}, + {readline_cmd_t::complete, L"complete"}, + {readline_cmd_t::complete_AND_SEARCH, L"complete-and-search"}, + {readline_cmd_t::pager_toggle_search, L"pager-toggle-search"}, + {readline_cmd_t::beginning_of_history, L"beginning-of-history"}, + {readline_cmd_t::end_of_history, L"end-of-history"}, + {readline_cmd_t::backward_kill_line, L"backward-kill-line"}, + {readline_cmd_t::kill_whole_line, L"kill-whole-line"}, + {readline_cmd_t::kill_word, L"kill-word"}, + {readline_cmd_t::kill_bigword, L"kill-bigword"}, + {readline_cmd_t::backward_kill_word, L"backward-kill-word"}, + {readline_cmd_t::backward_kill_path_component, L"backward-kill-path-component"}, + {readline_cmd_t::backward_kill_bigword, L"backward-kill-bigword"}, + {readline_cmd_t::history_token_search_backward, L"history-token-search-backward"}, + {readline_cmd_t::history_token_search_forward, L"history-token-search-forward"}, + {readline_cmd_t::self_insert, L"self-insert"}, + {readline_cmd_t::transpose_chars, L"transpose-chars"}, + {readline_cmd_t::transpose_words, L"transpose-words"}, + {readline_cmd_t::upcase_word, L"upcase-word"}, + {readline_cmd_t::downcase_word, L"downcase-word"}, + {readline_cmd_t::capitalize_word, L"capitalize-word"}, + {readline_cmd_t::vi_arg_digit, L"vi-arg-digit"}, + {readline_cmd_t::vi_delete_to, L"vi-delete-to"}, + {readline_cmd_t::execute, L"execute"}, + {readline_cmd_t::beginning_of_buffer, L"beginning-of-buffer"}, + {readline_cmd_t::end_of_buffer, L"end-of-buffer"}, + {readline_cmd_t::repaint, L"repaint"}, + {readline_cmd_t::force_repaint, L"force-repaint"}, + {readline_cmd_t::up_line, L"up-line"}, + {readline_cmd_t::down_line, L"down-line"}, + {readline_cmd_t::suppress_autosuggestion, L"suppress-autosuggestion"}, + {readline_cmd_t::accept_autosuggestion, L"accept-autosuggestion"}, + {readline_cmd_t::begin_selection, L"begin-selection"}, + {readline_cmd_t::swap_selection_start_stop, L"swap-selection-start-stop"}, + {readline_cmd_t::end_selection, L"end-selection"}, + {readline_cmd_t::kill_selection, L"kill-selection"}, + {readline_cmd_t::forward_jump, L"forward-jump"}, + {readline_cmd_t::backward_jump, L"backward-jump"}, + {readline_cmd_t::forward_jump_till, L"forward-jump-till"}, + {readline_cmd_t::backward_jump_till, L"backward-jump-till"}, + {readline_cmd_t::repeat_jump, L"repeat-jump"}, + {readline_cmd_t::reverse_repeat_jump, L"repeat-jump-reverse"}, + {readline_cmd_t::func_and, L"and"}, + {readline_cmd_t::cancel, L"cancel"}}; static_assert(sizeof(input_function_metadata) / sizeof(input_function_metadata[0]) == input_function_count, @@ -185,10 +185,10 @@ void input_set_bind_mode(const wcstring &bm) { /// Returns the arity of a given input function. static int input_function_arity(readline_cmd_t function) { switch (function) { - case readline_cmd_t::R_FORWARD_JUMP: - case readline_cmd_t::R_BACKWARD_JUMP: - case readline_cmd_t::R_FORWARD_JUMP_TILL: - case readline_cmd_t::R_BACKWARD_JUMP_TILL: + case readline_cmd_t::forward_jump: + case readline_cmd_t::backward_jump: + case readline_cmd_t::forward_jump_till: + case readline_cmd_t::backward_jump_till: return 1; default: return 0; @@ -481,12 +481,12 @@ char_event_t input_readch(bool allow_commands) { if (evt.is_readline()) { switch (evt.get_readline()) { - case readline_cmd_t::R_SELF_INSERT: { + case readline_cmd_t::self_insert: { // Issue #1595: ensure we only insert characters, not readline functions. The // common case is that this will be empty. return input_read_characters_no_readline(); } - case readline_cmd_t::R_AND: { + case readline_cmd_t::func_and: { if (input_function_status) { return input_readch(); } diff --git a/src/input_common.h b/src/input_common.h index 7bbf5bed7..27ad36d98 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -10,70 +10,70 @@ #include "maybe.h" enum class readline_cmd_t { - R_BEGINNING_OF_LINE = INPUT_COMMON_BASE, - R_END_OF_LINE, - R_FORWARD_CHAR, - R_BACKWARD_CHAR, - R_FORWARD_WORD, - R_BACKWARD_WORD, - R_FORWARD_BIGWORD, - R_BACKWARD_BIGWORD, - R_HISTORY_SEARCH_BACKWARD, - R_HISTORY_SEARCH_FORWARD, - R_DELETE_CHAR, - R_BACKWARD_DELETE_CHAR, - R_KILL_LINE, - R_YANK, - R_YANK_POP, - R_COMPLETE, - R_COMPLETE_AND_SEARCH, - R_PAGER_TOGGLE_SEARCH, - R_BEGINNING_OF_HISTORY, - R_END_OF_HISTORY, - R_BACKWARD_KILL_LINE, - R_KILL_WHOLE_LINE, - R_KILL_WORD, - R_KILL_BIGWORD, - R_BACKWARD_KILL_WORD, - R_BACKWARD_KILL_PATH_COMPONENT, - R_BACKWARD_KILL_BIGWORD, - R_HISTORY_TOKEN_SEARCH_BACKWARD, - R_HISTORY_TOKEN_SEARCH_FORWARD, - R_SELF_INSERT, - R_TRANSPOSE_CHARS, - R_TRANSPOSE_WORDS, - R_UPCASE_WORD, - R_DOWNCASE_WORD, - R_CAPITALIZE_WORD, - R_VI_ARG_DIGIT, - R_VI_DELETE_TO, - R_EXECUTE, - R_BEGINNING_OF_BUFFER, - R_END_OF_BUFFER, - R_REPAINT, - R_FORCE_REPAINT, - R_UP_LINE, - R_DOWN_LINE, - R_SUPPRESS_AUTOSUGGESTION, - R_ACCEPT_AUTOSUGGESTION, - R_BEGIN_SELECTION, - R_SWAP_SELECTION_START_STOP, - R_END_SELECTION, - R_KILL_SELECTION, - R_FORWARD_JUMP, - R_BACKWARD_JUMP, - R_FORWARD_JUMP_TILL, - R_BACKWARD_JUMP_TILL, - R_AND, - R_CANCEL, - R_REPEAT_JUMP, - R_REVERSE_REPEAT_JUMP, + beginning_of_line = INPUT_COMMON_BASE, + end_of_line, + forward_char, + backward_char, + forward_word, + backward_word, + forward_bigword, + backward_bigword, + history_search_backward, + history_search_forward, + delete_char, + backward_delete_char, + kill_line, + yank, + yank_POP, + complete, + complete_AND_SEARCH, + pager_toggle_search, + beginning_of_history, + end_of_history, + backward_kill_line, + kill_whole_line, + kill_word, + kill_bigword, + backward_kill_word, + backward_kill_path_component, + backward_kill_bigword, + history_token_search_backward, + history_token_search_forward, + self_insert, + transpose_chars, + transpose_words, + upcase_word, + downcase_word, + capitalize_word, + vi_arg_digit, + vi_delete_to, + execute, + beginning_of_buffer, + end_of_buffer, + repaint, + force_repaint, + up_line, + down_line, + suppress_autosuggestion, + accept_autosuggestion, + begin_selection, + swap_selection_start_stop, + end_selection, + kill_selection, + forward_jump, + backward_jump, + forward_jump_till, + backward_jump_till, + func_and, + cancel, + repeat_jump, + reverse_repeat_jump, }; // The range of key codes for inputrc-style keyboard functions. enum { - R_BEGIN_INPUT_FUNCTIONS = static_cast(readline_cmd_t::R_BEGINNING_OF_LINE), - R_END_INPUT_FUNCTIONS = static_cast(readline_cmd_t::R_REVERSE_REPEAT_JUMP) + 1 + R_BEGIN_INPUT_FUNCTIONS = static_cast(readline_cmd_t::beginning_of_line), + R_END_INPUT_FUNCTIONS = static_cast(readline_cmd_t::reverse_repeat_jump) + 1 }; /// Represents an event on the character input stream. diff --git a/src/reader.cpp b/src/reader.cpp index d11b72124..409e69b46 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -1034,61 +1034,61 @@ void reader_force_exit() { static bool command_ends_paging(readline_cmd_t c, bool focused_on_search_field) { using rl = readline_cmd_t; switch (c) { - case rl::R_HISTORY_SEARCH_BACKWARD: - case rl::R_HISTORY_SEARCH_FORWARD: - case rl::R_HISTORY_TOKEN_SEARCH_BACKWARD: - case rl::R_HISTORY_TOKEN_SEARCH_FORWARD: - case rl::R_ACCEPT_AUTOSUGGESTION: - case rl::R_CANCEL: { + case rl::history_search_backward: + case rl::history_search_forward: + case rl::history_token_search_backward: + case rl::history_token_search_forward: + case rl::accept_autosuggestion: + case rl::cancel: { // These commands always end paging. return true; } - case rl::R_COMPLETE: - case rl::R_COMPLETE_AND_SEARCH: - case rl::R_BACKWARD_CHAR: - case rl::R_FORWARD_CHAR: - case rl::R_UP_LINE: - case rl::R_DOWN_LINE: - case rl::R_REPAINT: - case rl::R_SUPPRESS_AUTOSUGGESTION: - case rl::R_BEGINNING_OF_HISTORY: - case rl::R_END_OF_HISTORY: { + case rl::complete: + case rl::complete_AND_SEARCH: + case rl::backward_char: + case rl::forward_char: + case rl::up_line: + case rl::down_line: + case rl::repaint: + case rl::suppress_autosuggestion: + case rl::beginning_of_history: + case rl::end_of_history: { // These commands never end paging. return false; } - case rl::R_EXECUTE: { - // R_EXECUTE does end paging, but only executes if it was not paging. So it's handled + case rl::execute: { + // execute does end paging, but only executes if it was not paging. So it's handled // specially. return false; } - case rl::R_BEGINNING_OF_LINE: - case rl::R_END_OF_LINE: - case rl::R_FORWARD_WORD: - case rl::R_BACKWARD_WORD: - case rl::R_FORWARD_BIGWORD: - case rl::R_BACKWARD_BIGWORD: - case rl::R_DELETE_CHAR: - case rl::R_BACKWARD_DELETE_CHAR: - case rl::R_KILL_LINE: - case rl::R_YANK: - case rl::R_YANK_POP: - case rl::R_BACKWARD_KILL_LINE: - case rl::R_KILL_WHOLE_LINE: - case rl::R_KILL_WORD: - case rl::R_KILL_BIGWORD: - case rl::R_BACKWARD_KILL_WORD: - case rl::R_BACKWARD_KILL_PATH_COMPONENT: - case rl::R_BACKWARD_KILL_BIGWORD: - case rl::R_SELF_INSERT: - case rl::R_TRANSPOSE_CHARS: - case rl::R_TRANSPOSE_WORDS: - case rl::R_UPCASE_WORD: - case rl::R_DOWNCASE_WORD: - case rl::R_CAPITALIZE_WORD: - case rl::R_VI_ARG_DIGIT: - case rl::R_VI_DELETE_TO: - case rl::R_BEGINNING_OF_BUFFER: - case rl::R_END_OF_BUFFER: + case rl::beginning_of_line: + case rl::end_of_line: + case rl::forward_word: + case rl::backward_word: + case rl::forward_bigword: + case rl::backward_bigword: + case rl::delete_char: + case rl::backward_delete_char: + case rl::kill_line: + case rl::yank: + case rl::yank_POP: + case rl::backward_kill_line: + case rl::kill_whole_line: + case rl::kill_word: + case rl::kill_bigword: + case rl::backward_kill_word: + case rl::backward_kill_path_component: + case rl::backward_kill_bigword: + case rl::self_insert: + case rl::transpose_chars: + case rl::transpose_words: + case rl::upcase_word: + case rl::downcase_word: + case rl::capitalize_word: + case rl::vi_arg_digit: + case rl::vi_delete_to: + case rl::beginning_of_buffer: + case rl::end_of_buffer: // These commands operate on the search field if that's where the focus is. return !focused_on_search_field; default: @@ -1099,12 +1099,12 @@ static bool command_ends_paging(readline_cmd_t c, bool focused_on_search_field) /// Indicates if the given command ends the history search. static bool command_ends_history_search(readline_cmd_t c) { switch (c) { - case readline_cmd_t::R_HISTORY_SEARCH_BACKWARD: - case readline_cmd_t::R_HISTORY_SEARCH_FORWARD: - case readline_cmd_t::R_HISTORY_TOKEN_SEARCH_BACKWARD: - case readline_cmd_t::R_HISTORY_TOKEN_SEARCH_FORWARD: - case readline_cmd_t::R_REPAINT: - case readline_cmd_t::R_FORCE_REPAINT: + case readline_cmd_t::history_search_backward: + case readline_cmd_t::history_search_forward: + case readline_cmd_t::history_token_search_backward: + case readline_cmd_t::history_token_search_forward: + case readline_cmd_t::repaint: + case readline_cmd_t::force_repaint: return false; default: return true; @@ -2491,7 +2491,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat using rl = readline_cmd_t; switch (c) { // Go to beginning of line. - case rl::R_BEGINNING_OF_LINE: { + case rl::beginning_of_line: { editable_line_t *el = active_edit_line(); while (el->position > 0 && el->text.at(el->position - 1) != L'\n') { update_buff_pos(el, el->position - 1); @@ -2500,7 +2500,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat reader_repaint_needed(); break; } - case rl::R_END_OF_LINE: { + case rl::end_of_line: { editable_line_t *el = active_edit_line(); if (el->position < el->size()) { const wchar_t *buff = el->text.c_str(); @@ -2514,22 +2514,22 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat reader_repaint_needed(); break; } - case rl::R_BEGINNING_OF_BUFFER: { + case rl::beginning_of_buffer: { update_buff_pos(&command_line, 0); reader_repaint_needed(); break; } - case rl::R_END_OF_BUFFER: { + case rl::end_of_buffer: { update_buff_pos(&command_line, command_line.size()); reader_repaint_needed(); break; } - case rl::R_CANCEL: { + case rl::cancel: { // The only thing we can cancel right now is paging, which we handled up above. break; } - case rl::R_FORCE_REPAINT: - case rl::R_REPAINT: { + case rl::force_repaint: + case rl::repaint: { if (!rls.coalescing_repaints) { rls.coalescing_repaints = true; exec_prompt(); @@ -2539,21 +2539,21 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } - case rl::R_COMPLETE: - case rl::R_COMPLETE_AND_SEARCH: { + case rl::complete: + case rl::complete_AND_SEARCH: { if (!complete_func) break; // Use the command line only; it doesn't make sense to complete in any other line. editable_line_t *el = &command_line; if (is_navigating_pager_contents() || - (!rls.comp_empty && rls.last_cmd == rl::R_COMPLETE)) { - // The user typed R_COMPLETE more than once in a row. If we are not yet fully + (!rls.comp_empty && rls.last_cmd == rl::complete)) { + // The user typed complete more than once in a row. If we are not yet fully // disclosed, then become so; otherwise cycle through our available completions. if (current_page_rendering.remaining_to_disclose > 0) { pager.set_fully_disclosed(true); reader_repaint_needed(); } else { - select_completion_in_direction(c == rl::R_COMPLETE ? direction_next + select_completion_in_direction(c == rl::complete ? direction_next : direction_prev); } } else { @@ -2613,11 +2613,11 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat cycle_command_line = el->text; cycle_cursor_pos = el->position; - bool cont_after_prefix_insertion = (c == rl::R_COMPLETE_AND_SEARCH); + bool cont_after_prefix_insertion = (c == rl::complete_AND_SEARCH); rls.comp_empty = handle_completions(rls.comp, cont_after_prefix_insertion); // Show the search field if requested and if we printed a list of completions. - if (c == rl::R_COMPLETE_AND_SEARCH && !rls.comp_empty && !pager.empty()) { + if (c == rl::complete_AND_SEARCH && !rls.comp_empty && !pager.empty()) { pager.set_search_field_shown(true); select_completion_in_direction(direction_next); reader_repaint_needed(); @@ -2625,7 +2625,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } - case rl::R_PAGER_TOGGLE_SEARCH: { + case rl::pager_toggle_search: { if (!pager.empty()) { // Toggle search, and begin navigating if we are now searching. bool sfs = pager.is_search_field_shown(); @@ -2638,7 +2638,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } - case rl::R_KILL_LINE: { + case rl::kill_line: { editable_line_t *el = active_edit_line(); const wchar_t *buff = el->text.c_str(); const wchar_t *begin = &buff[el->position]; @@ -2650,11 +2650,11 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat size_t len = end - begin; if (len) { - kill(el, begin - buff, len, KILL_APPEND, rls.last_cmd != rl::R_KILL_LINE); + kill(el, begin - buff, len, KILL_APPEND, rls.last_cmd != rl::kill_line); } break; } - case rl::R_BACKWARD_KILL_LINE: { + case rl::backward_kill_line: { editable_line_t *el = active_edit_line(); if (el->position <= 0) { break; @@ -2673,10 +2673,10 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat assert(end >= begin); size_t len = std::max(end - begin, 1); begin = end - len; - kill(el, begin - buff, len, KILL_PREPEND, rls.last_cmd != rl::R_BACKWARD_KILL_LINE); + kill(el, begin - buff, len, KILL_PREPEND, rls.last_cmd != rl::backward_kill_line); break; } - case rl::R_KILL_WHOLE_LINE: { + case rl::kill_whole_line: { // We match the emacs behavior here: "kills the entire line including the following // newline". editable_line_t *el = active_edit_line(); @@ -2702,17 +2702,17 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat assert(end >= begin); if (end > begin) { - kill(el, begin, end - begin, KILL_APPEND, rls.last_cmd != rl::R_KILL_WHOLE_LINE); + kill(el, begin, end - begin, KILL_APPEND, rls.last_cmd != rl::kill_whole_line); } break; } - case rl::R_YANK: { + case rl::yank: { wcstring yank_str = kill_yank(); insert_string(active_edit_line(), yank_str); rls.yank_len = yank_str.size(); break; } - case rl::R_YANK_POP: { + case rl::yank_POP: { if (rls.yank_len) { for (size_t i = 0; i < rls.yank_len; i++) remove_backward(); @@ -2722,11 +2722,11 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } - case rl::R_BACKWARD_DELETE_CHAR: { + case rl::backward_delete_char: { remove_backward(); break; } - case rl::R_DELETE_CHAR: { + case rl::delete_char: { // Remove the current character in the character buffer and on the screen using // syntax highlighting, etc. editable_line_t *el = active_edit_line(); @@ -2738,7 +2738,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } // Evaluate. If the current command is unfinished, or if the charater is escaped // using a backslash, insert a newline. - case rl::R_EXECUTE: { + case rl::execute: { // If the user hits return while navigating the pager, it only clears the pager. if (is_navigating_pager_contents()) { clear_pager(); @@ -2821,14 +2821,14 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat break; } - case rl::R_HISTORY_SEARCH_BACKWARD: - case rl::R_HISTORY_TOKEN_SEARCH_BACKWARD: - case rl::R_HISTORY_SEARCH_FORWARD: - case rl::R_HISTORY_TOKEN_SEARCH_FORWARD: { + case rl::history_search_backward: + case rl::history_token_search_backward: + case rl::history_search_forward: + case rl::history_token_search_forward: { if (history_search.is_at_end()) { const editable_line_t *el = &command_line; - bool by_token = (c == rl::R_HISTORY_TOKEN_SEARCH_BACKWARD) || - (c == rl::R_HISTORY_TOKEN_SEARCH_FORWARD); + bool by_token = (c == rl::history_token_search_backward) || + (c == rl::history_token_search_forward); if (by_token) { // Searching by token. const wchar_t *begin, *end; @@ -2855,7 +2855,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } if (history_search.active()) { history_search_direction_t dir = - (c == rl::R_HISTORY_SEARCH_BACKWARD || c == rl::R_HISTORY_TOKEN_SEARCH_BACKWARD) + (c == rl::history_search_backward || c == rl::history_token_search_backward) ? history_search_direction_t::backward : history_search_direction_t::forward; history_search.move_in_direction(dir); @@ -2863,7 +2863,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } - case rl::R_BACKWARD_CHAR: { + case rl::backward_char: { editable_line_t *el = active_edit_line(); if (is_navigating_pager_contents()) { select_completion_in_direction(direction_west); @@ -2873,7 +2873,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } - case rl::R_FORWARD_CHAR: { + case rl::forward_char: { editable_line_t *el = active_edit_line(); if (is_navigating_pager_contents()) { select_completion_in_direction(direction_east); @@ -2885,42 +2885,42 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } - case rl::R_BACKWARD_KILL_WORD: - case rl::R_BACKWARD_KILL_PATH_COMPONENT: - case rl::R_BACKWARD_KILL_BIGWORD: { + case rl::backward_kill_word: + case rl::backward_kill_path_component: + case rl::backward_kill_bigword: { move_word_style_t style = - (c == rl::R_BACKWARD_KILL_BIGWORD + (c == rl::backward_kill_bigword ? move_word_style_whitespace - : c == rl::R_BACKWARD_KILL_PATH_COMPONENT ? move_word_style_path_components + : c == rl::backward_kill_path_component ? move_word_style_path_components : move_word_style_punctuation); // Is this the same killring item as the last kill? - bool newv = (rls.last_cmd != rl::R_BACKWARD_KILL_WORD && - rls.last_cmd != rl::R_BACKWARD_KILL_PATH_COMPONENT && - rls.last_cmd != rl::R_BACKWARD_KILL_BIGWORD); + bool newv = (rls.last_cmd != rl::backward_kill_word && + rls.last_cmd != rl::backward_kill_path_component && + rls.last_cmd != rl::backward_kill_bigword); move_word(active_edit_line(), MOVE_DIR_LEFT, true /* erase */, style, newv); break; } - case rl::R_KILL_WORD: - case rl::R_KILL_BIGWORD: { + case rl::kill_word: + case rl::kill_bigword: { // The "bigword" functions differ only in that they move to the next whitespace, not // punctuation. auto move_style = - (c == rl::R_KILL_WORD) ? move_word_style_punctuation : move_word_style_whitespace; + (c == rl::kill_word) ? move_word_style_punctuation : move_word_style_whitespace; move_word(active_edit_line(), MOVE_DIR_RIGHT, true /* erase */, move_style, rls.last_cmd != c /* same kill item if same movement */); break; } - case rl::R_BACKWARD_WORD: - case rl::R_BACKWARD_BIGWORD: { - auto move_style = (c == rl::R_BACKWARD_WORD) ? move_word_style_punctuation + case rl::backward_word: + case rl::backward_bigword: { + auto move_style = (c == rl::backward_word) ? move_word_style_punctuation : move_word_style_whitespace; move_word(active_edit_line(), MOVE_DIR_LEFT, false /* do not erase */, move_style, false); break; } - case rl::R_FORWARD_WORD: - case rl::R_FORWARD_BIGWORD: { - auto move_style = (c == rl::R_FORWARD_WORD) ? move_word_style_punctuation + case rl::forward_word: + case rl::forward_bigword: { + auto move_style = (c == rl::forward_word) ? move_word_style_punctuation : move_word_style_whitespace; editable_line_t *el = active_edit_line(); if (el->position < el->size()) { @@ -2930,9 +2930,9 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } - case rl::R_BEGINNING_OF_HISTORY: - case rl::R_END_OF_HISTORY: { - bool up = (c == rl::R_BEGINNING_OF_HISTORY); + case rl::beginning_of_history: + case rl::end_of_history: { + bool up = (c == rl::beginning_of_history); if (is_navigating_pager_contents()) { select_completion_in_direction(up ? direction_page_north : direction_page_south); } else { @@ -2945,12 +2945,12 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } - case rl::R_UP_LINE: - case rl::R_DOWN_LINE: { + case rl::up_line: + case rl::down_line: { if (is_navigating_pager_contents()) { // We are already navigating pager contents. selection_direction_t direction; - if (c == rl::R_DOWN_LINE) { + if (c == rl::down_line) { // Down arrow is always south. direction = direction_south; } else if (selection_is_at_top()) { @@ -2965,7 +2965,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat select_completion_in_direction(direction); } else if (!pager.empty()) { // We pressed a direction with a non-empty pager, begin navigation. - select_completion_in_direction(c == rl::R_DOWN_LINE ? direction_south + select_completion_in_direction(c == rl::down_line ? direction_south : direction_north); } else { // Not navigating the pager contents. @@ -2973,7 +2973,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat int line_old = parse_util_get_line_from_offset(el->text, el->position); int line_new; - if (c == rl::R_UP_LINE) + if (c == rl::up_line) line_new = line_old - 1; else line_new = line_old + 1; @@ -3007,17 +3007,17 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } - case rl::R_SUPPRESS_AUTOSUGGESTION: { + case rl::suppress_autosuggestion: { suppress_autosuggestion = true; autosuggestion.clear(); reader_repaint_needed(); break; } - case rl::R_ACCEPT_AUTOSUGGESTION: { + case rl::accept_autosuggestion: { accept_autosuggestion(true); break; } - case rl::R_TRANSPOSE_CHARS: { + case rl::transpose_chars: { editable_line_t *el = active_edit_line(); if (el->size() < 2) { break; @@ -3037,7 +3037,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } - case rl::R_TRANSPOSE_WORDS: { + case rl::transpose_words: { editable_line_t *el = active_edit_line(); size_t len = el->size(); const wchar_t *buff = el->text.c_str(); @@ -3077,9 +3077,9 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } - case rl::R_UPCASE_WORD: - case rl::R_DOWNCASE_WORD: - case rl::R_CAPITALIZE_WORD: { + case rl::upcase_word: + case rl::downcase_word: + case rl::capitalize_word: { editable_line_t *el = active_edit_line(); // For capitalize_word, whether we've capitalized a character so far. bool capitalized_first = false; @@ -3093,10 +3093,10 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // We always change the case; this decides whether we go uppercase (true) or // lowercase (false). bool make_uppercase; - if (c == rl::R_CAPITALIZE_WORD) + if (c == rl::capitalize_word) make_uppercase = !capitalized_first && iswalnum(chr); else - make_uppercase = (c == rl::R_UPCASE_WORD); + make_uppercase = (c == rl::upcase_word); // Apply the operation and then record what we did. if (make_uppercase) @@ -3112,11 +3112,11 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat reader_repaint_needed(); break; } - case rl::R_BEGIN_SELECTION: - case rl::R_END_SELECTION: { + case rl::begin_selection: + case rl::end_selection: { sel_start_pos = command_line.position; sel_stop_pos = command_line.position; - if (c == rl::R_BEGIN_SELECTION) { + if (c == rl::begin_selection) { sel_active = true; sel_begin_pos = command_line.position; } else { @@ -3125,7 +3125,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat break; } - case rl::R_SWAP_SELECTION_START_STOP: { + case rl::swap_selection_start_stop: { if (!sel_active) break; size_t tmp = sel_begin_pos; sel_begin_pos = command_line.position; @@ -3134,22 +3134,22 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat update_buff_pos(el, tmp); break; } - case rl::R_KILL_SELECTION: { - bool newv = (rls.last_cmd != rl::R_KILL_SELECTION); + case rl::kill_selection: { + bool newv = (rls.last_cmd != rl::kill_selection); size_t start, len; if (reader_get_selection(&start, &len)) { kill(&command_line, start, len, KILL_APPEND, newv); } break; } - case rl::R_FORWARD_JUMP: - case rl::R_BACKWARD_JUMP: - case rl::R_FORWARD_JUMP_TILL: - case rl::R_BACKWARD_JUMP_TILL: { - auto direction = (c == rl::R_FORWARD_JUMP || c == rl::R_FORWARD_JUMP_TILL) + case rl::forward_jump: + case rl::backward_jump: + case rl::forward_jump_till: + case rl::backward_jump_till: { + auto direction = (c == rl::forward_jump || c == rl::forward_jump_till) ? jump_direction_t::forward : jump_direction_t::backward; - auto precision = (c == rl::R_FORWARD_JUMP || c == rl::R_BACKWARD_JUMP) + auto precision = (c == rl::forward_jump || c == rl::backward_jump) ? jump_precision_t::to : jump_precision_t::till; editable_line_t *el = active_edit_line(); @@ -3160,7 +3160,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat reader_repaint_needed(); break; } - case rl::R_REPEAT_JUMP: { + case rl::repeat_jump: { editable_line_t *el = active_edit_line(); bool success = false; @@ -3172,7 +3172,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat reader_repaint_needed(); break; } - case rl::R_REVERSE_REPEAT_JUMP: { + case rl::reverse_repeat_jump: { editable_line_t *el = active_edit_line(); bool success = false; jump_direction_t original_dir, dir; @@ -3196,14 +3196,14 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } // Some commands should have been handled internally by input_readch(). - case rl::R_SELF_INSERT: { + case rl::self_insert: { DIE("self-insert should have been handled by input_readch"); } - case rl::R_AND: { + case rl::func_and: { DIE("self-insert should have been handled by input_readch"); } - case rl::R_VI_ARG_DIGIT: - case rl::R_VI_DELETE_TO: { + case rl::vi_arg_digit: + case rl::vi_delete_to: { // TODO: what needs to happen with these? break; } @@ -3278,16 +3278,16 @@ maybe_t reader_data_t::readline(int nchars_or_0) { assert((event_needing_handling->is_char() || event_needing_handling->is_readline()) && "Should have a char or readline"); - if (rls.last_cmd != rl::R_YANK && rls.last_cmd != rl::R_YANK_POP) { + if (rls.last_cmd != rl::yank && rls.last_cmd != rl::yank_POP) { rls.yank_len = 0; } if (event_needing_handling->is_readline()) { readline_cmd_t readline_cmd = event_needing_handling->get_readline(); // If we get something other than a repaint, then stop coalescing them. - if (readline_cmd != rl::R_REPAINT) rls.coalescing_repaints = false; + if (readline_cmd != rl::repaint) rls.coalescing_repaints = false; - if (readline_cmd == rl::R_CANCEL && is_navigating_pager_contents()) { + if (readline_cmd == rl::cancel && is_navigating_pager_contents()) { set_command_line_and_position(&command_line, cycle_command_line, cycle_cursor_pos); } From 71f26a68137675c79e7caada6c5403e5a729f00b Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 23 Mar 2019 18:07:32 -0700 Subject: [PATCH 0142/1732] Remove INPUT_COMMON_BASE We no longer store readline commands as characters, so there's no need to reserve character space for them. --- src/common.cpp | 3 +-- src/common.h | 2 -- src/input_common.h | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/common.cpp b/src/common.cpp index b50bcac37..d097f5844 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -2382,8 +2382,7 @@ char **make_null_terminated_array(const std::vector &lst) { // TODO: Actually implement the replacement as documented above. bool fish_reserved_codepoint(wchar_t c) { return (c >= RESERVED_CHAR_BASE && c < RESERVED_CHAR_END) || - (c >= ENCODE_DIRECT_BASE && c < ENCODE_DIRECT_END) || - (c >= INPUT_COMMON_BASE && c < INPUT_COMMON_END); + (c >= ENCODE_DIRECT_BASE && c < ENCODE_DIRECT_END); } /// Reopen stdin, stdout and/or stderr on /dev/null. This is invoked when we find that our tty has diff --git a/src/common.h b/src/common.h index e84edaa50..cf6963349 100644 --- a/src/common.h +++ b/src/common.h @@ -87,8 +87,6 @@ typedef std::vector wcstring_list_t; // on Mac OS X. See http://www.unicode.org/faq/private_use.html. #define ENCODE_DIRECT_BASE (wchar_t)0xF600 #define ENCODE_DIRECT_END (ENCODE_DIRECT_BASE + 256) -#define INPUT_COMMON_BASE (wchar_t)0xF700 -#define INPUT_COMMON_END (INPUT_COMMON_BASE + 64) // NAME_MAX is not defined on Solaris #if !defined(NAME_MAX) diff --git a/src/input_common.h b/src/input_common.h index 27ad36d98..7489f0e96 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -10,7 +10,7 @@ #include "maybe.h" enum class readline_cmd_t { - beginning_of_line = INPUT_COMMON_BASE, + beginning_of_line, end_of_line, forward_char, backward_char, From 5afd1336e860992c6d440264ae1067c06126f9db Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 24 Mar 2019 10:46:42 +0100 Subject: [PATCH 0143/1732] functions/fish_npm_helper: Use physical pwd This searched for package.json in any parent, so just like finding .git and .hg directories it _needs_ to use the physical pwd because that's what git/hg/yarn use. In general, if you do _any_ logic on $PWD, it should be the physical path. Logical $PWD is basically only good for display and cd-ing around with symlinks. [ci skip] --- share/functions/fish_npm_helper.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/functions/fish_npm_helper.fish b/share/functions/fish_npm_helper.fish index 3ba7872b9..810154c01 100644 --- a/share/functions/fish_npm_helper.fish +++ b/share/functions/fish_npm_helper.fish @@ -38,7 +38,7 @@ function __yarn_filtered_list_packages end function __yarn_find_package_json - set parents (__fish_parent_directories (pwd)) + set parents (__fish_parent_directories (pwd -P)) for p in $parents if test -f "$p/package.json" From 22d93826468bafb47103b520cf20a6bd97d8c4a8 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 24 Mar 2019 16:59:00 +0100 Subject: [PATCH 0144/1732] completions/service: Remove useless helper function [ci skip] --- share/completions/service.fish | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/share/completions/service.fish b/share/completions/service.fish index 6cee6e241..06265c44f 100644 --- a/share/completions/service.fish +++ b/share/completions/service.fish @@ -1,22 +1,13 @@ # First argument is the names of the service, i.e. a file in /etc/init.d complete -c service -n "__fish_is_first_token" -xa "(__fish_print_service_names)" -d "Service" -set -l service_commands -function __fish_complete_static_service_actions - #The second argument is what action to take with the service - complete -c service -n "not __fish_is_first_token" -xa "$argv" -end - # as found in __fish_print_service_names.fish if test -d /run/systemd/system # Systemd systems - set service_commands start stop restart status enable disable - __fish_complete_static_service_actions $service_commands + complete -c service -n "not __fish_is_first_token" -xa "start stop restart status enable disable" else if type -f rc-service 2>/dev/null # OpenRC (Gentoo) - set service_commands start stop restart - __fish_complete_static_service_actions $service_commands + complete -c service -n "not __fish_is_first_token" -xa "start stop restart" else if test -d /etc/init.d # SysV on Debian and other linuxen - set service_commands start stop "--full-restart" - __fish_complete_static_service_actions $service_commands + complete -c service -n "not __fish_is_first_token" -xa "start stop --full-restart" else # FreeBSD # Use the output of `service -v foo` to retrieve the list of service-specific verbs complete -c service -n "not __fish_is_first_token" -xa "(__fish_complete_freebsd_service_actions)" From 77e71cfcb194619be09c806f66cce04082ab8fc0 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 24 Mar 2019 17:12:36 +0100 Subject: [PATCH 0145/1732] completions/git: Handle AM files Fixes #5763. [ci skip] --- share/completions/git.fish | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/share/completions/git.fish b/share/completions/git.fish index 98e0c30a7..6293142e7 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -190,6 +190,15 @@ function __fish_git_files set -ql added and set file "$line[9..-1]" and set desc $added_desc + case "1 AM*" + # Added files with additional modifications + if set -ql added + set file "$line[9..-1]" + set desc $added_desc + else if set -ql modified + set file "$line[9..-1]" + set desc $modified_desc + end case '1 .M*' # Modified # From the docs: "Ordinary changed entries have the following format:" From 295286b184c63b8a1ea91998c2e484122cc39ca2 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 24 Mar 2019 19:44:45 +0100 Subject: [PATCH 0146/1732] docs: Fix remaining "\subsection" markup See #5696. [ci skip] --- sphinx_doc_src/cmds/fish_vcs_prompt.rst | 3 ++- sphinx_doc_src/cmds/source.rst | 3 ++- sphinx_doc_src/cmds/string.rst | 9 ++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/sphinx_doc_src/cmds/fish_vcs_prompt.rst b/sphinx_doc_src/cmds/fish_vcs_prompt.rst index 716c26d98..92a7d72ab 100644 --- a/sphinx_doc_src/cmds/fish_vcs_prompt.rst +++ b/sphinx_doc_src/cmds/fish_vcs_prompt.rst @@ -16,7 +16,8 @@ If a vcs isn't installed, the respective function does nothing. For more information, see their documentation. -\subsection fish_vcs_prompt-example Example +Example +------- A simple prompt that displays vcs info:: diff --git a/sphinx_doc_src/cmds/source.rst b/sphinx_doc_src/cmds/source.rst index 33b5dc0c3..21fd13b2b 100644 --- a/sphinx_doc_src/cmds/source.rst +++ b/sphinx_doc_src/cmds/source.rst @@ -31,6 +31,7 @@ Example # Causes fish to re-read its initialization file. -\subsection Caveats +Caveats +------- In fish versions prior to 2.3.0 the ``$argv`` variable would have a single element (the name of the sourced file) if no arguments are present. Otherwise it would contain arguments without the name of the sourced file. That behavior was very confusing and unlike other shells such as bash and zsh. diff --git a/sphinx_doc_src/cmds/string.rst b/sphinx_doc_src/cmds/string.rst index fafb3b013..99e7970d8 100644 --- a/sphinx_doc_src/cmds/string.rst +++ b/sphinx_doc_src/cmds/string.rst @@ -59,7 +59,8 @@ The following subcommands are available. ``string join`` joins its STRING arguments into a single string separated by SEP, which can be an empty string. Exit status: 0 if at least one join was performed, or 1 otherwise. -\subsection string-join0 "join0" subcommand +"join0" subcommand +------------------ ``string join`` joins its STRING arguments into a single string separated by the zero byte (NUL), and adds a trailing NUL. This is most useful in conjunction with tools that accept NUL-delimited input, such as ``sort -z``. Exit status: 0 if at least one join was performed, or 1 otherwise. @@ -113,7 +114,8 @@ Exit status: 0 if at least one replacement was performed, or 1 otherwise. See also ``read --delimiter``. -\subsection string-split0 "split0" subcommand +"split0" subcommand +------------------- ``string split0`` splits each STRING on the zero byte (NUL). Options are the same as ``string split`` except that no separator is given. @@ -344,7 +346,8 @@ Match Regex Examples 0xBadC0de -\subsection string-example-split0 NUL Delimited Examples +NUL Delimited Examples +---------------------- From 8837d17910ab9fbda486643aa268c977ab7935c8 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 24 Mar 2019 19:50:51 +0100 Subject: [PATCH 0147/1732] docs: Remove weird Commands subsection This included another copy of the TOC in the middle of the index page and called it "Commands"? See #5696. cc @ridiculousfish [ci skip] --- sphinx_doc_src/index.rst | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index 349aee5e1..8bd8f19d3 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -513,19 +513,6 @@ Help Help on a specific builtin can also be obtained with the ``-h`` parameter. For instance, to obtain help on the ``fg`` builtin, either type ``fg -h`` or ``help fg``. -Commands -======== - -.. toctree:: - :maxdepth: 1 - - commands - design - tutorial - faq - license - - Autosuggestions =============== From 848d538f085ced0ab0fb80768d43bd0c9305bc2f Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 24 Mar 2019 19:59:23 +0100 Subject: [PATCH 0148/1732] docs: Replace @key markup with :kbd: The best I could find. It doesn't currently appear to render in the html, but it's better than showing `@key{thing}`. --- sphinx_doc_src/cmds/abbr.rst | 2 +- sphinx_doc_src/cmds/bind.rst | 8 +-- sphinx_doc_src/cmds/cdh.rst | 2 +- sphinx_doc_src/cmds/funced.rst | 2 +- sphinx_doc_src/faq.rst | 6 +- sphinx_doc_src/index.rst | 112 ++++++++++++++++----------------- sphinx_doc_src/tutorial.rst | 14 ++--- 7 files changed, 73 insertions(+), 73 deletions(-) diff --git a/sphinx_doc_src/cmds/abbr.rst b/sphinx_doc_src/cmds/abbr.rst index a4bcad137..6b30925d2 100644 --- a/sphinx_doc_src/cmds/abbr.rst +++ b/sphinx_doc_src/cmds/abbr.rst @@ -16,7 +16,7 @@ Description ``abbr`` manages abbreviations - user-defined words that are replaced with longer phrases after they are entered. -For example, a frequently-run command like ``git checkout`` can be abbreviated to ``gco``. After entering ``gco`` and pressing @key{Space} or @key{Enter}, the full text ``git checkout`` will appear in the command line. +For example, a frequently-run command like ``git checkout`` can be abbreviated to ``gco``. After entering ``gco`` and pressing :kbd:`Space` or :kbd:`Enter`, the full text ``git checkout`` will appear in the command line. Options ------- diff --git a/sphinx_doc_src/cmds/bind.rst b/sphinx_doc_src/cmds/bind.rst index 76c182793..1d9c6ddc1 100644 --- a/sphinx_doc_src/cmds/bind.rst +++ b/sphinx_doc_src/cmds/bind.rst @@ -21,7 +21,7 @@ Description ``bind`` adds a binding for the specified key sequence to the specified command. -SEQUENCE is the character sequence to bind to. These should be written as fish escape sequences. For example, because pressing the Alt key and another character sends that character prefixed with an escape character, Alt-based key bindings can be written using the ``\e`` escape. For example, @key{Alt,w} can be written as ``\ew``. The control character can be written in much the same way using the ``\c`` escape, for example @key{Control,X} (^X) can be written as ``\cx``. Note that Alt-based key bindings are case sensitive and Control-based key bindings are not. This is a constraint of text-based terminals, not ``fish``. +SEQUENCE is the character sequence to bind to. These should be written as fish escape sequences. For example, because pressing the Alt key and another character sends that character prefixed with an escape character, Alt-based key bindings can be written using the ``\e`` escape. For example, :kbd:`Alt+w` can be written as ``\ew``. The control character can be written in much the same way using the ``\c`` escape, for example :kbd:`Control+X` (^X) can be written as ``\cx``. Note that Alt-based key bindings are case sensitive and Control-based key bindings are not. This is a constraint of text-based terminals, not ``fish``. The default key binding can be set by specifying a ``SEQUENCE`` of the empty string (that is, ``''`` ). It will be used whenever no other binding matches. For most key bindings, it makes sense to use the ``self-insert`` function (i.e. ``````bind '' self-insert``````) as the default keybinding. This will insert any keystrokes not specifically bound to into the editor. Non- printable characters are ignored by the editor, so this will not result in control sequences being printable. @@ -155,7 +155,7 @@ Examples bind \\cd 'exit' -Causes ``fish`` to exit when @key{Control,D} is pressed. +Causes ``fish`` to exit when :kbd:`Control+D` is pressed. @@ -163,7 +163,7 @@ Causes ``fish`` to exit when @key{Control,D} is pressed. bind -k ppage history-search-backward -Performs a history search when the @key{Page Up} key is pressed. +Performs a history search when the :kbd:`Page Up` key is pressed. @@ -172,7 +172,7 @@ Performs a history search when the @key{Page Up} key is pressed. set -g fish_key_bindings fish_vi_key_bindings bind -M insert \\cc kill-whole-line force-repaint -Turns on Vi key bindings and rebinds @key{Control,C} to clear the input line. +Turns on Vi key bindings and rebinds :kbd:`Control+C` to clear the input line. Special Case: The escape Character diff --git a/sphinx_doc_src/cmds/cdh.rst b/sphinx_doc_src/cmds/cdh.rst index a29a53a9d..d013107f1 100644 --- a/sphinx_doc_src/cmds/cdh.rst +++ b/sphinx_doc_src/cmds/cdh.rst @@ -11,7 +11,7 @@ cdh [ directory ] Description ----------- -``cdh`` with no arguments presents a list of recently visited directories. You can then select one of the entries by letter or number. You can also press @key{tab} to use the completion pager to select an item from the list. If you give it a single argument it is equivalent to ``cd directory``. +``cdh`` with no arguments presents a list of recently visited directories. You can then select one of the entries by letter or number. You can also press :kbd:`tab` to use the completion pager to select an item from the list. If you give it a single argument it is equivalent to ``cd directory``. Note that the ``cd`` command limits directory history to the 25 most recently visited directories. The history is stored in the ``$dirprev`` and ``$dirnext`` variables which this command manipulates. If you make those universal variables your ``cd`` history is shared among all fish instances. diff --git a/sphinx_doc_src/cmds/funced.rst b/sphinx_doc_src/cmds/funced.rst index 5c9bfe5ad..2f33c6906 100644 --- a/sphinx_doc_src/cmds/funced.rst +++ b/sphinx_doc_src/cmds/funced.rst @@ -12,7 +12,7 @@ Description ``funced`` provides an interface to edit the definition of the function ``NAME``. -If the ``$VISUAL`` environment variable is set, it will be used as the program to edit the function. If ``$VISUAL`` is unset but ``$EDITOR`` is set, that will be used. Otherwise, a built-in editor will be used. Note that to enter a literal newline using the built-in editor you should press @key{Alt,Enter}. Pressing @key{Enter} signals that you are done editing the function. This does not apply to an external editor like emacs or vim. +If the ``$VISUAL`` environment variable is set, it will be used as the program to edit the function. If ``$VISUAL`` is unset but ``$EDITOR`` is set, that will be used. Otherwise, a built-in editor will be used. Note that to enter a literal newline using the built-in editor you should press :kbd:`Alt+Enter`. Pressing :kbd:`Enter` signals that you are done editing the function. This does not apply to an external editor like emacs or vim. If there is no function called ``NAME`` a new function will be created with the specified name diff --git a/sphinx_doc_src/faq.rst b/sphinx_doc_src/faq.rst index 7f5871b49..143ba7063 100644 --- a/sphinx_doc_src/faq.rst +++ b/sphinx_doc_src/faq.rst @@ -235,11 +235,11 @@ Fish history recall is very simple yet effective: - If the line you want is far back in the history, type any part of the line and then press Up one or more times. This will constrain the recall to lines that include this text, and you will get to the line you want much faster. This replaces "!vi", "!?bar.c" and the like. -- @key{Alt,↑,Up} recalls individual arguments, starting from the last argument in the last line executed. A single press replaces "!$", later presses replace "!!:4" and the like. +- :kbd:`Alt+↑,Up` recalls individual arguments, starting from the last argument in the last line executed. A single press replaces "!$", later presses replace "!!:4" and the like. - - If the argument you want is far back in history (e.g. 2 lines back - that's a lot of words!), type any part of it and then press @key{Alt,↑,Up}. This will show only arguments containing that part and you will get what you want much faster. Try it out, this is very convenient! + - If the argument you want is far back in history (e.g. 2 lines back - that's a lot of words!), type any part of it and then press :kbd:`Alt+↑,Up`. This will show only arguments containing that part and you will get what you want much faster. Try it out, this is very convenient! - - If you want to reuse several arguments from the same line ("!!:3*" and the like), consider recalling the whole line and removing what you don't need (@key{Alt,D} and @key{Alt,Backspace} are your friends). + - If you want to reuse several arguments from the same line ("!!:3*" and the like), consider recalling the whole line and removing what you don't need (:kbd:`Alt+D` and :kbd:`Alt+Backspace` are your friends). See documentation for more details about line editing in fish. diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index 8bd8f19d3..87f2e43c5 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -398,7 +398,7 @@ will start the emacs text editor in the background. Job control ----------- -Most programs allow you to suspend the program's execution and return control to ``fish`` by pressing @key{Control,Z} (also referred to as ``^Z``). Once back at the ``fish`` commandline, you can start other programs and do anything you want. If you then want you can go back to the suspended command by using the `fg `_ (foreground) command. +Most programs allow you to suspend the program's execution and return control to ``fish`` by pressing :kbd:`Control+Z` (also referred to as ``^Z``). Once back at the ``fish`` commandline, you can start other programs and do anything you want. If you then want you can go back to the suspended command by using the `fg `_ (foreground) command. If you instead want to put a suspended job into the background, use the `bg `_ command. @@ -518,7 +518,7 @@ Autosuggestions fish suggests commands as you type, based on command history, completions, and valid file paths. As you type commands, you will see a suggestion offered after the cursor, in a muted gray color (which can be changed with the ``fish_color_autosuggestion`` variable). -To accept the autosuggestion (replacing the command line contents), press right arrow or @key{Control,F}. To accept the first suggested word, press @key{Alt,→,Right} or @key{Alt,F}. If the autosuggestion is not what you want, just ignore it: it won't execute unless you accept it. +To accept the autosuggestion (replacing the command line contents), press right arrow or :kbd:`Control+F`. To accept the first suggested word, press :kbd:`Alt+→,Right` or :kbd:`Alt+F`. If the autosuggestion is not what you want, just ignore it: it won't execute unless you accept it. Autosuggestions are a powerful way to quickly summon frequently entered commands, by typing the first few characters. They are also an efficient technique for navigating through directory hierarchies. @@ -1352,64 +1352,64 @@ Shared bindings Some bindings are shared between emacs- and vi-mode because they aren't text editing bindings or because what Vi/Vim does for a particular key doesn't make sense for a shell. -- @key{Tab} `completes <#completion>`_ the current token. @key{Shift, Tab} completes the current token and starts the pager's search mode. +- :kbd:`Tab` `completes <#completion>`_ the current token. :kbd:`Shift, Tab` completes the current token and starts the pager's search mode. -- @key{Alt,←,Left} and @key{Alt,→,Right} move the cursor one word left or right (to the next space or punctuation mark), or moves forward/backward in the directory history if the command line is empty. If the cursor is already at the end of the line, and an autosuggestion is available, @key{Alt,→,Right} (or @key{Alt,F}) accepts the first word in the suggestion. +- :kbd:`Alt+←,Left` and :kbd:`Alt+→,Right` move the cursor one word left or right (to the next space or punctuation mark), or moves forward/backward in the directory history if the command line is empty. If the cursor is already at the end of the line, and an autosuggestion is available, :kbd:`Alt+→,Right` (or :kbd:`Alt+F`) accepts the first word in the suggestion. -- @key{Shift,←,Left} and @key{Shift,→,Right} move the cursor one word left or right, without stopping on punctuation. +- :kbd:`Shift,←,Left` and :kbd:`Shift,→,Right` move the cursor one word left or right, without stopping on punctuation. -- @cursor_key{↑,Up} and @cursor_key{↓,Down} (or @key{Control,P} and @key{Control,N} for emacs aficionados) search the command history for the previous/next command containing the string that was specified on the commandline before the search was started. If the commandline was empty when the search started, all commands match. See the `history <#history>`_ section for more information on history searching. +- @cursor_key{↑,Up} and @cursor_key{↓,Down} (or :kbd:`Control+P` and :kbd:`Control+N` for emacs aficionados) search the command history for the previous/next command containing the string that was specified on the commandline before the search was started. If the commandline was empty when the search started, all commands match. See the `history <#history>`_ section for more information on history searching. -- @key{Alt,↑,Up} and @key{Alt,↓,Down} search the command history for the previous/next token containing the token under the cursor before the search was started. If the commandline was not on a token when the search started, all tokens match. See the `history <#history>`_ section for more information on history searching. +- :kbd:`Alt+↑,Up` and :kbd:`Alt+↓,Down` search the command history for the previous/next token containing the token under the cursor before the search was started. If the commandline was not on a token when the search started, all tokens match. See the `history <#history>`_ section for more information on history searching. -- @key{Control,C} cancels the entire line. +- :kbd:`Control+C` cancels the entire line. -- @key{Control,D} delete one character to the right of the cursor. If the command line is empty, @key{Control,D} will exit fish. +- :kbd:`Control+D` delete one character to the right of the cursor. If the command line is empty, :kbd:`Control+D` will exit fish. -- @key{Control,U} moves contents from the beginning of line to the cursor to the `killring <#killring>`_. +- :kbd:`Control+U` moves contents from the beginning of line to the cursor to the `killring <#killring>`_. -- @key{Control,L} clears and repaints the screen. +- :kbd:`Control+L` clears and repaints the screen. -- @key{Control,W} moves the previous path component (everything up to the previous "/") to the `killring <#killring>`_. +- :kbd:`Control+W` moves the previous path component (everything up to the previous "/") to the `killring <#killring>`_. -- @key{Control,X} copies the current buffer to the system's clipboard, @key{Control,V} inserts the clipboard contents. +- :kbd:`Control+X` copies the current buffer to the system's clipboard, :kbd:`Control+V` inserts the clipboard contents. -- @key{Alt,d} moves the next word to the `killring <#killring>`_. +- :kbd:`Alt+d` moves the next word to the `killring <#killring>`_. -- @key{Alt,h} (or @key{F1}) shows the manual page for the current command, if one exists. +- :kbd:`Alt+h` (or :kbd:`F1`) shows the manual page for the current command, if one exists. -- @key{Alt,l} lists the contents of the current directory, unless the cursor is over a directory argument, in which case the contents of that directory will be listed. +- :kbd:`Alt+l` lists the contents of the current directory, unless the cursor is over a directory argument, in which case the contents of that directory will be listed. -- @key{Alt,p} adds the string '``| less;``' to the end of the job under the cursor. The result is that the output of the command will be paged. +- :kbd:`Alt+p` adds the string '``| less;``' to the end of the job under the cursor. The result is that the output of the command will be paged. -- @key{Alt,w} prints a short description of the command under the cursor. +- :kbd:`Alt+w` prints a short description of the command under the cursor. -- @key{Alt,e} edit the current command line in an external editor. The editor is chosen from the first available of the ``$VISUAL`` or ``$EDITOR`` variables. +- :kbd:`Alt+e` edit the current command line in an external editor. The editor is chosen from the first available of the ``$VISUAL`` or ``$EDITOR`` variables. -- @key{Alt,v} Same as @key{Alt,e}. +- :kbd:`Alt+v` Same as :kbd:`Alt+e`. .. _emacs-mode: Emacs mode commands ------------------- -- @key{Home} or @key{Control,A} moves the cursor to the beginning of the line. +- :kbd:`Home` or :kbd:`Control+A` moves the cursor to the beginning of the line. -- @key{End} or @key{Control,E} moves to the end of line. If the cursor is already at the end of the line, and an autosuggestion is available, @key{End} or @key{Control,E} accepts the autosuggestion. +- :kbd:`End` or :kbd:`Control+E` moves to the end of line. If the cursor is already at the end of the line, and an autosuggestion is available, :kbd:`End` or :kbd:`Control+E` accepts the autosuggestion. -- @cursor_key{←,Left} (or @key{Control,B}) and @cursor_key{→,Right} (or @key{Control,F}) move the cursor left or right by one character. If the cursor is already at the end of the line, and an autosuggestion is available, the @cursor_key{→,Right} key and the @key{Control,F} combination accept the suggestion. +- @cursor_key{←,Left} (or :kbd:`Control+B`) and @cursor_key{→,Right} (or :kbd:`Control+F`) move the cursor left or right by one character. If the cursor is already at the end of the line, and an autosuggestion is available, the @cursor_key{→,Right} key and the :kbd:`Control+F` combination accept the suggestion. -- @key{Delete} and @key{Backspace} removes one character forwards or backwards respectively. +- :kbd:`Delete` and :kbd:`Backspace` removes one character forwards or backwards respectively. -- @key{Control,K} moves contents from the cursor to the end of line to the `killring <#killring>`_. +- :kbd:`Control+K` moves contents from the cursor to the end of line to the `killring <#killring>`_. -- @key{Alt,c} capitalizes the current word. +- :kbd:`Alt+c` capitalizes the current word. -- @key{Alt,u} makes the current word uppercase. +- :kbd:`Alt+u` makes the current word uppercase. -- @key{Control,t} transposes the last two characters +- :kbd:`Control+t` transposes the last two characters -- @key{Alt,t} transposes the last two words +- :kbd:`Alt+t` transposes the last two words You can change these key bindings using the `bind `_ builtin. @@ -1420,7 +1420,7 @@ You can change these key bindings using the `bind `_ builtin. Vi mode commands ---------------- -Vi mode allows for the use of Vi-like commands at the prompt. Initially, `insert mode <#vi-mode-insert>`_ is active. @key{Escape} enters `command mode <#vi-mode-command>`_. The commands available in command, insert and visual mode are described below. Vi mode shares `some bindings <#shared-binds>`_ with `Emacs mode <#emacs-mode>`_. +Vi mode allows for the use of Vi-like commands at the prompt. Initially, `insert mode <#vi-mode-insert>`_ is active. :kbd:`Escape` enters `command mode <#vi-mode-command>`_. The commands available in command, insert and visual mode are described below. Vi mode shares `some bindings <#shared-binds>`_ with `Emacs mode <#emacs-mode>`_. It is also possible to add all emacs-mode bindings to vi-mode by using something like:: @@ -1444,40 +1444,40 @@ Command mode Command mode is also known as normal mode. -- @key{h} moves the cursor left. +- :kbd:`h` moves the cursor left. -- @key{l} moves the cursor right. +- :kbd:`l` moves the cursor right. -- @key{i} enters `insert mode <#vi-mode-insert>`_ at the current cursor position. +- :kbd:`i` enters `insert mode <#vi-mode-insert>`_ at the current cursor position. -- @key{v} enters `visual mode <#vi-mode-visual>`_ at the current cursor position. +- :kbd:`v` enters `visual mode <#vi-mode-visual>`_ at the current cursor position. -- @key{a} enters `insert mode <#vi-mode-insert>`_ after the current cursor position. +- :kbd:`a` enters `insert mode <#vi-mode-insert>`_ after the current cursor position. -- @key{Shift,A} enters `insert mode <#vi-mode-insert>`_ at the end of the line. +- :kbd:`Shift,A` enters `insert mode <#vi-mode-insert>`_ at the end of the line. -- @key{0} (zero) moves the cursor to beginning of line (remaining in command mode). +- :kbd:`0` (zero) moves the cursor to beginning of line (remaining in command mode). -- @key{d}@key{d} deletes the current line and moves it to the `killring <#killring>`_. +- :kbd:`d`:kbd:`d` deletes the current line and moves it to the `killring <#killring>`_. -- @key{Shift,D} deletes text after the current cursor position and moves it to the `killring <#killring>`_. +- :kbd:`Shift,D` deletes text after the current cursor position and moves it to the `killring <#killring>`_. -- @key{p} pastes text from the `killring <#killring>`_. +- :kbd:`p` pastes text from the `killring <#killring>`_. -- @key{u} search history backwards. +- :kbd:`u` search history backwards. -- @key{[} and @key{]} search the command history for the previous/next token containing the token under the cursor before the search was started. See the `history <#history>`_ section for more information on history searching. +- :kbd:`[` and :kbd:`]` search the command history for the previous/next token containing the token under the cursor before the search was started. See the `history <#history>`_ section for more information on history searching. -- @key{Backspace} moves the cursor left. +- :kbd:`Backspace` moves the cursor left. .. _vi-mode-insert: Insert mode ----------- -- @key{Escape} enters `command mode <#vi-mode-command>`_. +- :kbd:`Escape` enters `command mode <#vi-mode-command>`_. -- @key{Backspace} removes one character to the left. +- :kbd:`Backspace` removes one character to the left. .. _vi-mode-visual: @@ -1486,20 +1486,20 @@ Visual mode - @cursor_key{←,Left} and @cursor_key{→,Right} extend the selection backward/forward by one character. -- @key{b} and @key{w} extend the selection backward/forward by one word. +- :kbd:`b` and :kbd:`w` extend the selection backward/forward by one word. -- @key{d} and @key{x} move the selection to the `killring <#killring>`_ and enter `command mode <#vi-mode-command>`_. +- :kbd:`d` and :kbd:`x` move the selection to the `killring <#killring>`_ and enter `command mode <#vi-mode-command>`_. -- @key{Escape} and @key{Control,C} enter `command mode <#vi-mode-command>`_. +- :kbd:`Escape` and :kbd:`Control+C` enter `command mode <#vi-mode-command>`_. .. _killring: Copy and paste (Kill Ring) -------------------------- -``fish`` uses an Emacs style kill ring for copy and paste functionality. Use @key{Control,K} to cut from the current cursor position to the end of the line. The string that is cut (a.k.a. killed) is inserted into a linked list of kills, called the kill ring. To paste the latest value from the kill ring use @key{Control,Y}. After pasting, use @key{Alt,Y} to rotate to the previous kill. +``fish`` uses an Emacs style kill ring for copy and paste functionality. Use :kbd:`Control+K` to cut from the current cursor position to the end of the line. The string that is cut (a.k.a. killed) is inserted into a linked list of kills, called the kill ring. To paste the latest value from the kill ring use :kbd:`Control+Y`. After pasting, use :kbd:`Alt+Y` to rotate to the previous kill. -Copy and paste from outside are also supported, both via the @key{Control,X} / @key{Control,V} bindings and via the terminal's paste function, for which fish enables "Bracketed Paste Mode". When pasting inside single quotes, pasted single quotes and backslashes are automatically escaped so that the result can be used as a single token simply by closing the quote after. +Copy and paste from outside are also supported, both via the :kbd:`Control+X` / :kbd:`Control+V` bindings and via the terminal's paste function, for which fish enables "Bracketed Paste Mode". When pasting inside single quotes, pasted single quotes and backslashes are automatically escaped so that the result can be used as a single token simply by closing the quote after. .. _history-search: @@ -1508,7 +1508,7 @@ Searchable history After a command has been entered, it is inserted at the end of a history list. Any duplicate history items are automatically removed. By pressing the up and down keys, the user can search forwards and backwards in the history. If the current command line is not empty when starting a history search, only the commands containing the string entered into the command line are shown. -By pressing @key{Alt,↑,Up} and @key{Alt,↓,Down}, a history search is also performed, but instead of searching for a complete commandline, each commandline is broken into separate elements just like it would be before execution, and the history is searched for an element matching that under the cursor. +By pressing :kbd:`Alt+↑,Up` and :kbd:`Alt+↓,Down`, a history search is also performed, but instead of searching for a complete commandline, each commandline is broken into separate elements just like it would be before execution, and the history is searched for an element matching that under the cursor. History searches can be aborted by pressing the escape key. @@ -1523,7 +1523,7 @@ Examples: To search for previous entries containing the word 'make', type ``make`` in the console and press the up key. -If the commandline reads ``cd m``, place the cursor over the ``m`` character and press @key{Alt,↑,Up} to search for previously typed words containing 'm'. +If the commandline reads ``cd m``, place the cursor over the ``m`` character and press :kbd:`Alt+↑,Up` to search for previously typed words containing 'm'. .. _multiline: @@ -1533,11 +1533,11 @@ Multiline editing The fish commandline editor can be used to work on commands that are several lines long. There are three ways to make a command span more than a single line: -- Pressing the @key{Enter} key while a block of commands is unclosed, such as when one or more block commands such as ``for``, ``begin`` or ``if`` do not have a corresponding ``end`` command. +- Pressing the :kbd:`Enter` key while a block of commands is unclosed, such as when one or more block commands such as ``for``, ``begin`` or ``if`` do not have a corresponding ``end`` command. -- Pressing @key{Alt,Enter} instead of pressing the @key{Enter} key. +- Pressing :kbd:`Alt+Enter` instead of pressing the :kbd:`Enter` key. -- By inserting a backslash (``\``) character before pressing the @key{Enter} key, escaping the newline. +- By inserting a backslash (``\``) character before pressing the :kbd:`Enter` key, escaping the newline. The fish commandline editor works exactly the same in single line mode and in multiline mode. To move between lines use the left and right arrow keys and other such keyboard shortcuts. @@ -1550,7 +1550,7 @@ Normally when ``fish`` starts a program, this program will be put in the foregro -# By ending a command with the ``&`` (ampersand) symbol, the user tells ``fish`` to put the specified command into the background. A background process will be run simultaneous with ``fish``. ``fish`` will retain control of the terminal, so the program will not be able to read from the keyboard. --# By pressing @key{Control,Z}, the user stops a currently running foreground program and returns control to ``fish``. Some programs do not support this feature, or remap it to another key. GNU Emacs uses @key{Control,X} @key{z} to stop running. +-# By pressing :kbd:`Control+Z`, the user stops a currently running foreground program and returns control to ``fish``. Some programs do not support this feature, or remap it to another key. GNU Emacs uses :kbd:`Control+X` :kbd:`z` to stop running. -# By using the `bg `_ and `fg `_ builtin commands, the user can send any currently running job into the foreground or background. diff --git a/sphinx_doc_src/tutorial.rst b/sphinx_doc_src/tutorial.rst index 0cc4a6d28..5b386a755 100644 --- a/sphinx_doc_src/tutorial.rst +++ b/sphinx_doc_src/tutorial.rst @@ -123,7 +123,7 @@ Especially powerful is the recursive wildcard ** which searches directories recu /var/run/sntp.log -If that directory traversal is taking a long time, you can @key{Control,C} out of it. +If that directory traversal is taking a long time, you can :kbd:`Control+C` out of it. Pipes and Redirections @@ -163,21 +163,21 @@ And history too. Type a command once, and you can re-summon it by just typing a >_ r<___sync -avze ssh . myname@somelonghost.com:/some/long/path/doo/dee/doo/dee/doo -To accept the autosuggestion, hit @cursor_key{→,right arrow} or @key{Control,F}. To accept a single word of the autosuggestion, @key{Alt,→} (right arrow). If the autosuggestion is not what you want, just ignore it. +To accept the autosuggestion, hit @cursor_key{→,right arrow} or :kbd:`Control+F`. To accept a single word of the autosuggestion, :kbd:`Alt+→` (right arrow). If the autosuggestion is not what you want, just ignore it. Tab Completions --------------- ``fish`` comes with a rich set of tab completions, that work "out of the box." -Press @key{Tab}, and ``fish`` will attempt to complete the command, argument, or path:: +Press :kbd:`Tab`, and ``fish`` will attempt to complete the command, argument, or path:: - >_ /pri @key{Tab} → /private/ + >_ /pri :kbd:`Tab` → /private/ If there's more than one possibility, it will list them:: - >_ ~/stuff/s @key{Tab} + >_ ~/stuff/s :kbd:`Tab` ~/stuff/script.sh (Executable, 4.8kB) \mtch{~/stuff/sources/ (Directory)} @@ -185,8 +185,8 @@ Hit tab again to cycle through the possibilities. ``fish`` can also complete many commands, like git branches:: - >_ git merge pr @key{Tab} → git merge prompt_designer - >_ git checkout b @key{Tab} + >_ git merge pr :kbd:`Tab` → git merge prompt_designer + >_ git checkout b :kbd:`Tab` builtin_list_io_merge (Branch) \mtch{builtin_set_color (Branch) busted_events (Tag)} From 99d77c60492639abe206e922f7304f57e7032d0b Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 24 Mar 2019 20:03:29 +0100 Subject: [PATCH 0149/1732] docs: Replace &.arr; markup with unicode arrows This is still missing the @cursor_keys bit. See #5696. [ci skip] --- sphinx_doc_src/faq.rst | 8 ++++---- sphinx_doc_src/index.rst | 22 +++++++++++----------- sphinx_doc_src/tutorial.rst | 6 +++--- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/sphinx_doc_src/faq.rst b/sphinx_doc_src/faq.rst index 143ba7063..35742d8b9 100644 --- a/sphinx_doc_src/faq.rst +++ b/sphinx_doc_src/faq.rst @@ -31,7 +31,7 @@ You can also use the Web configuration tool, Input Stream ⇒|Shell Command|⇒ Output Stream -switch and data as arguments →→ exit code +switch and data as arguments →→ exit code This leads to another way of programming and especially of combining commands: @@ -518,7 +518,7 @@ Autosuggestions fish suggests commands as you type, based on command history, completions, and valid file paths. As you type commands, you will see a suggestion offered after the cursor, in a muted gray color (which can be changed with the ``fish_color_autosuggestion`` variable). -To accept the autosuggestion (replacing the command line contents), press right arrow or :kbd:`Control+F`. To accept the first suggested word, press :kbd:`Alt+→,Right` or :kbd:`Alt+F`. If the autosuggestion is not what you want, just ignore it: it won't execute unless you accept it. +To accept the autosuggestion (replacing the command line contents), press right arrow or :kbd:`Control+F`. To accept the first suggested word, press :kbd:`Alt+→,Right` or :kbd:`Alt+F`. If the autosuggestion is not what you want, just ignore it: it won't execute unless you accept it. Autosuggestions are a powerful way to quickly summon frequently entered commands, by typing the first few characters. They are also an efficient technique for navigating through directory hierarchies. @@ -1354,13 +1354,13 @@ Some bindings are shared between emacs- and vi-mode because they aren't text edi - :kbd:`Tab` `completes <#completion>`_ the current token. :kbd:`Shift, Tab` completes the current token and starts the pager's search mode. -- :kbd:`Alt+←,Left` and :kbd:`Alt+→,Right` move the cursor one word left or right (to the next space or punctuation mark), or moves forward/backward in the directory history if the command line is empty. If the cursor is already at the end of the line, and an autosuggestion is available, :kbd:`Alt+→,Right` (or :kbd:`Alt+F`) accepts the first word in the suggestion. +- :kbd:`Alt+←,Left` and :kbd:`Alt+→,Right` move the cursor one word left or right (to the next space or punctuation mark), or moves forward/backward in the directory history if the command line is empty. If the cursor is already at the end of the line, and an autosuggestion is available, :kbd:`Alt+→,Right` (or :kbd:`Alt+F`) accepts the first word in the suggestion. -- :kbd:`Shift,←,Left` and :kbd:`Shift,→,Right` move the cursor one word left or right, without stopping on punctuation. +- :kbd:`Shift,←,Left` and :kbd:`Shift,→,Right` move the cursor one word left or right, without stopping on punctuation. -- @cursor_key{↑,Up} and @cursor_key{↓,Down} (or :kbd:`Control+P` and :kbd:`Control+N` for emacs aficionados) search the command history for the previous/next command containing the string that was specified on the commandline before the search was started. If the commandline was empty when the search started, all commands match. See the `history <#history>`_ section for more information on history searching. +- @cursor_key{↑,Up} and @cursor_key{↓,Down} (or :kbd:`Control+P` and :kbd:`Control+N` for emacs aficionados) search the command history for the previous/next command containing the string that was specified on the commandline before the search was started. If the commandline was empty when the search started, all commands match. See the `history <#history>`_ section for more information on history searching. -- :kbd:`Alt+↑,Up` and :kbd:`Alt+↓,Down` search the command history for the previous/next token containing the token under the cursor before the search was started. If the commandline was not on a token when the search started, all tokens match. See the `history <#history>`_ section for more information on history searching. +- :kbd:`Alt+↑,Up` and :kbd:`Alt+↓,Down` search the command history for the previous/next token containing the token under the cursor before the search was started. If the commandline was not on a token when the search started, all tokens match. See the `history <#history>`_ section for more information on history searching. - :kbd:`Control+C` cancels the entire line. @@ -1397,7 +1397,7 @@ Emacs mode commands - :kbd:`End` or :kbd:`Control+E` moves to the end of line. If the cursor is already at the end of the line, and an autosuggestion is available, :kbd:`End` or :kbd:`Control+E` accepts the autosuggestion. -- @cursor_key{←,Left} (or :kbd:`Control+B`) and @cursor_key{→,Right} (or :kbd:`Control+F`) move the cursor left or right by one character. If the cursor is already at the end of the line, and an autosuggestion is available, the @cursor_key{→,Right} key and the :kbd:`Control+F` combination accept the suggestion. +- @cursor_key{←,Left} (or :kbd:`Control+B`) and @cursor_key{→,Right} (or :kbd:`Control+F`) move the cursor left or right by one character. If the cursor is already at the end of the line, and an autosuggestion is available, the @cursor_key{→,Right} key and the :kbd:`Control+F` combination accept the suggestion. - :kbd:`Delete` and :kbd:`Backspace` removes one character forwards or backwards respectively. @@ -1484,7 +1484,7 @@ Insert mode Visual mode ----------- -- @cursor_key{←,Left} and @cursor_key{→,Right} extend the selection backward/forward by one character. +- @cursor_key{←,Left} and @cursor_key{→,Right} extend the selection backward/forward by one character. - :kbd:`b` and :kbd:`w` extend the selection backward/forward by one word. @@ -1508,7 +1508,7 @@ Searchable history After a command has been entered, it is inserted at the end of a history list. Any duplicate history items are automatically removed. By pressing the up and down keys, the user can search forwards and backwards in the history. If the current command line is not empty when starting a history search, only the commands containing the string entered into the command line are shown. -By pressing :kbd:`Alt+↑,Up` and :kbd:`Alt+↓,Down`, a history search is also performed, but instead of searching for a complete commandline, each commandline is broken into separate elements just like it would be before execution, and the history is searched for an element matching that under the cursor. +By pressing :kbd:`Alt+↑,Up` and :kbd:`Alt+↓,Down`, a history search is also performed, but instead of searching for a complete commandline, each commandline is broken into separate elements just like it would be before execution, and the history is searched for an element matching that under the cursor. History searches can be aborted by pressing the escape key. @@ -1523,7 +1523,7 @@ Examples: To search for previous entries containing the word 'make', type ``make`` in the console and press the up key. -If the commandline reads ``cd m``, place the cursor over the ``m`` character and press :kbd:`Alt+↑,Up` to search for previously typed words containing 'm'. +If the commandline reads ``cd m``, place the cursor over the ``m`` character and press :kbd:`Alt+↑,Up` to search for previously typed words containing 'm'. .. _multiline: diff --git a/sphinx_doc_src/tutorial.rst b/sphinx_doc_src/tutorial.rst index 5b386a755..405d02cce 100644 --- a/sphinx_doc_src/tutorial.rst +++ b/sphinx_doc_src/tutorial.rst @@ -163,7 +163,7 @@ And history too. Type a command once, and you can re-summon it by just typing a >_ r<___sync -avze ssh . myname@somelonghost.com:/some/long/path/doo/dee/doo/dee/doo -To accept the autosuggestion, hit @cursor_key{→,right arrow} or :kbd:`Control+F`. To accept a single word of the autosuggestion, :kbd:`Alt+→` (right arrow). If the autosuggestion is not what you want, just ignore it. +To accept the autosuggestion, hit @cursor_key{→,right arrow} or :kbd:`Control+F`. To accept a single word of the autosuggestion, :kbd:`Alt+→` (right arrow). If the autosuggestion is not what you want, just ignore it. Tab Completions --------------- @@ -172,7 +172,7 @@ Tab Completions Press :kbd:`Tab`, and ``fish`` will attempt to complete the command, argument, or path:: - >_ /pri :kbd:`Tab` → /private/ + >_ /pri :kbd:`Tab` → /private/ If there's more than one possibility, it will list them:: @@ -185,7 +185,7 @@ Hit tab again to cycle through the possibilities. ``fish`` can also complete many commands, like git branches:: - >_ git merge pr :kbd:`Tab` → git merge prompt_designer + >_ git merge pr :kbd:`Tab` → git merge prompt_designer >_ git checkout b :kbd:`Tab` builtin_list_io_merge (Branch) \mtch{builtin_set_color (Branch) busted_events (Tag)} From 96b8ac70134be2f3caf530a5c96594bbc183b912 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 24 Mar 2019 12:12:08 -0700 Subject: [PATCH 0150/1732] Promote job_control_t to an enum class --- src/builtin_status.cpp | 46 ++++++++++++++++++++++------------------- src/parse_execution.cpp | 4 ++-- src/proc.cpp | 2 +- src/proc.h | 12 +++++------ 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/builtin_status.cpp b/src/builtin_status.cpp index 0f59405cd..c11aa4a5d 100644 --- a/src/builtin_status.cpp +++ b/src/builtin_status.cpp @@ -76,24 +76,25 @@ const enum_map status_enum_map[] = { /// Values that may be returned from the test-feature option to status. enum { TEST_FEATURE_ON, TEST_FEATURE_OFF, TEST_FEATURE_NOT_RECOGNIZED }; -int job_control_str_to_mode(const wchar_t *mode, wchar_t *cmd, io_streams_t &streams) { +static maybe_t job_control_str_to_mode(const wchar_t *mode, wchar_t *cmd, + io_streams_t &streams) { if (std::wcscmp(mode, L"full") == 0) { - return JOB_CONTROL_ALL; + return job_control_t::all; } else if (std::wcscmp(mode, L"interactive") == 0) { - return JOB_CONTROL_INTERACTIVE; + return job_control_t::interactive; } else if (std::wcscmp(mode, L"none") == 0) { - return JOB_CONTROL_NONE; + return job_control_t::none; } streams.err.append_format(L"%ls: Invalid job control mode '%ls'\n", cmd, mode); - return -1; + return none(); } struct status_cmd_opts_t { - bool print_help = false; - int level = 1; - int new_job_control_mode = -1; - const wchar_t *feature_name; - status_cmd_t status_cmd = STATUS_UNDEF; + bool print_help{false}; + int level{1}; + maybe_t new_job_control_mode{}; + const wchar_t *feature_name{}; + status_cmd_t status_cmd{STATUS_UNDEF}; }; /// Note: Do not add new flags that represent subcommands. We're encouraging people to switch to @@ -230,10 +231,11 @@ static int parse_cmd_opts(status_cmd_opts_t &opts, int *optind, //!OCLINT(high if (!set_status_cmd(cmd, opts, STATUS_SET_JOB_CONTROL, streams)) { return STATUS_CMD_ERROR; } - opts.new_job_control_mode = job_control_str_to_mode(w.woptarg, cmd, streams); - if (opts.new_job_control_mode == -1) { + auto job_mode = job_control_str_to_mode(w.woptarg, cmd, streams); + if (!job_mode) { return STATUS_CMD_ERROR; } + opts.new_job_control_mode = job_mode; break; } case 't': { @@ -309,14 +311,14 @@ int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) { streams.out.append_format( _(L"Job control: %ls\n"), - job_control_mode == JOB_CONTROL_INTERACTIVE + job_control_mode == job_control_t::interactive ? _(L"Only on interactive jobs") - : (job_control_mode == JOB_CONTROL_NONE ? _(L"Never") : _(L"Always"))); + : (job_control_mode == job_control_t::none ? _(L"Never") : _(L"Always"))); streams.out.append(parser.stack_trace()); break; } case STATUS_SET_JOB_CONTROL: { - if (opts.new_job_control_mode != -1) { + if (opts.new_job_control_mode) { // Flag form was used. CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd) } else { @@ -326,12 +328,14 @@ int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) { args.size()); return STATUS_INVALID_ARGS; } - opts.new_job_control_mode = job_control_str_to_mode(args[0].c_str(), cmd, streams); - if (opts.new_job_control_mode == -1) { + auto new_mode = job_control_str_to_mode(args[0].c_str(), cmd, streams); + if (!new_mode) { return STATUS_CMD_ERROR; } + opts.new_job_control_mode = new_mode; } - job_control_mode = opts.new_job_control_mode; + assert(opts.new_job_control_mode && "Should have a new mode"); + job_control_mode = *opts.new_job_control_mode; break; } case STATUS_FEATURES: { @@ -403,17 +407,17 @@ int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) { } case STATUS_IS_FULL_JOB_CTRL: { CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd) - retval = job_control_mode != JOB_CONTROL_ALL; + retval = job_control_mode != job_control_t::all; break; } case STATUS_IS_INTERACTIVE_JOB_CTRL: { CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd) - retval = job_control_mode != JOB_CONTROL_INTERACTIVE; + retval = job_control_mode != job_control_t::interactive; break; } case STATUS_IS_NO_JOB_CTRL: { CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd) - retval = job_control_mode != JOB_CONTROL_NONE; + retval = job_control_mode != job_control_t::none; break; } case STATUS_STACK_TRACE: { diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index c14aadd7f..85de38ab8 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -1207,8 +1207,8 @@ parse_execution_result_t parse_execution_context_t::run_1_job(tnode_t jo shared_ptr job = std::make_shared(acquire_job_id(), block_io, parent_job); job->tmodes = tmodes; job->set_flag(job_flag_t::JOB_CONTROL, - (job_control_mode == JOB_CONTROL_ALL) || - ((job_control_mode == JOB_CONTROL_INTERACTIVE) && shell_is_interactive())); + (job_control_mode == job_control_t::all) || + ((job_control_mode == job_control_t::interactive) && shell_is_interactive())); job->set_flag(job_flag_t::FOREGROUND, !job_node_is_background(job_node)); diff --git a/src/proc.cpp b/src/proc.cpp index 7c5016a14..df60dd461 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -79,7 +79,7 @@ bool is_block = false; bool is_breakpoint = false; bool is_login = false; int is_event = 0; -int job_control_mode = JOB_CONTROL_INTERACTIVE; +job_control_t job_control_mode = job_control_t::interactive; int no_exec = 0; static int is_interactive = -1; diff --git a/src/proc.h b/src/proc.h index b6f09376f..b161589ab 100644 --- a/src/proc.h +++ b/src/proc.h @@ -38,10 +38,10 @@ enum process_type_t { INTERNAL_EXEC }; -enum { - JOB_CONTROL_ALL, - JOB_CONTROL_INTERACTIVE, - JOB_CONTROL_NONE, +enum class job_control_t { + all, + interactive, + none, }; /// A proc_status_t is a value type that encapsulates logic around exited vs stopped vs signaled, @@ -489,8 +489,8 @@ void set_proc_had_barrier(bool flag); /// The current job control mode. /// -/// Must be one of JOB_CONTROL_ALL, JOB_CONTROL_INTERACTIVE and JOB_CONTROL_NONE. -extern int job_control_mode; +/// Must be one of job_control_t::all, job_control_t::interactive and job_control_t::none. +extern job_control_t job_control_mode; /// If this flag is set, fish will never fork or run execve. It is used to put fish into a syntax /// verifier mode where fish tries to validate the syntax of a file but doesn't actually do From 165c82e68ae16082b892a7d406d226ff8b6453f4 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 24 Mar 2019 12:29:25 -0700 Subject: [PATCH 0151/1732] Promote process_type_t to an enum class --- src/exec.cpp | 31 ++++++++++++++++--------------- src/parse_execution.cpp | 32 ++++++++++++++++---------------- src/proc.cpp | 2 +- src/proc.h | 34 +++++++++++++++++----------------- 4 files changed, 50 insertions(+), 49 deletions(-) diff --git a/src/exec.cpp b/src/exec.cpp index b93c78f02..d22e81334 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -488,7 +488,7 @@ static bool fork_child_for_process(const std::shared_ptr &job, process_t static bool exec_internal_builtin_proc(parser_t &parser, const std::shared_ptr &j, process_t *p, const io_pipe_t *pipe_read, const io_chain_t &proc_io_chain, io_streams_t &streams) { - assert(p->type == INTERNAL_BUILTIN && "Process must be a builtin"); + assert(p->type == process_type_t::builtin && "Process must be a builtin"); int local_builtin_stdin = STDIN_FILENO; autoclose_fd_t locally_opened_stdin{}; @@ -590,7 +590,7 @@ static bool exec_internal_builtin_proc(parser_t &parser, const std::shared_ptr &j, process_t *p, io_chain_t *io_chain, const io_streams_t &builtin_io_streams) { - assert(p->type == INTERNAL_BUILTIN && "Process is not a builtin"); + assert(p->type == process_type_t::builtin && "Process is not a builtin"); const output_stream_t &stdout_stream = builtin_io_streams.out; const output_stream_t &stderr_stream = builtin_io_streams.err; @@ -677,7 +677,7 @@ static bool handle_builtin_output(const std::shared_ptr &j, process_t *p, /// \return true on success, false if there is an exec error. static bool exec_external_command(env_stack_t &vars, const std::shared_ptr &j, process_t *p, const io_chain_t &proc_io_chain) { - assert(p->type == EXTERNAL && "Process is not external"); + assert(p->type == process_type_t::external && "Process is not external"); // Get argv and envv before we fork. null_terminated_array_t argv_array; convert_wide_array_to_narrow(p->get_argv_array(), &argv_array); @@ -786,7 +786,7 @@ static bool exec_external_command(env_stack_t &vars, const std::shared_ptr j, process_t *p, const io_chain_t &user_ios, io_chain_t io_chain) { - assert((p->type == INTERNAL_FUNCTION || p->type == INTERNAL_BLOCK_NODE) && + assert((p->type == process_type_t::function || p->type == process_type_t::block_node) && "Unexpected process type"); // Create an output buffer if we're piping to another process. @@ -802,7 +802,7 @@ static bool exec_block_or_func_process(parser_t &parser, std::shared_ptr io_chain.push_back(block_output_bufferfill); } - if (p->type == INTERNAL_FUNCTION) { + if (p->type == process_type_t::function) { const wcstring func_name = p->argv0(); auto props = function_get_properties(func_name); if (!props) { @@ -822,7 +822,7 @@ static bool exec_block_or_func_process(parser_t &parser, std::shared_ptr parser.allow_function(); parser.pop_block(fb); } else { - assert(p->type == INTERNAL_BLOCK_NODE); + assert(p->type == process_type_t::block_node); assert(p->block_node_source && p->internal_block_node && "Process is missing node info"); internal_exec_helper(parser, p->block_node_source, p->internal_block_node, io_chain, j); } @@ -939,7 +939,7 @@ static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr< // to generate it, since that result would not get written back to the parent. This call // could be safely removed, but it would result in slightly lower performance - at least on // uniprocessor systems. - if (p->type == EXTERNAL) { + if (p->type == process_type_t::external) { // Apply universal barrier so we have the most recent uvar changes if (!get_proc_had_barrier()) { set_proc_had_barrier(true); @@ -951,15 +951,15 @@ static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr< // Execute the process. p->check_generations_before_launch(); switch (p->type) { - case INTERNAL_FUNCTION: - case INTERNAL_BLOCK_NODE: { + case process_type_t::function: + case process_type_t::block_node: { if (!exec_block_or_func_process(parser, j, p, all_ios, process_net_io_chain)) { return false; } break; } - case INTERNAL_BUILTIN: { + case process_type_t::builtin: { io_streams_t builtin_io_streams{stdout_read_limit}; if (!exec_internal_builtin_proc(parser, j, p, pipe_read.get(), process_net_io_chain, builtin_io_streams)) { @@ -971,16 +971,17 @@ static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr< break; } - case EXTERNAL: { + case process_type_t::external: { if (!exec_external_command(parser.vars(), j, p, process_net_io_chain)) { return false; } break; } - case INTERNAL_EXEC: { + case process_type_t::exec: { // We should have handled exec up above. - DIE("INTERNAL_EXEC process found in pipeline, where it should never be. Aborting."); + DIE("process_type_t::exec process found in pipeline, where it should never be. " + "Aborting."); break; } } @@ -1002,7 +1003,7 @@ bool exec_job(parser_t &parser, shared_ptr j) { const std::shared_ptr parent_job = j->get_parent(); // Perhaps inherit our parent's pgid and job control flag. - if (parent_job && j->processes.front()->type == EXTERNAL) { + if (parent_job && j->processes.front()->type == process_type_t::external) { if (parent_job->pgid != INVALID_PID) { j->pgid = parent_job->pgid; j->set_flag(job_flag_t::JOB_CONTROL, true); @@ -1019,7 +1020,7 @@ bool exec_job(parser_t &parser, shared_ptr j) { } } - if (j->processes.front()->type == INTERNAL_EXEC) { + if (j->processes.front()->type == process_type_t::exec) { internal_exec(parser.vars(), j.get(), all_ios); // internal_exec only returns if it failed to set up redirections. // In case of an successful exec, this code is not reached. diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 85de38ab8..2034f0d56 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -143,9 +143,9 @@ tnode_t parse_execution_context_t::infinite_recursive_statem return infinite_recursive_statement; } -enum process_type_t parse_execution_context_t::process_type_for_command( +process_type_t parse_execution_context_t::process_type_for_command( tnode_t statement, const wcstring &cmd) const { - enum process_type_t process_type = EXTERNAL; + enum process_type_t process_type = process_type_t::external; // Determine the process type, which depends on the statement decoration (command, builtin, // etc). @@ -153,19 +153,19 @@ enum process_type_t parse_execution_context_t::process_type_for_command( if (decoration == parse_statement_decoration_exec) { // Always exec. - process_type = INTERNAL_EXEC; + process_type = process_type_t::exec; } else if (decoration == parse_statement_decoration_command) { // Always a command. - process_type = EXTERNAL; + process_type = process_type_t::external; } else if (decoration == parse_statement_decoration_builtin) { // What happens if this builtin is not valid? - process_type = INTERNAL_BUILTIN; + process_type = process_type_t::builtin; } else if (function_exists(cmd)) { - process_type = INTERNAL_FUNCTION; + process_type = process_type_t::function; } else if (builtin_exists(cmd)) { - process_type = INTERNAL_BUILTIN; + process_type = process_type_t::builtin; } else { - process_type = EXTERNAL; + process_type = process_type_t::external; } return process_type; } @@ -775,7 +775,7 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process( enum process_type_t process_type = process_type_for_command(statement, cmd); // Check for stack overflow. - if (process_type == INTERNAL_FUNCTION && + if (process_type == process_type_t::function && parser->forbidden_function.size() > FISH_MAX_STACK_DEPTH) { this->report_error(statement, CALL_STACK_LIMIT_EXCEEDED_ERR_MSG); return parse_execution_errored; @@ -783,7 +783,7 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process( // Protect against exec with background processes running static uint32_t last_exec_run_counter = -1; - if (process_type == INTERNAL_EXEC && shell_is_interactive()) { + if (process_type == process_type_t::exec && shell_is_interactive()) { job_iterator_t jobs; bool have_bg = false; const job_t *bg = nullptr; @@ -811,7 +811,7 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process( } wcstring path_to_external_command; - if (process_type == EXTERNAL || process_type == INTERNAL_EXEC) { + if (process_type == process_type_t::external || process_type == process_type_t::exec) { // Determine the actual command. This may be an implicit cd. bool has_command = path_get_path(cmd, &path_to_external_command, parser->vars()); @@ -847,7 +847,7 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process( path_to_external_command.clear(); // If we have defined a wrapper around cd, use it, otherwise use the cd builtin. - process_type = function_exists(L"cd") ? INTERNAL_FUNCTION : INTERNAL_BUILTIN; + process_type = function_exists(L"cd") ? process_type_t::function : process_type_t::builtin; } else { // Not implicit cd. const globspec_t glob_behavior = (cmd == L"set" || cmd == L"count") ? nullglob : failglob; @@ -1006,8 +1006,8 @@ template parse_execution_result_t parse_execution_context_t::populate_block_process( job_t *job, process_t *proc, tnode_t statement, tnode_t specific_statement) { - // We handle block statements by creating INTERNAL_BLOCK_NODE, that will bounce back to us when - // it's time to execute them. + // We handle block statements by creating process_type_t::block_node, that will bounce back to + // us when it's time to execute them. UNUSED(job); static_assert(Type::token == symbol_block_statement || Type::token == symbol_if_statement || Type::token == symbol_switch_statement, @@ -1022,7 +1022,7 @@ parse_execution_result_t parse_execution_context_t::populate_block_process( bool errored = !this->determine_io_chain(arguments, &process_io_chain); if (errored) return parse_execution_errored; - proc->type = INTERNAL_BLOCK_NODE; + proc->type = process_type_t::block_node; proc->block_node_source = pstree; proc->internal_block_node = statement; proc->set_io_chain(process_io_chain); @@ -1245,7 +1245,7 @@ parse_execution_result_t parse_execution_context_t::run_1_job(tnode_t jo // Check to see if this contained any external commands. bool job_contained_external_command = false; for (const auto &proc : job->processes) { - if (proc->type == EXTERNAL) { + if (proc->type == process_type_t::external) { job_contained_external_command = true; break; } diff --git a/src/proc.cpp b/src/proc.cpp index df60dd461..119bbfeee 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -917,7 +917,7 @@ void proc_sanity_check() { for (const process_ptr_t &p : j->processes) { // Internal block nodes do not have argv - see issue #1545. - bool null_ok = (p->type == INTERNAL_BLOCK_NODE); + bool null_ok = (p->type == process_type_t::block_node); validate_pointer(p->get_argv(), _(L"Process argument list"), null_ok); validate_pointer(p->argv0(), _(L"Process name"), null_ok); diff --git a/src/proc.h b/src/proc.h index b161589ab..716fd42f7 100644 --- a/src/proc.h +++ b/src/proc.h @@ -25,17 +25,17 @@ #include "topic_monitor.h" /// Types of processes. -enum process_type_t { +enum class process_type_t { /// A regular external command. - EXTERNAL, + external, /// A builtin command. - INTERNAL_BUILTIN, + builtin, /// A shellscript function. - INTERNAL_FUNCTION, + function, /// A block of commands, represented as a node. - INTERNAL_BLOCK_NODE, + block_node, /// The exec builtin. - INTERNAL_EXEC + exec, }; enum class job_control_t { @@ -137,21 +137,22 @@ class internal_proc_t { /// process, an internal builtin which may or may not spawn a fake IO process during execution, a /// shellscript function or a block of commands to be evaluated by calling eval. Lastly, this /// process can be the result of an exec command. The role of this process_t is determined by the -/// type field, which can be one of EXTERNAL, INTERNAL_BUILTIN, INTERNAL_FUNCTION, INTERNAL_EXEC. +/// type field, which can be one of process_type_t::external, process_type_t::builtin, +/// process_type_t::function, process_type_t::exec. /// /// The process_t contains information on how the process should be started, such as command name /// and arguments, as well as runtime information on the status of the actual physical process which /// represents it. Shellscript functions, builtins and blocks of code may all need to spawn an /// external process that handles the piping and redirecting of IO for them. /// -/// If the process is of type EXTERNAL or INTERNAL_EXEC, argv is the argument array and actual_cmd -/// is the absolute path of the command to execute. +/// If the process is of type process_type_t::external or process_type_t::exec, argv is the argument +/// array and actual_cmd is the absolute path of the command to execute. /// -/// If the process is of type INTERNAL_BUILTIN, argv is the argument vector, and argv[0] is the name -/// of the builtin command. +/// If the process is of type process_type_t::builtin, argv is the argument vector, and argv[0] is +/// the name of the builtin command. /// -/// If the process is of type INTERNAL_FUNCTION, argv is the argument vector, and argv[0] is the -/// name of the shellscript function. +/// If the process is of type process_type_t::function, argv is the argument vector, and argv[0] is +/// the name of the shellscript function. class process_t { private: null_terminated_array_t argv_array; @@ -169,9 +170,8 @@ class process_t { bool is_first_in_job{false}; bool is_last_in_job{false}; - /// Type of process. Can be one of \c EXTERNAL, \c INTERNAL_BUILTIN, \c INTERNAL_FUNCTION, \c - /// INTERNAL_EXEC. - enum process_type_t type { EXTERNAL }; + /// Type of process. + process_type_t type{process_type_t::external}; /// For internal block processes only, the node offset of the statement. /// This is always either block, ifs, or switchs, never boolean or decorated. @@ -208,7 +208,7 @@ class process_t { /// launch. This helps us avoid spurious waitpid calls. void check_generations_before_launch(); - /// Actual command to pass to exec in case of EXTERNAL or INTERNAL_EXEC. + /// Actual command to pass to exec in case of process_type_t::external or process_type_t::exec. wcstring actual_cmd; /// Generation counts for reaping. From 3bbee06248b073fc30ae5cc8e418c943c8cd6e11 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 24 Mar 2019 14:27:23 -0700 Subject: [PATCH 0152/1732] Introduce the notion of a deferred process In a job, a deferred process is the last fish internal process which pipes to an external command. Execute the deferred process last; this will allow for streaming its output. --- src/exec.cpp | 132 +++++++++++++++++++++++++++++++++++---------------- src/io.h | 4 ++ 2 files changed, 95 insertions(+), 41 deletions(-) diff --git a/src/exec.cpp b/src/exec.cpp index d22e81334..4775dc27b 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -861,35 +861,14 @@ static bool exec_block_or_func_process(parser_t &parser, std::shared_ptr return true; } -/// Executes a process \p in job \j, using the read pipe \p pipe_current_read. -/// If the process pipes to a command, the read end of the created pipe is returned in -/// out_pipe_next_read. \returns true on success, false on exec error. +/// Executes a process \p in job \j, using the pipes \p pipes (which may have invalid fds if this is +/// the first or last process). +/// deferred_pipes represents the pipes from our deferred process; if set ensure they get closed in +/// any child. +/// \returns true on success, false on exec error. static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr j, - autoclose_fd_t pipe_current_read, - autoclose_fd_t *out_pipe_next_read, const io_chain_t &all_ios, - size_t stdout_read_limit) { - // The pipe this command will write to (if any). - shared_ptr pipe_write; - // The pipe this command will read from (if any). - shared_ptr pipe_read; - - // See if we need a pipe for the next command. - const bool pipes_to_next_command = !p->is_last_in_job; - if (pipes_to_next_command) { - // Construct our pipes. - auto local_pipes = make_autoclose_pipes(all_ios); - if (!local_pipes) { - debug(1, PIPE_ERROR); - wperror(L"pipe"); - job_mark_process_as_failed(j, p); - return false; - } - - pipe_write = std::make_shared(p->pipe_write_fd, false /* not input */, - std::move(local_pipes->write)); - *out_pipe_next_read = std::move(local_pipes->read); - } - + autoclose_pipes_t pipes, const io_chain_t &all_ios, + const autoclose_pipes_t &deferred_pipes, size_t stdout_read_limit) { // The write pipe (destined for stdout) needs to occur before redirections. For example, // with a redirection like this: // @@ -920,20 +899,30 @@ static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr< // The IO chain for this process. io_chain_t process_net_io_chain = j->block_io_chain(); - if (pipe_write) { - process_net_io_chain.push_back(pipe_write); + + if (pipes.write.valid()) { + process_net_io_chain.push_back(std::make_shared( + p->pipe_write_fd, false /* not input */, std::move(pipes.write))); } // The explicit IO redirections associated with the process. process_net_io_chain.append(p->io_chain()); // Read pipe goes last. - if (pipe_current_read.valid()) { - pipe_read = std::make_shared(STDIN_FILENO, true /* input */, - std::move(pipe_current_read)); + shared_ptr pipe_read{}; + if (pipes.read.valid()) { + pipe_read = + std::make_shared(STDIN_FILENO, true /* input */, std::move(pipes.read)); process_net_io_chain.push_back(pipe_read); } + // If we have stashed pipes, make sure those get closed in the child. + for (const autoclose_fd_t *afd : {&deferred_pipes.read, &deferred_pipes.write}) { + if (afd->valid()) { + process_net_io_chain.push_back(std::make_shared(afd->fd())); + } + } + // This call is used so the global environment variable array is regenerated, if needed, // before the fork. That way, we avoid a lot of duplicate work where EVERY child would need // to generate it, since that result would not get written back to the parent. This call @@ -988,6 +977,31 @@ static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr< return true; } +// Do we have a fish internal process that pipes into a real process? If so, we are going to +// launch it last (if there's more than one, just the last one). That is to prevent buffering +// from blocking further processes. See #1396. +// Example: +// for i in (seq 1 5); sleep 1; echo $i; end | cat +// This should show the output as it comes, not buffer until the end. +// Any such process (only one per job) will be called the "deferred" process. +static process_t *get_deferred_process(const shared_ptr &j) { + process_t *last_internal = nullptr; + for (const auto &p : j->processes) { + if (p->type == process_type_t::exec) { + // No tail reordering for execs. + return nullptr; + } else if (p->type != process_type_t::external) { + last_internal = p.get(); + } + } + if (last_internal && !last_internal->is_last_in_job) { + // This is the last internal process, and it pipes to an external process. + return last_internal; + } else { + return nullptr; + } +} + bool exec_job(parser_t &parser, shared_ptr j) { assert(j && "null job_t passed to exec_job!"); @@ -1011,15 +1025,17 @@ bool exec_job(parser_t &parser, shared_ptr j) { } size_t stdout_read_limit = 0; - const io_chain_t all_ios = j->all_io_redirections(); + io_chain_t all_ios = j->all_io_redirections(); + + // The read limit is dictated by the last bufferfill. for (auto &io : all_ios) { if ((io->io_mode == io_mode_t::bufferfill)) { - // The read limit is dictated by the last bufferfill. const auto *bf = static_cast(io.get()); stdout_read_limit = bf->buffer()->read_limit(); } } + // Handle an exec call. if (j->processes.front()->type == process_type_t::exec) { internal_exec(parser.vars(), j.get(), all_ios); // internal_exec only returns if it failed to set up redirections. @@ -1029,6 +1045,10 @@ bool exec_job(parser_t &parser, shared_ptr j) { return false; } + // Get the deferred process, if any. We will have to remember its pipes. + autoclose_pipes_t deferred_pipes; + process_t *const deferred_process = get_deferred_process(j); + // This loop loops over every process_t in the job, starting it as appropriate. This turns out // to be rather complex, since a process_t can be one of many rather different things. // @@ -1041,16 +1061,46 @@ bool exec_job(parser_t &parser, shared_ptr j) { // 3. The pipe that the next process should read from (courtesy of us) // autoclose_fd_t pipe_next_read; - for (const auto &unique_p : j->processes) { - autoclose_fd_t current_read = std::move(pipe_next_read); - if (!exec_process_in_job(parser, unique_p.get(), j, std::move(current_read), - &pipe_next_read, all_ios, stdout_read_limit)) { - exec_error = true; - break; + for (const auto &p : j->processes) { + // proc_pipes is the pipes applied to this process. That is, it is the read end + // containing the output of the previous process (if any), plus the write end that will + // output to the next process (if any). + autoclose_pipes_t proc_pipes; + proc_pipes.read = std::move(pipe_next_read); + if (!p->is_last_in_job) { + auto pipes = make_autoclose_pipes(all_ios); + if (!pipes) { + debug(1, PIPE_ERROR); + wperror(L"pipe"); + job_mark_process_as_failed(j, p.get()); + exec_error = true; + break; + } + pipe_next_read = std::move(pipes->read); + proc_pipes.write = std::move(pipes->write); + } + + if (p.get() == deferred_process) { + deferred_pipes = std::move(proc_pipes); + } else { + if (!exec_process_in_job(parser, p.get(), j, std::move(proc_pipes), all_ios, + deferred_pipes, stdout_read_limit)) { + exec_error = true; + break; + } } } pipe_next_read.close(); + // Now execute any deferred process. + if (!exec_error && deferred_process) { + assert(deferred_pipes.write.valid() && "Deferred process should always have a write pipe"); + if (!exec_process_in_job(parser, deferred_process, j, std::move(deferred_pipes), all_ios, + {}, stdout_read_limit)) { + exec_error = true; + } + } + debug(3, L"Created job %d from command '%ls' with pgrp %d", j->job_id, j->command_wcstr(), j->pgid); diff --git a/src/io.h b/src/io.h index 4017af474..e72a00291 100644 --- a/src/io.h +++ b/src/io.h @@ -352,6 +352,10 @@ struct autoclose_pipes_t { /// Write end of the pipe. autoclose_fd_t write; + + autoclose_pipes_t() = default; + autoclose_pipes_t(autoclose_fd_t r, autoclose_fd_t w) + : read(std::move(r)), write(std::move(w)) {} }; /// Call pipe(), populating autoclose fds, avoiding conflicts. /// The pipes are marked CLO_EXEC. From 5eade35257aeb1302f57c112123ba7042c062b3e Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 24 Mar 2019 21:12:41 -0700 Subject: [PATCH 0153/1732] Stop buffering deferred function processes If a function process is deferred, allow it to be unbuffered. This permits certain simple cases where functions are piped to external commands to execute without buffering. This is a somewhat-hacky stopgap measure that can't really be extended to more general concurrent processes. However it is overall an improvement in user experience that might help flush out some bugs too. --- src/exec.cpp | 26 +++++++++++++++++--------- tests/test1.in | 2 +- tests/test1.out | 2 +- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/exec.cpp b/src/exec.cpp index 4775dc27b..ddf612d9d 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -783,15 +783,18 @@ static bool exec_external_command(env_stack_t &vars, const std::shared_ptr j, process_t *p, - const io_chain_t &user_ios, io_chain_t io_chain) { + const io_chain_t &user_ios, io_chain_t io_chain, + bool allow_buffering) { assert((p->type == process_type_t::function || p->type == process_type_t::block_node) && "Unexpected process type"); // Create an output buffer if we're piping to another process. shared_ptr block_output_bufferfill{}; - if (!p->is_last_in_job) { + if (!p->is_last_in_job && allow_buffering) { // Be careful to handle failure, e.g. too many open fds. block_output_bufferfill = io_bufferfill_t::create(user_ios); if (!block_output_bufferfill) { @@ -863,12 +866,13 @@ static bool exec_block_or_func_process(parser_t &parser, std::shared_ptr /// Executes a process \p in job \j, using the pipes \p pipes (which may have invalid fds if this is /// the first or last process). -/// deferred_pipes represents the pipes from our deferred process; if set ensure they get closed in -/// any child. -/// \returns true on success, false on exec error. +/// \p deferred_pipes represents the pipes from our deferred process; if set ensure they get closed +/// in any child. If \p is_deferred_run is true, then this is a deferred run; this affects how +/// certain buffering works. \returns true on success, false on exec error. static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr j, autoclose_pipes_t pipes, const io_chain_t &all_ios, - const autoclose_pipes_t &deferred_pipes, size_t stdout_read_limit) { + const autoclose_pipes_t &deferred_pipes, size_t stdout_read_limit, + bool is_deferred_run = false) { // The write pipe (destined for stdout) needs to occur before redirections. For example, // with a redirection like this: // @@ -942,7 +946,11 @@ static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr< switch (p->type) { case process_type_t::function: case process_type_t::block_node: { - if (!exec_block_or_func_process(parser, j, p, all_ios, process_net_io_chain)) { + // Allow buffering unless this is a deferred run. If deferred, then processes after us + // were already launched, so they are ready to receive (or reject) our output. + bool allow_buffering = !is_deferred_run; + if (!exec_block_or_func_process(parser, j, p, all_ios, process_net_io_chain, + allow_buffering)) { return false; } break; @@ -1096,7 +1104,7 @@ bool exec_job(parser_t &parser, shared_ptr j) { if (!exec_error && deferred_process) { assert(deferred_pipes.write.valid() && "Deferred process should always have a write pipe"); if (!exec_process_in_job(parser, deferred_process, j, std::move(deferred_pipes), all_ios, - {}, stdout_read_limit)) { + {}, stdout_read_limit, true)) { exec_error = true; } } diff --git a/tests/test1.in b/tests/test1.in index f006e774a..41fc71caa 100644 --- a/tests/test1.in +++ b/tests/test1.in @@ -109,7 +109,7 @@ end echo Test 5 $sta logmsg Verify that we can turn stderr into stdout and then pipe it -# Note that the order here seems unspecified - 'errput' appears before 'output', why? +# Note that the order here has historically been unspecified - 'errput' could conceivably appear before 'output'. begin ; echo output ; echo errput 1>&2 ; end 2>&1 | tee ../test/temp/tee_test.txt ; cat ../test/temp/tee_test.txt logmsg "Test that trailing ^ doesn't trigger redirection, see #1873" diff --git a/tests/test1.out b/tests/test1.out index 6c141412d..8ac15efc6 100644 --- a/tests/test1.out +++ b/tests/test1.out @@ -44,10 +44,10 @@ Test 5 pass #################### # Verify that we can turn stderr into stdout and then pipe it -errput output errput output +errput #################### # Test that trailing ^ doesn't trigger redirection, see #1873 From 93d70fae11f25e2ca04dfcd055685a97b2aa0f60 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 24 Mar 2019 21:39:39 -0700 Subject: [PATCH 0154/1732] Relnote stop buffering deferred function processes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8311bbfde..e9649eb8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - `string replace` had an additional round of escaping in the replacement (not the match!), so escaping backslashes would require `string replace -ra '([ab])' '\\\\\\\$1' a`. A new feature flag `string-replace-fewer-backslashes` can be used to disable this, so that it becomes `string replace -ra '([ab])' '\\\\$1' a` (#5556). - Add `$pipestatus` support - macOS Mojave: fish.app can actually run (#5727), 10.14.4's Terminal.app no longer causes an error on launch (#5725) +- fish no longer requires buffering for the last function in a pipeline. ### Syntax changes and new commands - None yet. From ea3a368c50cd838ca43e49f0d7dafc3772f7b40c Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Mon, 25 Mar 2019 00:41:04 -0700 Subject: [PATCH 0155/1732] Make env_var_t store its values via shared_ptr This switches env_var_t to be an immutable value type, and stores its contents via a shared_ptr. This eliminates string copying when fetching env_var_t values. --- src/env.cpp | 25 +++++++++++++------------ src/env.h | 54 ++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/env.cpp b/src/env.cpp index 3cfe58715..4d338622d 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -1239,17 +1239,16 @@ int env_stack_t::set_internal(const wcstring &key, env_mode_flags_t input_var_mo has_changed_new = true; } - var.set_vals(std::move(val)); - var.set_pathvar(var_mode & ENV_PATHVAR); - var.set_read_only(is_read_only(key)); + var = var.setting_vals(std::move(val)) + .setting_exports(var_mode & ENV_EXPORT) + .setting_pathvar(var_mode & ENV_PATHVAR) + .setting_read_only(is_read_only(key)); if (var_mode & ENV_EXPORT) { // The new variable is exported. - var.set_exports(true); node->exportv = true; has_changed_new = true; } else { - var.set_exports(false); // Set the node's exported when it changes something about exports // (also when it redefines a variable to not be exported). node->exportv = has_changed_old != has_changed_new; @@ -1351,20 +1350,16 @@ int env_stack_t::remove(const wcstring &key, int var_mode) { return erased ? ENV_OK : ENV_NOT_FOUND; } -const wcstring_list_t &env_var_t::as_list() const { return vals; } +const wcstring_list_t &env_var_t::as_list() const { return *vals_; } wchar_t env_var_t::get_delimiter() const { return is_pathvar() ? PATH_ARRAY_SEP : NONPATH_ARRAY_SEP; } /// Return a string representation of the var. -wcstring env_var_t::as_string() const { - return join_strings(vals, get_delimiter()); -} +wcstring env_var_t::as_string() const { return join_strings(*vals_, get_delimiter()); } -void env_var_t::to_list(wcstring_list_t &out) const { - out = vals; -} +void env_var_t::to_list(wcstring_list_t &out) const { out = *vals_; } env_var_t::env_var_flags_t env_var_t::flags_for(const wchar_t *name) { env_var_flags_t result = 0; @@ -1372,6 +1367,12 @@ env_var_t::env_var_flags_t env_var_t::flags_for(const wchar_t *name) { return result; } +/// \return a singleton empty list, to avoid unnecessary allocations in env_var_t. +std::shared_ptr env_var_t::empty_list() { + static const auto result = std::make_shared(); + return result; +} + maybe_t env_stack_t::get(const wcstring &key, env_mode_flags_t mode) const { const bool has_scope = mode & (ENV_LOCAL | ENV_GLOBAL | ENV_UNIVERSAL); const bool search_local = !has_scope || (mode & ENV_LOCAL); diff --git a/src/env.h b/src/env.h index f5d240b84..be26aefa2 100644 --- a/src/env.h +++ b/src/env.h @@ -66,13 +66,22 @@ void env_init(const struct config_paths_t *paths = NULL); /// routines. void misc_init(); +/// env_var_t is an immutable value-type data structure representing the value of an environment +/// variable. class env_var_t { public: using env_var_flags_t = uint8_t; private: - wcstring_list_t vals; // list of values assigned to the var - env_var_flags_t flags; + env_var_t(std::shared_ptr vals, env_var_flags_t flags) + : vals_(std::move(vals)), flags_(flags) {} + + /// The list of values in this variable. + /// shared_ptr allows for cheap copying. + std::shared_ptr vals_{empty_list()}; + + /// Flag in this variable. + env_var_flags_t flags_{}; public: enum { @@ -82,24 +91,27 @@ class env_var_t { }; // Constructors. + env_var_t() = default; env_var_t(const env_var_t &) = default; env_var_t(env_var_t &&) = default; - env_var_t(wcstring_list_t vals, env_var_flags_t flags) : vals(std::move(vals)), flags(flags) {} + + env_var_t(wcstring_list_t vals, env_var_flags_t flags) + : env_var_t(std::make_shared(std::move(vals)), flags) {} + env_var_t(wcstring val, env_var_flags_t flags) : env_var_t(wcstring_list_t{std::move(val)}, flags) {} // Constructors that infer the flags from a name. env_var_t(const wchar_t *name, wcstring_list_t vals) : env_var_t(std::move(vals), flags_for(name)) {} + env_var_t(const wchar_t *name, wcstring val) : env_var_t(std::move(val), flags_for(name)) {} - env_var_t() = default; - - bool empty() const { return vals.empty() || (vals.size() == 1 && vals[0].empty()); } - bool read_only() const { return flags & flag_read_only; } - bool exports() const { return flags & flag_export; } - bool is_pathvar() const { return flags & flag_pathvar; } - env_var_flags_t get_flags() const { return flags; } + bool empty() const { return vals_->empty() || (vals_->size() == 1 && vals_->front().empty()); } + bool read_only() const { return flags_ & flag_read_only; } + bool exports() const { return flags_ & flag_export; } + bool is_pathvar() const { return flags_ & flag_pathvar; } + env_var_flags_t get_flags() const { return flags_; } wcstring as_string() const; void to_list(wcstring_list_t &out) const; @@ -108,38 +120,50 @@ class env_var_t { /// \return the character used when delimiting quoted expansion. wchar_t get_delimiter() const; - void set_vals(wcstring_list_t v) { vals = std::move(v); } + /// \return a copy of this variable with new values. + env_var_t setting_vals(wcstring_list_t vals) const { + return env_var_t{std::move(vals), flags_}; + } - void set_exports(bool exportv) { + env_var_t setting_exports(bool exportv) const { + env_var_flags_t flags = flags_; if (exportv) { flags |= flag_export; } else { flags &= ~flag_export; } + return env_var_t{vals_, flags}; } - void set_pathvar(bool pathvar) { + env_var_t setting_pathvar(bool pathvar) const { + env_var_flags_t flags = flags_; if (pathvar) { flags |= flag_pathvar; } else { flags &= ~flag_pathvar; } + return env_var_t{vals_, flags}; } - void set_read_only(bool read_only) { + env_var_t setting_read_only(bool read_only) const { + env_var_flags_t flags = flags_; if (read_only) { flags |= flag_read_only; } else { flags &= ~flag_read_only; } + return env_var_t{vals_, flags}; } static env_var_flags_t flags_for(const wchar_t *name); + static std::shared_ptr empty_list(); env_var_t &operator=(const env_var_t &var) = default; env_var_t &operator=(env_var_t &&) = default; - bool operator==(const env_var_t &rhs) const { return vals == rhs.vals && flags == rhs.flags; } + bool operator==(const env_var_t &rhs) const { + return *vals_ == *rhs.vals_ && flags_ == rhs.flags_; + } bool operator!=(const env_var_t &rhs) const { return ! (*this == rhs); } }; From 989f992a75f1a14e9ebbe95a0433cb9867f7c9e8 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Mon, 25 Mar 2019 00:49:52 -0700 Subject: [PATCH 0156/1732] Rearrange and inline some env code --- src/env.cpp | 182 ++++++++++++++++++++++++---------------------------- 1 file changed, 85 insertions(+), 97 deletions(-) diff --git a/src/env.cpp b/src/env.cpp index 4d338622d..1a4080d7d 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -136,7 +136,13 @@ class env_node_t { maybe_t find_entry(const wcstring &key); - bool contains_any_of(const wcstring_list_t &vars) const; + /// Return whether this node contains any of the entries in the vars list. + bool contains_any_of(const wcstring_list_t &vars) const { + for (const auto &v : vars) { + if (env.count(v)) return true; + } + return false; + } }; using env_node_ref_t = std::shared_ptr; @@ -175,18 +181,80 @@ struct var_stack_t { // Pushes a new node onto our stack // Optionally creates a new scope for the node - void push(bool new_scope); + void push(bool new_scope) { + auto node = std::make_shared(new_scope); + + // Copy local-exported variables. + auto top_node = top; + // Only if we introduce a new shadowing scope; i.e. not if it's just `begin; end` or + // "--no-scope-shadowing". + if (new_scope && top_node != this->global_env) { + for (const auto &var : top_node->env) { + if (var.second.exports()) node->env.insert(var); + } + } + + node->next = this->top; + this->top = node; + if (new_scope && local_scope_exports(this->top)) { + this->mark_changed_exported(); + } + } // Pops the top node if it's not global - void pop(); + void pop() { + // Don't pop the top-most, global, level. + if (top == this->global_env) { + debug(0, _(L"Tried to pop empty environment stack.")); + sanity_lose(); + return; + } + + bool locale_changed = top->contains_any_of(locale_variables); + bool curses_changed = top->contains_any_of(curses_variables); + + if (top->new_scope) { //!OCLINT(collapsible if statements) + if (top->exportv || local_scope_exports(top->next)) { + this->mark_changed_exported(); + } + } + + // Actually do the pop! + env_node_ref_t old_top = this->top; + this->top = old_top->next; + for (const auto &entry_pair : old_top->env) { + const env_var_t &var = entry_pair.second; + if (var.exports()) { + this->mark_changed_exported(); + break; + } + } + + // TODO: instantize this locale and curses + const auto &vars = env_stack_t::principal(); + if (locale_changed) init_locale(vars); + if (curses_changed) init_curses(vars); + } // Returns the next scope to search for a given node, respecting the new_scope flag. // Returns an empty pointer if we're done. - env_node_ref_t next_scope_to_search(const env_node_ref_t &node) const; + env_node_ref_t next_scope_to_search(const env_node_ref_t &node) const { + assert(node != NULL); + if (node == this->global_env) { + return nullptr; + } + return node->new_scope ? this->global_env : node->next; + } // Returns the scope used for unspecified scopes. An unspecified scope is either the topmost // shadowing scope, or the global scope if none. This implements the default behavior of `set`. - env_node_ref_t resolve_unspecified_scope(); + env_node_ref_t resolve_unspecified_scope() { + env_node_ref_t node = this->top; + while (node && !node->new_scope) { + node = node->next; + } + return node ? node : this->global_env; + } /// Copy this vars_stack. var_stack_t clone() const { @@ -201,100 +269,12 @@ struct var_stack_t { void get_exported(const env_node_t *n, var_table_t &h) const; /// Returns the global variable set. - static env_node_ref_t globals(); + static env_node_ref_t globals() { + static env_node_ref_t s_globals{std::make_shared(false)}; + return s_globals; + } }; -env_node_ref_t var_stack_t::globals() { - static env_node_ref_t s_globals{std::make_shared(false)}; - return s_globals; -} - -void var_stack_t::push(bool new_scope) { - auto node = std::make_shared(new_scope); - - // Copy local-exported variables. - auto top_node = top; - // Only if we introduce a new shadowing scope; i.e. not if it's just `begin; end` or - // "--no-scope-shadowing". - if (new_scope && top_node != this->global_env) { - for (const auto &var : top_node->env) { - if (var.second.exports()) node->env.insert(var); - } - } - - node->next = this->top; - this->top = node; - if (new_scope && local_scope_exports(this->top)) { - this->mark_changed_exported(); - } -} - -/// Return true if if the node contains any of the entries in the vars list. -bool env_node_t::contains_any_of(const wcstring_list_t &vars) const { - for (const auto &v : vars) { - if (env.count(v)) return true; - } - return false; -} - -void var_stack_t::pop() { - // Don't pop the top-most, global, level. - if (top == this->global_env) { - debug(0, _(L"Tried to pop empty environment stack.")); - sanity_lose(); - return; - } - - bool locale_changed = top->contains_any_of(locale_variables); - bool curses_changed = top->contains_any_of(curses_variables); - - if (top->new_scope) { //!OCLINT(collapsible if statements) - if (top->exportv || local_scope_exports(top->next)) { - this->mark_changed_exported(); - } - } - - // Actually do the pop! - env_node_ref_t old_top = this->top; - this->top = old_top->next; - for (const auto &entry_pair : old_top->env) { - const env_var_t &var = entry_pair.second; - if (var.exports()) { - this->mark_changed_exported(); - break; - } - } - - // TODO: instantize this locale and curses - const auto &vars = env_stack_t::principal(); - if (locale_changed) init_locale(vars); - if (curses_changed) init_curses(vars); -} - -env_node_ref_t var_stack_t::next_scope_to_search(const env_node_ref_t &node) const { - assert(node != NULL); - if (node == this->global_env) { - return nullptr; - } - return node->new_scope ? this->global_env : node->next; -} - -env_node_ref_t var_stack_t::resolve_unspecified_scope() { - env_node_ref_t node = this->top; - while (node && !node->new_scope) { - node = node->next; - } - return node ? node : this->global_env; -} - -env_stack_t::env_stack_t() : vars_(make_unique()) {} -env_stack_t::env_stack_t(std::unique_ptr vars) : vars_(std::move(vars)) {} - -// Get the variable stack -var_stack_t &env_stack_t::vars_stack() { return *vars_; } - -const var_stack_t &env_stack_t::vars_stack() const { return *vars_; } - /// Universal variables global instance. Initialized in env_init. static env_universal_t *s_universal_variables = NULL; @@ -334,6 +314,14 @@ static const string_set_t env_electric = {L"history", L"pipestatus", L"status", static bool is_electric(const wcstring &key) { return contains(env_electric, key); } +env_stack_t::env_stack_t() : vars_(make_unique()) {} +env_stack_t::env_stack_t(std::unique_ptr vars) : vars_(std::move(vars)) {} + +// Get the variable stack +var_stack_t &env_stack_t::vars_stack() { return *vars_; } + +const var_stack_t &env_stack_t::vars_stack() const { return *vars_; } + maybe_t env_node_t::find_entry(const wcstring &key) { var_table_t::const_iterator entry = env.find(key); if (entry != env.end()) return entry->second; From eeec6cc2fc7e0636d8ea9f50f1fa62a65db1472a Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Mon, 25 Mar 2019 02:26:50 -0700 Subject: [PATCH 0157/1732] Remove a single use of env_stack_t::principal --- src/builtin_read.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/builtin_read.cpp b/src/builtin_read.cpp index a0f1ab91a..077bf164d 100644 --- a/src/builtin_read.cpp +++ b/src/builtin_read.cpp @@ -198,13 +198,12 @@ static int parse_cmd_opts(read_cmd_opts_t &opts, int *optind, //!OCLINT(high nc /// Read from the tty. This is only valid when the stream is stdin and it is attached to a tty and /// we weren't asked to split on null characters. -static int read_interactive(wcstring &buff, int nchars, bool shell, bool silent, +static int read_interactive(parser_t &parser, wcstring &buff, int nchars, bool shell, bool silent, const wchar_t *prompt, const wchar_t *right_prompt, const wchar_t *commandline) { int exit_res = STATUS_CMD_OK; - // TODO: rationalize this. - const auto &vars = env_stack_t::principal(); + const auto &vars = parser.vars(); wcstring read_history_ID = history_session_id(vars); if (!read_history_ID.empty()) read_history_ID += L"_read"; reader_push(read_history_ID); @@ -469,8 +468,8 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) { int stream_stdin_is_a_tty = isatty(streams.stdin_fd); if (stream_stdin_is_a_tty && !opts.split_null) { // Read interactively using reader_readline(). This does not support splitting on null. - exit_res = read_interactive(buff, opts.nchars, opts.shell, opts.silent, opts.prompt, - opts.right_prompt, opts.commandline); + exit_res = read_interactive(parser, buff, opts.nchars, opts.shell, opts.silent, + opts.prompt, opts.right_prompt, opts.commandline); } else if (!opts.nchars && !stream_stdin_is_a_tty && lseek(streams.stdin_fd, 0, SEEK_CUR) != -1) { exit_res = read_in_chunks(streams.stdin_fd, buff, opts.split_null); From b86200938f8b9e9a2016cb2130c14d0bd3193a2f Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 26 Mar 2019 10:11:36 +0100 Subject: [PATCH 0158/1732] Always use "." for cd Nobody doesn't want to use $PWD to cd, so if $CDPATH does not include it that was a mistake. Bash also appends "." here. Fixes #4484. --- CHANGELOG.md | 1 + sphinx_doc_src/cmds/cd.rst | 2 +- src/path.cpp | 5 ++--- tests/cd.err | 3 +++ tests/cd.in | 10 ++++++++++ tests/cd.out | 6 ++++++ 6 files changed, 23 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9649eb8f..99c4789e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Add `$pipestatus` support - macOS Mojave: fish.app can actually run (#5727), 10.14.4's Terminal.app no longer causes an error on launch (#5725) - fish no longer requires buffering for the last function in a pipeline. +- cd now always checks the current directory, even if $CDPATH does not include it or "." (#4484). ### Syntax changes and new commands - None yet. diff --git a/sphinx_doc_src/cmds/cd.rst b/sphinx_doc_src/cmds/cd.rst index 2a6fcc748..623d853b8 100644 --- a/sphinx_doc_src/cmds/cd.rst +++ b/sphinx_doc_src/cmds/cd.rst @@ -13,7 +13,7 @@ Description If ``DIRECTORY`` is supplied, it will become the new directory. If no parameter is given, the contents of the ``HOME`` environment variable will be used. -If ``DIRECTORY`` is a relative path, the paths found in the ``CDPATH`` environment variable array will be tried as prefixes for the specified path. +If ``DIRECTORY`` is a relative path, the paths found in the ``CDPATH`` list will be tried as prefixes for the specified path, in addition to $PWD. Note that the shell will attempt to change directory without requiring ``cd`` if the name of a directory is provided (starting with ``.``, ``/`` or ``~``, or ending with ``/``). diff --git a/src/path.cpp b/src/path.cpp index 8349dd50e..937738664 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -173,9 +173,8 @@ maybe_t path_get_cdpath(const wcstring &dir, const wcstring &wd, if (auto cdpaths = env_vars.get(L"CDPATH")) { cdpathsv = cdpaths->as_list(); } - if (cdpathsv.empty()) { - cdpathsv.push_back(L"."); - } + // Always append $PWD + cdpathsv.push_back(L"."); for (wcstring next_path : cdpathsv) { if (next_path.empty()) next_path = L"."; if (next_path == L"." && !wd.empty()) { diff --git a/tests/cd.err b/tests/cd.err index 4653e2ee6..fae7b99e0 100644 --- a/tests/cd.err +++ b/tests/cd.err @@ -7,3 +7,6 @@ #################### # Virtual PWD inheritance + +#################### +# CDPATH diff --git a/tests/cd.in b/tests/cd.in index 2d02d269c..e70a7f902 100644 --- a/tests/cd.in +++ b/tests/cd.in @@ -62,6 +62,16 @@ test (realpath $output_pwd) = $real_getcwd and echo "BogusPWD test 2 succeeded" or echo "BogusPWD test 2 failed: $output_pwd vs $real_getcwd" +# $CDPATH +logmsg CDPATH +set -g CDPATH $base +cd linkhome +test $PWD = $base/linkhome; and echo Gone to linkhome via CDPATH +set -g CDPATH /tmp +cd $base +test $PWD = $base; and echo Gone to base +cd linkhome +test $PWD = $base/linkhome; and echo Gone to linkhome via implicit . in CDPATH # cd back before removing the test directory again. cd $oldpwd diff --git a/tests/cd.out b/tests/cd.out index 8fd581f17..d3801a10a 100644 --- a/tests/cd.out +++ b/tests/cd.out @@ -23,3 +23,9 @@ cd: PWD is /tmp/cdcomp_test/linkhome BogusPWD test 1 succeeded BogusPWD test 2 succeeded + +#################### +# CDPATH +Gone to linkhome via CDPATH +Gone to base +Gone to linkhome via implicit . in CDPATH From 39a601927f6f10240a971ef10e4e64d20fe1c6f4 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 26 Mar 2019 16:36:28 +0100 Subject: [PATCH 0159/1732] Remove useless empty lines from stack traces This printed things like ``` in function 'f' called on standard input in function 'd' called on standard input in function 'b' called on standard input in function 'a' called on standard input ``` As a first step, it removes the empty lines so it's now ``` in function 'f' called on standard input in function 'd' called on standard input in function 'b' called on standard input in function 'a' called on standard input ``` See #5434. --- src/parser.cpp | 2 -- tests/invocation/broken-config-continues.err | 1 - 2 files changed, 3 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 572f9b5bb..8e8c71138 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -416,8 +416,6 @@ void parser_t::stack_trace_internal(size_t block_idx, wcstring *buff) const { append_format(*buff, _(L"\twith parameter list '%ls'\n"), tmp.c_str()); } } - - append_format(*buff, L"\n"); } // Recursively print the next block. diff --git a/tests/invocation/broken-config-continues.err b/tests/invocation/broken-config-continues.err index c4165a1a8..d15aebbd8 100644 --- a/tests/invocation/broken-config-continues.err +++ b/tests/invocation/broken-config-continues.err @@ -4,4 +4,3 @@ syntax-error ^ from sourcing file $XDG_CONFIG_HOME/fish/config.fish called during startup - From 71a2337c5f8f0e2ebecc30aca9d1e151110cd9de Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 26 Mar 2019 17:18:07 +0100 Subject: [PATCH 0160/1732] Remove stray newlines in test Sorry! --- tests/test_cmdsub.err | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_cmdsub.err b/tests/test_cmdsub.err index 1d39d0ae7..5ef37be88 100644 --- a/tests/test_cmdsub.err +++ b/tests/test_cmdsub.err @@ -18,11 +18,9 @@ fish: Too much data emitted by command substitution so it was discarded in function 'subme' called on standard input with parameter list '513' - in command substitution called on standard input - #################### # Make sure output from builtins outside of command substitution is not affected From e723f02aa7969415dc11ef9fe4d80666aad6f830 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 26 Mar 2019 17:10:45 +0100 Subject: [PATCH 0161/1732] Remove empty line also for event handlers --- src/parser.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/parser.cpp b/src/parser.cpp index 8e8c71138..ba0da627a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -355,7 +355,6 @@ void parser_t::stack_trace_internal(size_t block_idx, wcstring *buff) const { const event_block_t *eb = static_cast(b); wcstring description = event_get_desc(eb->event); append_format(*buff, _(L"in event handler: %ls\n"), description.c_str()); - buff->append(L"\n"); // Stop recursing at event handler. No reason to believe that any other code is relevant. // From 975023faf273243b1673d4267c94f75a60590849 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 26 Mar 2019 17:15:51 +0100 Subject: [PATCH 0162/1732] Print arguments on the same line as the function Now: ``` cd: Unknown option '-r' ~/dev/fish-shell/share/functions/cd.fish (line 40): builtin cd $argv ^ in function 'cd' with arguments '-r' in function 'f' in function 'd' in function 'b' with arguments '-1q --wurst' in function 'a' called on standard input ``` See #5434. --- src/parser.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index ba0da627a..bbc1edf3a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -379,7 +379,21 @@ void parser_t::stack_trace_internal(size_t block_idx, wcstring *buff) const { case FUNCTION_CALL: case FUNCTION_CALL_NO_SHADOW: { const function_block_t *fb = static_cast(b); - append_format(*buff, _(L"in function '%ls'\n"), fb->name.c_str()); + append_format(*buff, _(L"in function '%ls'"), fb->name.c_str()); + const process_t *const process = fb->process; + // Print arguments on the same line. + if (process->argv(1)) { + wcstring tmp; + + for (i = 1; process->argv(i); i++) { + if (i > 1) tmp.push_back(L' '); + tmp.append(process->argv(i)); + } + // TODO: Escape these. + append_format(*buff, _(L" with arguments '%ls'\n"), tmp.c_str()); + } else { + buff->append(L"\n"); + } break; } case SUBST: { @@ -402,19 +416,6 @@ void parser_t::stack_trace_internal(size_t block_idx, wcstring *buff) const { append_format(*buff, _(L"\tcalled on standard input\n")); } - if (b->type() == FUNCTION_CALL) { - const function_block_t *fb = static_cast(b); - const process_t *const process = fb->process; - if (process->argv(1)) { - wcstring tmp; - - for (i = 1; process->argv(i); i++) { - if (i > 1) tmp.push_back(L' '); - tmp.append(process->argv(i)); - } - append_format(*buff, _(L"\twith parameter list '%ls'\n"), tmp.c_str()); - } - } } // Recursively print the next block. From 7095de628c8f05b2142827a74511cd1c979c5c90 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 26 Mar 2019 17:10:56 +0100 Subject: [PATCH 0163/1732] Remove "called on standard input" message This was printed basically everywhere. The user knows what they executed on standard input. A good example: ```fish set c (subme 513) ``` used to print ``` fish: Too much data emitted by command substitution so it was discarded set -l x (string repeat -n $argv x) ^ in function 'subme' called on standard input with parameter list '513' in command substitution called on standard input ``` and now it is ``` fish: Too much data emitted by command substitution so it was discarded set -l x (string repeat -n $argv x) ^ in function 'subme' with arguments '513' in command substitution ``` See #5434. --- src/parser.cpp | 5 +++-- tests/test_cmdsub.err | 5 +---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index bbc1edf3a..a920b477d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -405,6 +405,7 @@ void parser_t::stack_trace_internal(size_t block_idx, wcstring *buff) const { } } + // Print where the function is called. const wchar_t *file = b->src_filename; if (file) { @@ -413,9 +414,9 @@ void parser_t::stack_trace_internal(size_t block_idx, wcstring *buff) const { } else if (is_within_fish_initialization()) { append_format(*buff, _(L"\tcalled during startup\n")); } else { - append_format(*buff, _(L"\tcalled on standard input\n")); + // This one is way too noisy + // append_format(*buff, _(L"\tcalled on standard input\n")); } - } // Recursively print the next block. diff --git a/tests/test_cmdsub.err b/tests/test_cmdsub.err index 5ef37be88..62819c597 100644 --- a/tests/test_cmdsub.err +++ b/tests/test_cmdsub.err @@ -15,11 +15,8 @@ fish: Too much data emitted by command substitution so it was discarded set -l x (string repeat -n $argv x) ^ -in function 'subme' - called on standard input - with parameter list '513' +in function 'subme' with arguments '513' in command substitution - called on standard input #################### # Make sure output from builtins outside of command substitution is not affected From 88a935d8d1c63b18b240ad1a4d8196fc84f6b4c3 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 26 Mar 2019 17:45:25 +0100 Subject: [PATCH 0164/1732] Escape arguments in stacktraces See #5434. --- src/parser.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/parser.cpp b/src/parser.cpp index a920b477d..15871ed03 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -387,7 +387,13 @@ void parser_t::stack_trace_internal(size_t block_idx, wcstring *buff) const { for (i = 1; process->argv(i); i++) { if (i > 1) tmp.push_back(L' '); - tmp.append(process->argv(i)); + // We can't quote the arguments because we print this in quotes. + // As a special-case, add the empty argument as "". + if (process->argv(i)[0]) { + tmp.append(escape_string(process->argv(i), ESCAPE_ALL | ESCAPE_NO_QUOTED)); + } else { + tmp.append(L"\"\""); + } } // TODO: Escape these. append_format(*buff, _(L" with arguments '%ls'\n"), tmp.c_str()); From 88d2d54276c8c7cb9423b6e9f8868789e8ef85b3 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 26 Mar 2019 19:13:01 +0100 Subject: [PATCH 0165/1732] Stop printing help summary on error This now displays - the error message - a (significantly shorter) backtrace - A call to open `help $cmd` if necessary See #5434. Fixes #3404. --- src/builtin.cpp | 85 +++++-------------------------------- src/builtin.h | 2 + src/builtin_argparse.cpp | 8 +++- src/builtin_commandline.cpp | 16 +++---- src/builtin_complete.cpp | 2 +- src/builtin_disown.cpp | 2 +- src/builtin_exit.cpp | 4 +- src/builtin_fg.cpp | 4 +- src/builtin_function.cpp | 2 +- src/builtin_functions.cpp | 14 +++--- src/builtin_read.cpp | 12 +++--- src/builtin_return.cpp | 6 +-- src/builtin_set.cpp | 34 +++++++-------- src/builtin_ulimit.cpp | 6 +-- tests/string.err | 6 --- 15 files changed, 71 insertions(+), 132 deletions(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index 6efffd6b3..f30162799 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -187,92 +187,29 @@ wcstring builtin_help_get(parser_t &parser, io_streams_t &streams, const wchar_t /// void builtin_print_help(parser_t &parser, io_streams_t &streams, const wchar_t *cmd, output_stream_t &b) { - bool is_stderr = &b == &streams.err; - if (is_stderr) { - b.append(parser.current_line()); - } - - const wcstring h = builtin_help_get(parser, streams, cmd); - - if (!h.size()) return; - - wchar_t *str = wcsdup(h.c_str()); - if (str) { - bool is_short = false; - if (is_stderr) { - // Interactive mode help to screen - only print synopsis if the rest won't fit. - int screen_height, my_lines; - - screen_height = common_get_height(); - my_lines = count_char(str, L'\n'); - if (!shell_is_interactive() || (my_lines > 2 * screen_height / 3)) { - wchar_t *pos; - int cut = 0; - int i; - - is_short = true; - - // First move down 4 lines. - pos = str; - for (i = 0; (i < 4) && pos && *pos; i++) { - pos = std::wcschr(pos + 1, L'\n'); - } - - if (pos && *pos) { - // Then find the next empty line. - for (; *pos; pos++) { - if (*pos != L'\n') { - continue; - } - - int is_empty = 1; - wchar_t *pos2; - for (pos2 = pos + 1; *pos2; pos2++) { - if (*pos2 == L'\n') break; - - if (*pos2 != L'\t' && *pos2 != L' ') { - is_empty = 0; - break; - } - } - if (is_empty) { - // And cut it. - *(pos2 + 1) = L'\0'; - cut = 1; - break; - } - } - } - - // We did not find a good place to cut message to shorten it - so we make sure we - // don't print anything. - if (!cut) { - *str = 0; - } - } - } - - b.append(str); - if (is_short) { - b.append_format(_(L"%ls: Type 'help %ls' for related documentation\n\n"), cmd, cmd); - } - - free(str); - } + b.append(builtin_help_get(parser, streams, cmd)); } /// Perform error reporting for encounter with unknown option. void builtin_unknown_option(parser_t &parser, io_streams_t &streams, const wchar_t *cmd, const wchar_t *opt) { streams.err.append_format(BUILTIN_ERR_UNKNOWN, cmd, opt); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); } /// Perform error reporting for encounter with missing argument. void builtin_missing_argument(parser_t &parser, io_streams_t &streams, const wchar_t *cmd, const wchar_t *opt) { streams.err.append_format(BUILTIN_ERR_MISSING, cmd, opt); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); +} + +/// Print the backtrace and call for help that we use at the end of error messages. +void builtin_print_error_trailer(parser_t &parser, output_stream_t &b, const wchar_t *cmd) { + b.append(L"\n"); + b.append(parser.current_line()); + b.append(L"\n"); + b.append_format(_(L"(Type 'help %ls' for related documentation)\n"), cmd); } /// A generic bultin that only supports showing a help message. This is only a placeholder that diff --git a/src/builtin.h b/src/builtin.h index 8e5fd5e18..6185267bf 100644 --- a/src/builtin.h +++ b/src/builtin.h @@ -115,6 +115,8 @@ void builtin_unknown_option(parser_t &parser, io_streams_t &streams, const wchar void builtin_missing_argument(parser_t &parser, io_streams_t &streams, const wchar_t *cmd, const wchar_t *opt); +void builtin_print_error_trailer(parser_t &parser, output_stream_t &b, const wchar_t *cmd); + void builtin_wperror(const wchar_t *s, io_streams_t &streams); struct help_only_cmd_opts_t { diff --git a/src/builtin_argparse.cpp b/src/builtin_argparse.cpp index 9c6d930a3..4c70fd657 100644 --- a/src/builtin_argparse.cpp +++ b/src/builtin_argparse.cpp @@ -548,7 +548,13 @@ static int argparse_parse_flags(parser_t &parser, const argparse_cmd_opts_t &opt retval = validate_and_store_implicit_int(parser, opts, arg_contents, w, long_idx, streams); } else { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]); + streams.err.append_format(BUILTIN_ERR_UNKNOWN, cmd, argv[w.woptind - 1]); + // We don't use builtin_print_error_trailer as that + // says to use the cmd help, + // which doesn't work if it's a command that does not belong to fish. + // + // Plus this particular error is not an error in argparse usage. + streams.err.append(parser.current_line()); retval = STATUS_INVALID_ARGS; } if (retval != STATUS_CMD_OK) return retval; diff --git a/src/builtin_commandline.cpp b/src/builtin_commandline.cpp index a4fb80f46..d37e87384 100644 --- a/src/builtin_commandline.cpp +++ b/src/builtin_commandline.cpp @@ -196,7 +196,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) streams.err.append(argv[0]); streams.err.append(L": Can not set commandline in non-interactive mode\n"); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_ERROR; } @@ -315,7 +315,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) if (buffer_part || cut_at_cursor || append_mode || tokenize || cursor_mode || line_mode || search_mode || paging_mode) { streams.err.append_format(BUILTIN_ERR_COMBO, argv[0]); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -331,7 +331,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) input_queue_ch(*mc); } else { streams.err.append_format(_(L"%ls: Unknown input function '%ls'"), cmd, argv[i]); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } } @@ -351,14 +351,14 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) // Check for invalid switch combinations. if ((search_mode || line_mode || cursor_mode || paging_mode) && (argc - w.woptind > 1)) { streams.err.append_format(L"%ls: Too many arguments", argv[0]); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } if ((buffer_part || tokenize || cut_at_cursor) && (cursor_mode || line_mode || search_mode || paging_mode)) { streams.err.append_format(BUILTIN_ERR_COMBO, argv[0]); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -366,7 +366,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) streams.err.append_format( BUILTIN_ERR_COMBO2, cmd, L"--cut-at-cursor and --tokenize can not be used when setting the commandline"); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -374,7 +374,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) streams.err.append_format( BUILTIN_ERR_COMBO2, cmd, L"insertion mode switches can not be used when not in insertion mode"); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -392,7 +392,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) long new_pos = fish_wcstol(argv[w.woptind]); if (errno) { streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, cmd, argv[w.woptind]); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); } current_buffer = reader_get_buffer(); diff --git a/src/builtin_complete.cpp b/src/builtin_complete.cpp index c96571210..c3b25cc75 100644 --- a/src/builtin_complete.cpp +++ b/src/builtin_complete.cpp @@ -270,7 +270,7 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (w.woptind != argc) { streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } diff --git a/src/builtin_disown.cpp b/src/builtin_disown.cpp index 382c95099..52e2c995b 100644 --- a/src/builtin_disown.cpp +++ b/src/builtin_disown.cpp @@ -19,7 +19,7 @@ static int disown_job(const wchar_t *cmd, parser_t &parser, io_streams_t &streams, job_t *j) { if (j == 0) { streams.err.append_format(_(L"%ls: Unknown job '%ls'\n"), L"bg"); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } diff --git a/src/builtin_exit.cpp b/src/builtin_exit.cpp index d089598ae..9337f7e23 100644 --- a/src/builtin_exit.cpp +++ b/src/builtin_exit.cpp @@ -73,7 +73,7 @@ int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (optind + 1 < argc) { streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -84,7 +84,7 @@ int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (errno) { streams.err.append_format(_(L"%ls: Argument '%ls' must be an integer\n"), cmd, argv[optind]); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } } diff --git a/src/builtin_fg.cpp b/src/builtin_fg.cpp index a89f45866..8a915ecc1 100644 --- a/src/builtin_fg.cpp +++ b/src/builtin_fg.cpp @@ -68,14 +68,14 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { streams.err.append_format(_(L"%ls: '%ls' is not a job\n"), cmd, argv[optind]); } - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); j = 0; } else { int pid = abs(fish_wcstoi(argv[optind])); if (errno) { streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, cmd, argv[optind]); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); } else { j = job_t::from_pid(pid); if (!j || !j->is_constructed() || j->is_completed()) { diff --git a/src/builtin_function.cpp b/src/builtin_function.cpp index 104a728d8..db9777f32 100644 --- a/src/builtin_function.cpp +++ b/src/builtin_function.cpp @@ -230,7 +230,7 @@ int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_lis if (retval != STATUS_CMD_OK) return retval; if (opts.print_help) { - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_OK; } diff --git a/src/builtin_functions.cpp b/src/builtin_functions.cpp index c9d02753b..91b334e6e 100644 --- a/src/builtin_functions.cpp +++ b/src/builtin_functions.cpp @@ -282,7 +282,7 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) { bool describe = opts.description ? true : false; if (describe + opts.erase + opts.list + opts.query + opts.copy > 1) { streams.err.append_format(_(L"%ls: Invalid combination of options\n"), cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -296,14 +296,14 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (argc - optind != 1) { streams.err.append_format(_(L"%ls: Expected exactly one function name\n"), cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } func = argv[optind]; if (!function_exists(func)) { streams.err.append_format(_(L"%ls: Function '%ls' does not exist\n"), cmd, func); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_ERROR; } @@ -370,7 +370,7 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) { streams.err.append_format(_(L"%ls: Expected exactly two names (current function name, " L"and new function name)\n"), cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } current_func = argv[optind]; @@ -379,14 +379,14 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (!function_exists(current_func)) { streams.err.append_format(_(L"%ls: Function '%ls' does not exist\n"), cmd, current_func.c_str()); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_ERROR; } if (!valid_func_name(new_func) || parser_keywords_is_reserved(new_func)) { streams.err.append_format(_(L"%ls: Illegal function name '%ls'\n"), cmd, new_func.c_str()); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -395,7 +395,7 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) { streams.err.append_format( _(L"%ls: Function '%ls' already exists. Cannot create copy '%ls'\n"), cmd, new_func.c_str(), current_func.c_str()); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_ERROR; } diff --git a/src/builtin_read.cpp b/src/builtin_read.cpp index 077bf164d..ec8dc974a 100644 --- a/src/builtin_read.cpp +++ b/src/builtin_read.cpp @@ -130,13 +130,13 @@ static int parse_cmd_opts(read_cmd_opts_t &opts, int *optind, //!OCLINT(high nc if (errno == ERANGE) { streams.err.append_format(_(L"%ls: Argument '%ls' is out of range\n"), cmd, w.woptarg); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } streams.err.append_format(_(L"%ls: Argument '%ls' must be an integer\n"), cmd, w.woptarg); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } break; @@ -351,7 +351,7 @@ static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int arg const wchar_t *const *argv, parser_t &parser, io_streams_t &streams) { if (opts.prompt && opts.prompt_str) { streams.err.append_format(_(L"%ls: Options %ls and %ls cannot be used together\n"), cmd, L"-p", L"-P"); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -373,7 +373,7 @@ static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int arg if ((opts.place & ENV_UNEXPORT) && (opts.place & ENV_EXPORT)) { streams.err.append_format(BUILTIN_ERR_EXPUNEXP, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -381,7 +381,7 @@ static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int arg (opts.place & ENV_UNIVERSAL ? 1 : 0) > 1) { streams.err.append_format(BUILTIN_ERR_GLOCAL, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -404,7 +404,7 @@ static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int arg for (int i = 0; i < argc; i++) { if (!valid_var_name(argv[i])) { streams.err.append_format(BUILTIN_ERR_VARNAME, cmd, argv[i]); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } } diff --git a/src/builtin_return.cpp b/src/builtin_return.cpp index 27ce2beda..32a201af8 100644 --- a/src/builtin_return.cpp +++ b/src/builtin_return.cpp @@ -73,7 +73,7 @@ int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (optind + 1 < argc) { streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -83,7 +83,7 @@ int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) { retval = fish_wcstoi(argv[1]); if (errno) { streams.err.append_format(_(L"%ls: Argument '%ls' must be an integer\n"), cmd, argv[1]); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } retval &= 0xFF; @@ -98,7 +98,7 @@ int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (function_block_idx >= parser.block_count()) { streams.err.append_format(_(L"%ls: Not inside of function\n"), cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_ERROR; } diff --git a/src/builtin_set.cpp b/src/builtin_set.cpp index 3a18e5a09..f435bbff7 100644 --- a/src/builtin_set.cpp +++ b/src/builtin_set.cpp @@ -175,42 +175,42 @@ static int validate_cmd_opts(const wchar_t *cmd, set_cmd_opts_t &opts, //!OCLIN // Can't query and erase or list. if (opts.query && (opts.erase || opts.list)) { streams.err.append_format(BUILTIN_ERR_COMBO, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } // We can't both list and erase variables. if (opts.erase && opts.list) { streams.err.append_format(BUILTIN_ERR_COMBO, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } // Variables can only have one scope. if (opts.local + opts.global + opts.universal > 1) { streams.err.append_format(BUILTIN_ERR_GLOCAL, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } // Variables can only have one export status. if (opts.exportv && opts.unexport) { streams.err.append_format(BUILTIN_ERR_EXPUNEXP, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } // Variables can only have one path status. if (opts.pathvar && opts.unpathvar) { streams.err.append_format(BUILTIN_ERR_EXPUNEXP, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } // Trying to erase and (un)export at the same time doesn't make sense. if (opts.erase && (opts.exportv || opts.unexport)) { streams.err.append_format(BUILTIN_ERR_COMBO, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -218,13 +218,13 @@ static int validate_cmd_opts(const wchar_t *cmd, set_cmd_opts_t &opts, //!OCLIN if (opts.show && (opts.local || opts.global || opts.erase || opts.list || opts.exportv || opts.universal)) { streams.err.append_format(BUILTIN_ERR_COMBO, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } if (argc == 0 && opts.erase) { streams.err.append_format(BUILTIN_SET_ERASE_NO_VAR, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -519,7 +519,7 @@ static int builtin_set_query(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, int idx_count = parse_index(indexes, dest, scope, streams, parser.vars()); if (idx_count == -1) { free(dest); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_ERROR; } @@ -612,7 +612,7 @@ static int builtin_set_show(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, if (std::wcschr(arg, L'[')) { streams.err.append_format( _(L"%ls: `set --show` does not allow slices with the var names\n"), cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_ERROR; } @@ -631,7 +631,7 @@ static int builtin_set_erase(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, parser_t &parser, io_streams_t &streams) { if (argc != 1) { streams.err.append_format(BUILTIN_ERR_ARG_COUNT2, cmd, L"--erase", 1, argc); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_ERROR; } @@ -641,14 +641,14 @@ static int builtin_set_erase(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, std::vector indexes; int idx_count = parse_index(indexes, dest, scope, streams, parser.vars()); if (idx_count == -1) { - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_ERROR; } int retval; if (!valid_var_name(dest)) { streams.err.append_format(BUILTIN_ERR_VARNAME, cmd, dest); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -709,7 +709,7 @@ static int set_var_slices(const wchar_t *cmd, set_cmd_opts_t &opts, const wchar_ if (opts.append || opts.prepend) { streams.err.append_format( L"%ls: Cannot use --append or --prepend when assigning to a slice", cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -740,7 +740,7 @@ static int builtin_set_set(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, w parser_t &parser, io_streams_t &streams) { if (argc == 0) { streams.err.append_format(BUILTIN_ERR_MIN_ARG_COUNT1, cmd, 1); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -752,13 +752,13 @@ static int builtin_set_set(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, w std::vector indexes; int idx_count = parse_index(indexes, varname, scope, streams, parser.vars()); if (idx_count == -1) { - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } if (!valid_var_name(varname)) { streams.err.append_format(BUILTIN_ERR_VARNAME, cmd, varname); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } diff --git a/src/builtin_ulimit.cpp b/src/builtin_ulimit.cpp index 553c35514..40fe6bfef 100644 --- a/src/builtin_ulimit.cpp +++ b/src/builtin_ulimit.cpp @@ -269,7 +269,7 @@ int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) { return STATUS_CMD_OK; } else if (arg_count != 1) { streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } @@ -282,7 +282,7 @@ int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) { rlim_t new_limit; if (*argv[w.woptind] == L'\0') { streams.err.append_format(_(L"%ls: New limit cannot be an empty string\n"), cmd); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } else if (wcscasecmp(argv[w.woptind], L"unlimited") == 0) { new_limit = RLIM_INFINITY; @@ -294,7 +294,7 @@ int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) { new_limit = fish_wcstol(argv[w.woptind]); if (errno) { streams.err.append_format(_(L"%ls: Invalid limit '%ls'\n"), cmd, argv[w.woptind]); - builtin_print_help(parser, streams, cmd, streams.err); + builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } new_limit *= get_multiplier(what); diff --git a/tests/string.err b/tests/string.err index 0b2106c73..d291768ce 100644 --- a/tests/string.err +++ b/tests/string.err @@ -185,9 +185,6 @@ string match: ^ #################### # string invalidarg string: Subcommand 'invalidarg' is not valid -Standard input (line 211): -string invalidarg; and echo "unexpected exit 0" -^ #################### # string length @@ -270,9 +267,6 @@ string repeat: Expected argument #################### # string repeat -l fakearg 2>&1 string repeat: Unknown option '-l' -Standard input (line 287): -string repeat -l fakearg -^ #################### # string repeat "" From 7fa454666d55264d6b8f78af302298694b21dee7 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 26 Mar 2019 19:29:44 +0100 Subject: [PATCH 0166/1732] Only append newline if stacktrace isn't empty This printed weird things like ```fish $ functions -x functions: Unknown option '-x' (Type 'help functions' for related documentation) ``` Instead, let's make it ```fish $ functions -x functions: Unknown option '-x' (Type 'help functions' for related documentation) ``` --- src/builtin.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index f30162799..347f5c216 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -207,8 +207,12 @@ void builtin_missing_argument(parser_t &parser, io_streams_t &streams, const wch /// Print the backtrace and call for help that we use at the end of error messages. void builtin_print_error_trailer(parser_t &parser, output_stream_t &b, const wchar_t *cmd) { b.append(L"\n"); - b.append(parser.current_line()); - b.append(L"\n"); + const wcstring stacktrace = parser.current_line(); + // Don't print two empty lines if we don't have a stacktrace. + if (!stacktrace.empty()) { + b.append(stacktrace); + b.append(L"\n"); + } b.append_format(_(L"(Type 'help %ls' for related documentation)\n"), cmd); } From 54156845e43a653ea74afbc34871193cc093709f Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 26 Mar 2019 19:33:20 +0100 Subject: [PATCH 0167/1732] CHANGELOG error changes [ci skip] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99c4789e3..b2d167ff4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - macOS Mojave: fish.app can actually run (#5727), 10.14.4's Terminal.app no longer causes an error on launch (#5725) - fish no longer requires buffering for the last function in a pipeline. - cd now always checks the current directory, even if $CDPATH does not include it or "." (#4484). +- Error messages no longer include a (rather large) help summary and the stacktrace has been shortened (#3404, #5434). ### Syntax changes and new commands - None yet. From 248200520e1c4a9e9a69f1aa9d486f2923012c04 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 27 Mar 2019 09:03:17 +0100 Subject: [PATCH 0168/1732] functions/help: Prefer xdg-open/cygstart over open Some systems like Debian have "open" as a symlink to "openvt" (for... historical reasons). See #5756. [ci skip] --- share/functions/help.fish | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/share/functions/help.fish b/share/functions/help.fish index 977818ed7..99ca6a884 100644 --- a/share/functions/help.fish +++ b/share/functions/help.fish @@ -54,6 +54,16 @@ function help --description 'Show help for the fish shell' end end + # If we have an open _command_ we use it - otherwise it's our function, + # which might not have a backend to use. + # Note that we prefer xdg-open, because this open might also be a symlink to "openvt" + # like it is on Debian. + if command -sq open + set fish_browser open + # The open command needs a trampoline because the macOS version can't handle #-fragments. + set need_trampoline 1 + end + # If the OS appears to be Windows (graphical), try to use cygstart if type -q cygstart set fish_browser cygstart @@ -62,14 +72,6 @@ function help --description 'Show help for the fish shell' else if type -q xdg-open; and set -q -x DISPLAY set fish_browser xdg-open end - - # If we have an open _command_ we use it - otherwise it's our function, - # which might not have a backend to use. - if command -sq open - set fish_browser open - # The open command needs a trampoline because the macOS version can't handle #-fragments. - set need_trampoline 1 - end end end From 2a51e42ee02e8f0d4043addc1e0c610a54f64e07 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 22 Mar 2019 17:24:10 +0100 Subject: [PATCH 0169/1732] functions/help: Try harder to find a browser on WSL We now try cmd.exe via $PATH and via a common location, wsl-open, and an open command. Fixes #5756. [ci skip] --- share/functions/help.fish | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/share/functions/help.fish b/share/functions/help.fish index 99ca6a884..95b153c20 100644 --- a/share/functions/help.fish +++ b/share/functions/help.fish @@ -72,6 +72,19 @@ function help --description 'Show help for the fish shell' else if type -q xdg-open; and set -q -x DISPLAY set fish_browser xdg-open end + + # Try to find cmd.exe via $PATH or one of the paths that it's often at. + # + # We use this instead of xdg-open because that's useless without a backend + # like wsl-open which we'll check in a minute. + if set -l cmd (command -s cmd.exe /mnt/c/Windows/System32/cmd.exe) + # Use the first of these. + set fish_browser $cmd[1] + end + + if type -q wsl-open + set fish_browser wsl-open + end end end @@ -119,11 +132,6 @@ function help --description 'Show help for the fish shell' set fish_help_page "index.html" end - set -l wsl 0 - if uname -a | string match -qr Microsoft - set wsl 1 - end - set -l page_url if test -f $__fish_help_dir/index.html # Help is installed, use it @@ -155,8 +163,9 @@ function help --description 'Show help for the fish shell' end end - if test $wsl -eq 1 - cmd.exe /c "start $page_url" + # cmd.exe needs more coaxing. + if string match -qr 'cmd.exe$' -- $fish_browser[1] + $fish_browser /c "start $page_url" # If browser is known to be graphical, put into background else if contains -- $fish_browser[1] $graphical_browsers switch $fish_browser[1] From 6a9079899d77dee483bbae96cb124cf3c84009e0 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 27 Mar 2019 12:29:03 +0100 Subject: [PATCH 0170/1732] docs: Add an annotated completion example It's not _perfect_, but should hopefully ease the introduction a teensy bit. We use `timedatectl` because it's a reasonably simple command that still uses subcommands and some generated candidates. [ci skip] --- sphinx_doc_src/index.rst | 51 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index 687efeec3..974c97097 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -570,6 +570,57 @@ To provide a list of possible completions for myprog, use the ``-a`` switch. If There are also special switches for specifying that a switch requires an argument, to disable filename completion, to create completions that are only available in some combinations, etc.. For a complete description of the various switches accepted by the ``complete`` command, see the documentation for the `complete `_ builtin, or write ``complete --help`` inside the ``fish`` shell. +As a simple example, here's an excerpt of the completions for systemd's ``timedatectl``:: + + # All subcommands that timedatectl knows - this is useful for later. + set -l commands status set-time set-timezone list-timezones set-local-rtc set-ntp + + # Disable file completions for the entire command + # because it does not take files anywhere + # Note that this can't be undone, + # so it's often better to only disable it for certain completions. + # + # File completions also need to be disabled + # if you wish to offer a certain set of files (e.g. just directories). + complete -c timedatectl -f + + # This line offers the subcommands + # -"status", + # -"set-timezone", + # -"set-time" + # -"list-timezones" + # if no subcommand has been given so far. + # + # The `-n`/`--condition` option takes script as a string, which it executes. + # If it returns true, the completion is offered. + # Here the condition is the `__fish_seen_subcommands_from` helper function. + # If returns true if any of the given commands is used on the commandline, + # as determined by a simple heuristic. + # For more complex uses, you can write your own function. + # See e.g. the git completions for an example. + # + complete -c timedatectl -n "not __fish_seen_subcommand_from $commands" -a "status set-time set-timezone list-timezones" + + # If the "set-timezone" subcommand is used, + # offer the output of `timedatectl list-timezones` as completions. + # Each line of output is used as a separate candidate, + # and anything after a tab is taken as the description. + # It's often useful to transform command output with `string` into that form. + complete -c timedatectl -n "__fish_seen_subcommand_from set-timezone" -a "(timedatectl list-timezones)" + + # Completion candidates can also be described via `-d`, + # which is useful if the description is constant. + # Try to keep these short, because that means the user gets to see more at once. + complete -c timedatectl -n "not __fish_seen_subcommand_from $commands" -a "set-local-rtc" -d "Maintain RTC in local time" + + # We can also limit options to certain subcommands by using conditions. + complete -c timedatectl -n "__fish_seen_subcommand_from set-local-rtc" -l adjust-system-clock -d 'Synchronize system clock from the RTC' + + # These are simple options that can be used everywhere. + complete -c timedatectl -s h -l help -d 'Print a short help text and exit' + complete -c timedatectl -l version -d 'Print a short version string and exit' + complete -c timedatectl -l no-pager -d 'Do not pipe output into a pager' + For examples of how to write your own complex completions, study the completions in ``/usr/share/fish/completions``. (The exact path depends on your chosen installation prefix and may be slightly different) .. _completion-func: From 4e7795217dc3ed7c07425dae03cfbadf17182629 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 27 Mar 2019 12:43:26 +0100 Subject: [PATCH 0171/1732] docs: Replace @cursor_key Should be the last of them. See #5696. [ci skip] --- sphinx_doc_src/index.rst | 6 +++--- sphinx_doc_src/tutorial.rst | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index 974c97097..bc62c5d7f 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -1409,7 +1409,7 @@ Some bindings are shared between emacs- and vi-mode because they aren't text edi - :kbd:`Shift,←,Left` and :kbd:`Shift,→,Right` move the cursor one word left or right, without stopping on punctuation. -- @cursor_key{↑,Up} and @cursor_key{↓,Down} (or :kbd:`Control+P` and :kbd:`Control+N` for emacs aficionados) search the command history for the previous/next command containing the string that was specified on the commandline before the search was started. If the commandline was empty when the search started, all commands match. See the `history <#history>`_ section for more information on history searching. +- :kbd:`↑` (Up) and :kbd:`↓` (Down) (or :kbd:`Control+P` and :kbd:`Control+N` for emacs aficionados) search the command history for the previous/next command containing the string that was specified on the commandline before the search was started. If the commandline was empty when the search started, all commands match. See the `history <#history>`_ section for more information on history searching. - :kbd:`Alt+↑,Up` and :kbd:`Alt+↓,Down` search the command history for the previous/next token containing the token under the cursor before the search was started. If the commandline was not on a token when the search started, all tokens match. See the `history <#history>`_ section for more information on history searching. @@ -1448,7 +1448,7 @@ Emacs mode commands - :kbd:`End` or :kbd:`Control+E` moves to the end of line. If the cursor is already at the end of the line, and an autosuggestion is available, :kbd:`End` or :kbd:`Control+E` accepts the autosuggestion. -- @cursor_key{←,Left} (or :kbd:`Control+B`) and @cursor_key{→,Right} (or :kbd:`Control+F`) move the cursor left or right by one character. If the cursor is already at the end of the line, and an autosuggestion is available, the @cursor_key{→,Right} key and the :kbd:`Control+F` combination accept the suggestion. +- :kbd:`←` (Left) (or :kbd:`Control+B`) and :kbd:`→` (Right) (or :kbd:`Control+F`) move the cursor left or right by one character. If the cursor is already at the end of the line, and an autosuggestion is available, the :kbd:`→` (Right) key and the :kbd:`Control+F` combination accept the suggestion. - :kbd:`Delete` and :kbd:`Backspace` removes one character forwards or backwards respectively. @@ -1535,7 +1535,7 @@ Insert mode Visual mode ----------- -- @cursor_key{←,Left} and @cursor_key{→,Right} extend the selection backward/forward by one character. +- :kbd:`←` (Left) and :kbd:`→` (Right) extend the selection backward/forward by one character. - :kbd:`b` and :kbd:`w` extend the selection backward/forward by one word. diff --git a/sphinx_doc_src/tutorial.rst b/sphinx_doc_src/tutorial.rst index 405d02cce..01503482b 100644 --- a/sphinx_doc_src/tutorial.rst +++ b/sphinx_doc_src/tutorial.rst @@ -163,7 +163,7 @@ And history too. Type a command once, and you can re-summon it by just typing a >_ r<___sync -avze ssh . myname@somelonghost.com:/some/long/path/doo/dee/doo/dee/doo -To accept the autosuggestion, hit @cursor_key{→,right arrow} or :kbd:`Control+F`. To accept a single word of the autosuggestion, :kbd:`Alt+→` (right arrow). If the autosuggestion is not what you want, just ignore it. +To accept the autosuggestion, hit :kbd:`→` (right arrow) or :kbd:`Control+F`. To accept a single word of the autosuggestion, :kbd:`Alt+→` (right arrow). If the autosuggestion is not what you want, just ignore it. Tab Completions --------------- From e2ce63ff62c1964fb5371e406f96ce6b00df67c5 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 27 Mar 2019 12:46:51 +0100 Subject: [PATCH 0172/1732] functions/help: Adjust command paths to sphinx We now build a separate page per-command in cmds/$cmd.html instead of a section in the "commands.html" page. See #5696. [ci skip] --- share/functions/help.fish | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/functions/help.fish b/share/functions/help.fish index 95b153c20..0a6c94dfd 100644 --- a/share/functions/help.fish +++ b/share/functions/help.fish @@ -105,11 +105,11 @@ function help --description 'Show help for the fish shell' switch "$fish_help_item" case "." - set fish_help_page "commands.html\#source" + set fish_help_page "cmds/source.html" case globbing set fish_help_page "index.html\#expand" case (__fish_print_commands) - set fish_help_page "commands.html\#$fish_help_item" + set fish_help_page "cmds/$fish_help_item.html" case $help_topics set fish_help_page "index.html\#$fish_help_item" case 'tut_*' From d8ec4685ffec9cf53d81cea39c528852e6ea0aee Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 26 Mar 2019 21:39:25 +0100 Subject: [PATCH 0173/1732] src/builtin_test: Remove weird leading tab from error message This is a remainder from when we used to speak of "eval errors". --- src/builtin_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builtin_test.cpp b/src/builtin_test.cpp index 3951a7ecc..821001ab1 100644 --- a/src/builtin_test.cpp +++ b/src/builtin_test.cpp @@ -864,7 +864,7 @@ int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (!eval_errors.empty()) { if (!should_suppress_stderr_for_tests()) { for (size_t i = 0; i < eval_errors.size(); i++) { - streams.err.append_format(L"\t%ls\n", eval_errors.at(i).c_str()); + streams.err.append_format(L"%ls\n", eval_errors.at(i).c_str()); } } return STATUS_INVALID_ARGS; From 785945c861654793a889bcbd89c02d235b401569 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 26 Mar 2019 21:40:10 +0100 Subject: [PATCH 0174/1732] src/builtin_test: Print backtrace on error `test` is a common source of problems, and with the current system they can be quite hard to find. So we print a backtrace with line numbers and all. --- src/builtin_test.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/builtin_test.cpp b/src/builtin_test.cpp index 821001ab1..b36921297 100644 --- a/src/builtin_test.cpp +++ b/src/builtin_test.cpp @@ -21,6 +21,7 @@ #include "builtin.h" #include "common.h" #include "io.h" +#include "parser.h" #include "wutil.h" // IWYU pragma: keep using std::unique_ptr; @@ -830,6 +831,7 @@ int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) { argc--; } else { streams.err.append(L"[: the last argument must be ']'\n"); + builtin_print_error_trailer(parser, streams.err, program_name); return STATUS_INVALID_ARGS; } } @@ -848,14 +850,8 @@ int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wcstring err; unique_ptr expr = test_parser::parse_args(args, err, program_name); if (!expr) { -#if 0 - streams.err.append(L"Oops! test was given args:\n"); - for (size_t i=0; i < argc; i++) { - streams.err.append_format(L"\t%ls\n", args.at(i).c_str()); - } - streams.err.append_format(L"and returned parse error: %ls\n", err.c_str()); -#endif streams.err.append(err); + builtin_print_error_trailer(parser, streams.err, program_name); return STATUS_CMD_ERROR; } @@ -866,6 +862,9 @@ int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) { for (size_t i = 0; i < eval_errors.size(); i++) { streams.err.append_format(L"%ls\n", eval_errors.at(i).c_str()); } + // Add a backtrace but not the "see help" message + // because this isn't about passing the wrong options. + streams.err.append(parser.current_line()); } return STATUS_INVALID_ARGS; } From 5441ebc91f212aea38346c181d8dcda0bd8899f1 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Thu, 28 Mar 2019 00:37:06 -0700 Subject: [PATCH 0175/1732] Remove some dead code --- src/builtin.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index 347f5c216..d2b545536 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -143,15 +143,6 @@ int parse_help_only_cmd_opts(struct help_only_cmd_opts_t &opts, int *optind, int return STATUS_CMD_OK; } -/// Count the number of times the specified character occurs in the specified string. -static int count_char(const wchar_t *str, wchar_t c) { - int res = 0; - for (; *str; str++) { - res += (*str == c); - } - return res; -} - /// Obtain help/usage information for the specified builtin from manpage in subshell /// /// @param name From 21d8b465cced887bfea086bf066383a9f04f0ee6 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 28 Mar 2019 11:55:27 +0100 Subject: [PATCH 0176/1732] nextd/prevd: Print BEL instead of "Hit end of history" That message is just hugely annoying. Hat-tip to @floam and d524bad5f16b5a18c22fefe440. --- CHANGELOG.md | 1 + share/functions/__fish_move_last.fish | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2d167ff4..508e1bdc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ - `bosh` - `vagrant` - The git prompt in informative mode now shows the number of stashes if enabled. +- The nextd and prevd functions no longer print "Hit end of history", instead using a BEL. ### For distributors and developers - The autotools-based build system and legacy Xcode build systems have been removed, leaving only the CMake build system. All distributors and developers must migrate to the CMake build. diff --git a/share/functions/__fish_move_last.fish b/share/functions/__fish_move_last.fish index b9c57d805..751b3d2a0 100644 --- a/share/functions/__fish_move_last.fish +++ b/share/functions/__fish_move_last.fish @@ -6,7 +6,8 @@ function __fish_move_last -d "Move the last element of a directory history from if test $size_src = 0 # Cannot make this step - printf (_ "Hit end of history…\n") + # Print a bel, which is the character to print for notifications like these. + printf \a return 1 end From 42acbaa5af59a93c8ecf74ccc696ab7df15a23eb Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 28 Mar 2019 12:27:45 +0100 Subject: [PATCH 0177/1732] Remouve ouveroused U Webster was right, gosh dang it! [ci skip] --- src/complete.h | 2 +- src/output.cpp | 2 +- src/screen.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/complete.h b/src/complete.h index 3b1655f5d..2563f34ca 100644 --- a/src/complete.h +++ b/src/complete.h @@ -73,7 +73,7 @@ class completion_t { wcstring description; /// The type of fuzzy match. string_fuzzy_match_t match; - /// Flags determining the completion behaviour. + /// Flags determining the completion behavior. /// /// Determines whether a space should be inserted after this completion if it is the only /// possible completion using the COMPLETE_NO_SPACE flag. The COMPLETE_NO_CASE can be used to diff --git a/src/output.cpp b/src/output.cpp index 1fadaa34a..80f0f51d8 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -180,7 +180,7 @@ void outputter_t::set_color(rgb_color_t c, rgb_color_t c2) { was_italics = false; was_dim = false; was_reverse = false; - // If we exit attibute mode, we must first set a color, or previously coloured text might + // If we exit attibute mode, we must first set a color, or previously colored text might // lose it's color. Terminals are weird... write_foreground_color(*this, 0); writembs(*this, exit_attribute_mode); diff --git a/src/screen.cpp b/src/screen.cpp index bd34c94a1..47d324d17 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -463,7 +463,7 @@ static void s_move(screen_t *s, int new_x, int new_y) { if (y_steps > 0 && (std::strcmp(cursor_down, "\n") == 0)) { // This is very strange - it seems some (all?) consoles use a simple newline as the cursor // down escape. This will of course move the cursor to the beginning of the line as well as - // moving it down one step. The cursor_up does not have this behaviour... + // moving it down one step. The cursor_up does not have this behavior... s->actual.cursor.x = 0; } From c94fe0f8c921dc71dffda59120e96d69b5745900 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 28 Mar 2019 21:16:05 +0100 Subject: [PATCH 0178/1732] docs/fish_git_prompt: Document default settings This should help with interpreting the results. All this is quite convoluted, especially with defaults dependent on other settings. [ci skip] --- sphinx_doc_src/cmds/fish_git_prompt.rst | 43 ++++++++++++------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/sphinx_doc_src/cmds/fish_git_prompt.rst b/sphinx_doc_src/cmds/fish_git_prompt.rst index 08b1cb9b5..59e2bc207 100644 --- a/sphinx_doc_src/cmds/fish_git_prompt.rst +++ b/sphinx_doc_src/cmds/fish_git_prompt.rst @@ -38,48 +38,47 @@ There are numerous configuration options, either as fish variables or git config - $__fish_git_prompt_showcolorhints can be set to enable coloring for certain things. -A number of variables to set characters and color used to indicate things. Many of these have a different default if used with informative status enabled. +A number of variables set characters and color used to indicate things. Many of these have a different default if used with informative status enabled. The normal default is given first, then the informative default if it is different. If no default for the colors is given, they default to $__fish_git_prompt_color. -- $__fish_git_prompt_char_stateseparator -- $__fish_git_prompt_color +- $__fish_git_prompt_char_stateseparator (' ', |) +- $__fish_git_prompt_color (nothing) - $__fish_git_prompt_color_prefix - $__fish_git_prompt_color_suffix - $__fish_git_prompt_color_bare - $__fish_git_prompt_color_merging Some variables are only used in some modes, like when informative status is enabled (by setting $__fish_git_prompt_show_informative_status): -- $__fish_git_prompt_char_cleanstate +- $__fish_git_prompt_char_cleanstate (✔) - $__fish_git_prompt_color_cleanstate Variables used with showdirtystate: -- $__fish_git_prompt_char_dirtystate -- $__fish_git_prompt_char_invalidstate -- $__fish_git_prompt_char_stagedstate -- $__fish_git_prompt_color_dirtystate +- $__fish_git_prompt_char_dirtystate (*, ✚) +- $__fish_git_prompt_char_invalidstate (#, ✖) +- $__fish_git_prompt_char_stagedstate (+, ●) +- $__fish_git_prompt_color_dirtystate (red with showcolorhints, same as color_flags otherwise) - $__fish_git_prompt_color_invalidstate -- $__fish_git_prompt_color_stagedstate +- $__fish_git_prompt_color_stagedstate (green with showcolorhints, color_flags otherwise) Variables used with showstashstate: -- $__fish_git_prompt_char_stashstate -- $__fish_git_prompt_color_stashstate +- $__fish_git_prompt_char_stashstate ($, ⚑) +- $__fish_git_prompt_color_stashstate (same as color_flags) Variables used with showuntrackedfiles: -- $__fish_git_prompt_char_untrackedfiles -- $__fish_git_prompt_color_untrackedfiles +- $__fish_git_prompt_char_untrackedfiles (%, …) +- $__fish_git_prompt_color_untrackedfiles (same as color_flags) Variables used with showupstream (also implied by informative status): -- $__fish_git_prompt_char_upstream_ahead -- $__fish_git_prompt_char_upstream_behind -- $__fish_git_prompt_char_upstream_diverged -- $__fish_git_prompt_char_upstream_equal -- $__fish_git_prompt_char_upstream_prefix +- $__fish_git_prompt_char_upstream_ahead (>, ↑) +- $__fish_git_prompt_char_upstream_behind (<, ↓) +- $__fish_git_prompt_char_upstream_diverged (<>) +- $__fish_git_prompt_char_upstream_equal (=) +- $__fish_git_prompt_char_upstream_prefix ('') - $__fish_git_prompt_color_upstream Colors used with showcolorhints: -- $__fish_git_prompt_color_branch -- $__fish_git_prompt_color_branch_detached -- $__fish_git_prompt_color_dirtystate -- $__fish_git_prompt_color_flags +- $__fish_git_prompt_color_branch (green) +- $__fish_git_prompt_color_branch_detached (red) +- $__fish_git_prompt_color_flags (--bold blue) Note that all colors can also have a corresponding "_done" color. E.g. $__fish_git_prompt_color_upstream_done, used right _after_ the upstream. From 6cf61d52355018b069d56688d8aae0e616559a4d Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 28 Mar 2019 22:11:28 +0100 Subject: [PATCH 0179/1732] docs/fish_git_prompt: Fix formatting Sphinx likes empty lines before lists. Also give variable names the ``treatment``. [ci skip] --- sphinx_doc_src/cmds/fish_git_prompt.rst | 82 +++++++++++++------------ 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/sphinx_doc_src/cmds/fish_git_prompt.rst b/sphinx_doc_src/cmds/fish_git_prompt.rst index 59e2bc207..a3aeab276 100644 --- a/sphinx_doc_src/cmds/fish_git_prompt.rst +++ b/sphinx_doc_src/cmds/fish_git_prompt.rst @@ -10,13 +10,13 @@ For obvious reasons, it requires having git installed. There are numerous configuration options, either as fish variables or git config variables. If a git config variable is supported, it will be used if set, and the fish variable will only be used if it isn't. -- $__fish_git_prompt_show_informative_status or the git config option "bash.showInformativeStatus" can be set to enable the "informative" display, which will show a large amount of information - the number of untracked files, dirty files, unpushed/unpulled commits, etc... In large repositories, this can take a lot of time, so it is recommended to disable it there, via ``git config bash.showInformativeStatus false``. +- ``$__fish_git_prompt_show_informative_status`` or the git config option "bash.showInformativeStatus" can be set to enable the "informative" display, which will show a large amount of information - the number of untracked files, dirty files, unpushed/unpulled commits, etc... In large repositories, this can take a lot of time, so it is recommended to disable it there, via ``git config bash.showInformativeStatus false``. -- $__fish_git_prompt_showdirtystate or the git config option "bash.showDirtyState" can be set to show if the repository is "dirty", i.e. has uncommitted changes. +- ``$__fish_git_prompt_showdirtystate`` or the git config option "bash.showDirtyState" can be set to show if the repository is "dirty", i.e. has uncommitted changes. -- $__fish_git_prompt_showuntrackedfiles or the git config option "bash.showUntrackedFiles" can be set to show if the repository has untracked files (that aren't ignored). +- ``$__fish_git_prompt_showuntrackedfiles`` or the git config option "bash.showUntrackedFiles" can be set to show if the repository has untracked files (that aren't ignored). -- $__fish_git_prompt_showupstream can be set to a number of values to determine how changes between HEAD and upstream are shown: +- ``$__fish_git_prompt_showupstream`` can be set to a number of values to determine how changes between HEAD and upstream are shown: verbose show number of commits ahead/behind (+/-) upstream name if verbose, then also show the upstream abbrev name @@ -25,62 +25,68 @@ There are numerous configuration options, either as fish variables or git config svn always compare HEAD to your SVN upstream none disables (useful with show_informative_status) -- $__fish_git_prompt_showstashstate can be set to display the state of the stash. +- ``$__fish_git_prompt_showstashstate`` can be set to display the state of the stash. -- $__fish_git_prompt_shorten_branch_len can be set to the number of characters that the branch name will be shortened to. +- ``$__fish_git_prompt_shorten_branch_len`` can be set to the number of characters that the branch name will be shortened to. -- $__fish_git_prompt_describe_style can be set to a number of styles that describe the current HEAD: +- ``$__fish_git_prompt_describe_style`` can be set to a number of styles that describe the current HEAD: contains branch describe default -- $__fish_git_prompt_showcolorhints can be set to enable coloring for certain things. +- ``$__fish_git_prompt_showcolorhints`` can be set to enable coloring for certain things. -A number of variables set characters and color used to indicate things. Many of these have a different default if used with informative status enabled. The normal default is given first, then the informative default if it is different. If no default for the colors is given, they default to $__fish_git_prompt_color. +A number of variables set characters and color used to indicate things. Many of these have a different default if used with informative status enabled. The normal default is given first, then the informative default if it is different. If no default for the colors is given, they default to ``$__fish_git_prompt_color``. -- $__fish_git_prompt_char_stateseparator (' ', |) -- $__fish_git_prompt_color (nothing) -- $__fish_git_prompt_color_prefix -- $__fish_git_prompt_color_suffix -- $__fish_git_prompt_color_bare -- $__fish_git_prompt_color_merging +- ``$__fish_git_prompt_char_stateseparator`` (' ', |) +- ``$__fish_git_prompt_color`` ('') +- ``$__fish_git_prompt_color_prefix`` +- ``$__fish_git_prompt_color_suffix`` +- ``$__fish_git_prompt_color_bare`` +- ``$__fish_git_prompt_color_merging`` -Some variables are only used in some modes, like when informative status is enabled (by setting $__fish_git_prompt_show_informative_status): -- $__fish_git_prompt_char_cleanstate (✔) -- $__fish_git_prompt_color_cleanstate +Some variables are only used in some modes, like when informative status is enabled (by setting ``$__fish_git_prompt_show_informative_status``): + +- ``$__fish_git_prompt_char_cleanstate`` (✔) +- ``$__fish_git_prompt_color_cleanstate`` Variables used with showdirtystate: -- $__fish_git_prompt_char_dirtystate (*, ✚) -- $__fish_git_prompt_char_invalidstate (#, ✖) -- $__fish_git_prompt_char_stagedstate (+, ●) -- $__fish_git_prompt_color_dirtystate (red with showcolorhints, same as color_flags otherwise) -- $__fish_git_prompt_color_invalidstate -- $__fish_git_prompt_color_stagedstate (green with showcolorhints, color_flags otherwise) + +- ``$__fish_git_prompt_char_dirtystate`` (*, ✚) +- ``$__fish_git_prompt_char_invalidstate`` (#, ✖) +- ``$__fish_git_prompt_char_stagedstate`` (+, ●) +- ``$__fish_git_prompt_color_dirtystate`` (red with showcolorhints, same as color_flags otherwise) +- ``$__fish_git_prompt_color_invalidstate`` +- ``$__fish_git_prompt_color_stagedstate`` (green with showcolorhints, color_flags otherwise) Variables used with showstashstate: -- $__fish_git_prompt_char_stashstate ($, ⚑) -- $__fish_git_prompt_color_stashstate (same as color_flags) + +- ``$__fish_git_prompt_char_stashstate`` (``$``, ⚑) +- ``$__fish_git_prompt_color_stashstate`` (same as color_flags) Variables used with showuntrackedfiles: -- $__fish_git_prompt_char_untrackedfiles (%, …) -- $__fish_git_prompt_color_untrackedfiles (same as color_flags) + +- ``$__fish_git_prompt_char_untrackedfiles`` (%, …) +- ``$__fish_git_prompt_color_untrackedfiles`` (same as color_flags) Variables used with showupstream (also implied by informative status): -- $__fish_git_prompt_char_upstream_ahead (>, ↑) -- $__fish_git_prompt_char_upstream_behind (<, ↓) -- $__fish_git_prompt_char_upstream_diverged (<>) -- $__fish_git_prompt_char_upstream_equal (=) -- $__fish_git_prompt_char_upstream_prefix ('') -- $__fish_git_prompt_color_upstream + +- ``$__fish_git_prompt_char_upstream_ahead`` (>, ↑) +- ``$__fish_git_prompt_char_upstream_behind`` (<, ↓) +- ``$__fish_git_prompt_char_upstream_diverged`` (<>) +- ``$__fish_git_prompt_char_upstream_equal`` (=) +- ``$__fish_git_prompt_char_upstream_prefix`` ('') +- ``$__fish_git_prompt_color_upstream`` Colors used with showcolorhints: -- $__fish_git_prompt_color_branch (green) -- $__fish_git_prompt_color_branch_detached (red) -- $__fish_git_prompt_color_flags (--bold blue) -Note that all colors can also have a corresponding "_done" color. E.g. $__fish_git_prompt_color_upstream_done, used right _after_ the upstream. +- ``$__fish_git_prompt_color_branch`` (green) +- ``$__fish_git_prompt_color_branch_detached`` (red) +- ``$__fish_git_prompt_color_flags`` (--bold blue) + +Note that all colors can also have a corresponding "_done" color. E.g. ``$__fish_git_prompt_color_upstream_done``, used right _after_ the upstream. See also fish_vcs_prompt, which will call all supported vcs-prompt functions, including git, hg and svn. From 0c5015d4677faf8f2f983e5f8445c59bca60f3e1 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Thu, 28 Mar 2019 18:23:32 -0500 Subject: [PATCH 0180/1732] Correct the reversed diff output for all tests This has been driving nuts for years. The output of the diff emitted when a test fails was always reversed, because the diff tool is called with `${difftool} ${new} ${old}` so all the `-` and `+` contexts are reversed, and the highlights are all screwed up. The output of a `make test` run should show what has changed from the baseline/expected, not how the expected differs from the actual. When considered from both the perspective of intentional changes to the test outputs and failed test outputs, it is desirable to see how the test output has changed from the previously expected, and not the other way around. (If you were used to the previous behavior, I apologize. But it was wrong.) --- tests/interactive.fish | 4 ++-- tests/invocation.sh | 8 ++++---- tests/test.fish | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/interactive.fish b/tests/interactive.fish index 933749446..f6a05a12b 100644 --- a/tests/interactive.fish +++ b/tests/interactive.fish @@ -69,11 +69,11 @@ function test_file say red "fail" if test $out_status -ne 0 say yellow "Output differs for file $file. Diff follows:" - colordiff -u $file.tmp.out $file.out + colordiff -u $file.out $file.tmp.out end if test $err_status -ne 0 say yellow "Error output differs for file $file. Diff follows:" - colordiff -u $file.tmp.err $file.err + colordiff -u $file.err $file.tmp.err end if test $exit_status -ne 0 say yellow "Exit status differs for file $file." diff --git a/tests/invocation.sh b/tests/invocation.sh index 8ced43e4e..728636ca4 100755 --- a/tests/invocation.sh +++ b/tests/invocation.sh @@ -245,10 +245,10 @@ test_file() ( mv -f "${test_stderr}.new" "${test_stderr}" # Check the results - if ! diff "${test_stdout}" "${want_stdout}" >/dev/null 2>/dev/null ; then + if ! diff "${want_stdout}" "${test_stdout}" >/dev/null 2>/dev/null ; then out_status=1 fi - if ! diff "${test_stderr}" "${want_stderr}" >/dev/null 2>/dev/null ; then + if ! diff "${want_stderr}" "${test_stderr}" >/dev/null 2>/dev/null ; then err_status=1 fi @@ -264,11 +264,11 @@ test_file() ( if [ "$out_status" != '0' ] ; then say "$term_yellow" "Output differs for file $file. Diff follows:" - "$difftool" -u "${test_stdout}" "${want_stdout}" + "$difftool" -u "${want_stdout}" "${test_stdout}" fi if [ "$err_status" != '0' ] ; then say "$term_yellow" "Error output differs for file $file. Diff follows:" - "$difftool" -u "${test_stderr}" "${want_stderr}" + "$difftool" -u "${want_stderr}" "${test_stderr}" fi rc=1 fi diff --git a/tests/test.fish b/tests/test.fish index 0711e0933..62025fe0d 100644 --- a/tests/test.fish +++ b/tests/test.fish @@ -55,11 +55,11 @@ function test_file say red "fail" if test $out_status -ne 0 say yellow "Output differs for file $file. Diff follows:" - colordiff -u $base.tmp.out $base.out + colordiff -u $base.out $base.tmp.out end if test $err_status -ne 0 say yellow "Error output differs for file $file. Diff follows:" - colordiff -u $base.tmp.err $base.err + colordiff -u $base.err $base.tmp.err end if test $exit_status -ne 0 say yellow "Exit status differs for file $file." From f8e0e0ef827f40928973850c375409bbcaed8060 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Sun, 30 Dec 2018 21:25:16 -0600 Subject: [PATCH 0181/1732] Remove abstractions around job list Directly access the job list without the intermediate job_iterator_t, and remove functions that are ripe for abuse by modifying a local enumeration of the same list instead of operating on the iterators directly (e.g. proc.cpp iterates jobs, and mid-iteration calls parser::job_remove(j) with the job (and not the iterator to the job), causing an invisible invalidation of the pre-existing local iterators. --- src/builtin_bg.cpp | 10 +++---- src/builtin_disown.cpp | 24 ++++++++++------- src/builtin_fg.cpp | 44 +++++++++++++++--------------- src/builtin_jobs.cpp | 12 +++------ src/builtin_wait.cpp | 20 +++++--------- src/parse_execution.cpp | 16 ++++++++--- src/parser.cpp | 20 ++------------ src/parser.h | 3 --- src/proc.cpp | 59 +++++++++++++---------------------------- src/proc.h | 23 ++-------------- src/reader.cpp | 6 ++--- 11 files changed, 87 insertions(+), 150 deletions(-) diff --git a/src/builtin_bg.cpp b/src/builtin_bg.cpp index c97b1dddb..9af0cbbfc 100644 --- a/src/builtin_bg.cpp +++ b/src/builtin_bg.cpp @@ -51,19 +51,19 @@ int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (optind == argc) { // No jobs were specified so use the most recent (i.e., last) job. - job_t *j; - job_iterator_t jobs; - while ((j = jobs.next())) { + job_t *job = nullptr; + for (auto j : jobs()) { if (j->is_stopped() && j->get_flag(job_flag_t::JOB_CONTROL) && (!j->is_completed())) { + job = j.get(); break; } } - if (!j) { + if (!job) { streams.err.append_format(_(L"%ls: There are no suitable jobs\n"), cmd); retval = STATUS_CMD_ERROR; } else { - retval = send_to_bg(parser, streams, j); + retval = send_to_bg(parser, streams, job); } return retval; diff --git a/src/builtin_disown.cpp b/src/builtin_disown.cpp index 52e2c995b..dc766cc34 100644 --- a/src/builtin_disown.cpp +++ b/src/builtin_disown.cpp @@ -31,13 +31,17 @@ static int disown_job(const wchar_t *cmd, parser_t &parser, io_streams_t &stream streams.err.append_format(fmt, cmd, j->job_id, j->command_wcstr()); } - pid_t pgid = j->pgid; - if (!parser.job_remove(j)) { - return STATUS_CMD_ERROR; + for (auto itr = jobs().begin(); itr != jobs().end(); ++itr) { + auto job = itr->get(); + if (job == j) { + pid_t pgid = j->pgid; + add_disowned_pgid(pgid); + jobs().erase(itr); + return STATUS_CMD_OK; + } } - add_disowned_pgid(pgid); - return STATUS_CMD_OK; + return STATUS_CMD_ERROR; } /// Builtin for removing jobs from the job list. @@ -56,20 +60,20 @@ int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) { } if (argv[1] == 0) { - job_t *j; // Select last constructed job (ie first job in the job queue) that is possible to disown. // Stopped jobs can be disowned (they will be continued). // Foreground jobs can be disowned. // Even jobs that aren't under job control can be disowned! - job_iterator_t jobs; - while ((j = jobs.next())) { + job_t *job = nullptr; + for (auto j : jobs()) { if (j->is_constructed() && (!j->is_completed())) { + job = j.get(); break; } } - if (j) { - retval = disown_job(cmd, parser, streams, j); + if (job) { + retval = disown_job(cmd, parser, streams, job); } else { streams.err.append_format(_(L"%ls: There are no suitable jobs\n"), cmd); retval = STATUS_CMD_ERROR; diff --git a/src/builtin_fg.cpp b/src/builtin_fg.cpp index 8a915ecc1..0ef092740 100644 --- a/src/builtin_fg.cpp +++ b/src/builtin_fg.cpp @@ -33,20 +33,20 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { return STATUS_CMD_OK; } - job_t *j = NULL; - + job_t *job = nullptr; if (optind == argc) { // Select last constructed job (I.e. first job in the job que) that is possible to put in // the foreground. - job_iterator_t jobs; - while ((j = jobs.next())) { + + for (auto j : jobs()) { if (j->is_constructed() && (!j->is_completed()) && ((j->is_stopped() || (!j->is_foreground())) && j->get_flag(job_flag_t::JOB_CONTROL))) { + job = j.get(); break; } } - if (!j) { + if (!job) { streams.err.append_format(_(L"%ls: There are no suitable jobs\n"), cmd); } } else if (optind + 1 < argc) { @@ -58,8 +58,8 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { pid = fish_wcstoi(argv[optind]); if (!(errno || pid < 0)) { - j = job_t::from_pid(pid); - if (j) found_job = true; + job = job_t::from_pid(pid); + if (job) found_job = true; } if (found_job) { @@ -70,46 +70,46 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { builtin_print_error_trailer(parser, streams.err, cmd); - j = 0; + job = 0; } else { int pid = abs(fish_wcstoi(argv[optind])); if (errno) { streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, cmd, argv[optind]); builtin_print_error_trailer(parser, streams.err, cmd); } else { - j = job_t::from_pid(pid); - if (!j || !j->is_constructed() || j->is_completed()) { + job = job_t::from_pid(pid); + if (!job || !job->is_constructed() || job->is_completed()) { streams.err.append_format(_(L"%ls: No suitable job: %d\n"), cmd, pid); - j = 0; - } else if (!j->get_flag(job_flag_t::JOB_CONTROL)) { + job = nullptr; + } else if (!job->get_flag(job_flag_t::JOB_CONTROL)) { streams.err.append_format(_(L"%ls: Can't put job %d, '%ls' to foreground because " L"it is not under job control\n"), - cmd, pid, j->command_wcstr()); - j = 0; + cmd, pid, job->command_wcstr()); + job = 0; } } } - if (!j) { + if (!job) { return STATUS_INVALID_ARGS; } if (streams.err_is_redirected) { - streams.err.append_format(FG_MSG, j->job_id, j->command_wcstr()); + streams.err.append_format(FG_MSG, job->job_id, job->command_wcstr()); } else { // If we aren't redirecting, send output to real stderr, since stuff in sb_err won't get // printed until the command finishes. - std::fwprintf(stderr, FG_MSG, j->job_id, j->command_wcstr()); + std::fwprintf(stderr, FG_MSG, job->job_id, job->command_wcstr()); } - const wcstring ft = tok_first(j->command()); + const wcstring ft = tok_first(job->command()); //For compatibility with fish 2.0's $_, now replaced with `status current-command` if (!ft.empty()) parser.vars().set_one(L"_", ENV_EXPORT, ft); - reader_write_title(j->command()); + reader_write_title(job->command()); - j->promote(); - j->set_flag(job_flag_t::FOREGROUND, true); + job->promote(); + job->set_flag(job_flag_t::FOREGROUND, true); - j->continue_job(j->is_stopped()); + job->continue_job(job->is_stopped()); return STATUS_CMD_OK; } diff --git a/src/builtin_jobs.cpp b/src/builtin_jobs.cpp index 6d9857992..c3673b89d 100644 --- a/src/builtin_jobs.cpp +++ b/src/builtin_jobs.cpp @@ -174,11 +174,9 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (print_last) { // Ignore unconstructed jobs, i.e. ourself. - job_iterator_t jobs; - const job_t *j; - while ((j = jobs.next())) { + for (auto j : jobs()) { if (j->is_constructed() && !j->is_completed()) { - builtin_jobs_print(j, mode, !streams.out_is_redirected, streams); + builtin_jobs_print(j.get(), mode, !streams.out_is_redirected, streams); return STATUS_CMD_ERROR; } } @@ -217,12 +215,10 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) { } } } else { - job_iterator_t jobs; - const job_t *j; - while ((j = jobs.next())) { + for (auto j : jobs()) { // Ignore unconstructed jobs, i.e. ourself. if (j->is_constructed() && !j->is_completed()) { - builtin_jobs_print(j, mode, !found && !streams.out_is_redirected, streams); + builtin_jobs_print(j.get(), mode, !found && !streams.out_is_redirected, streams); found = true; } } diff --git a/src/builtin_wait.cpp b/src/builtin_wait.cpp index b517f7a78..34a687bb1 100644 --- a/src/builtin_wait.cpp +++ b/src/builtin_wait.cpp @@ -16,10 +16,7 @@ /// If a specified process has already finished but the job hasn't, parser_t::job_get_from_pid() /// doesn't work properly, so use this function in wait command. static job_id_t get_job_id_from_pid(pid_t pid) { - job_t *j; - job_iterator_t jobs; - - while ((j = jobs.next()) != nullptr) { + for (auto j : jobs()) { if (j->pgid == pid) { return j->job_id; } @@ -34,8 +31,7 @@ static job_id_t get_job_id_from_pid(pid_t pid) { } static bool all_jobs_finished() { - job_iterator_t jobs; - while (job_t *j = jobs.next()) { + for (auto j : jobs()) { // If any job is not completed, return false. // If there are stopped jobs, they are ignored. if (j->is_constructed() && !j->is_completed() && !j->is_stopped()) { @@ -46,14 +42,13 @@ static bool all_jobs_finished() { } static bool any_jobs_finished(size_t jobs_len) { - job_iterator_t jobs; bool no_jobs_running = true; // If any job is removed from list, return true. - if (jobs_len != jobs.count()) { + if (jobs_len != jobs().size()) { return true; } - while (job_t *j = jobs.next()) { + for (auto j : jobs()) { // If any job is completed, return true. if (j->is_constructed() && (j->is_completed() || j->is_stopped())) { return true; @@ -70,8 +65,7 @@ static bool any_jobs_finished(size_t jobs_len) { } static int wait_for_backgrounds(bool any_flag) { - job_iterator_t jobs; - size_t jobs_len = jobs.count(); + size_t jobs_len = jobs().size(); while ((!any_flag && !all_jobs_finished()) || (any_flag && !any_jobs_finished(jobs_len))) { if (reader_test_interrupted()) { @@ -143,10 +137,9 @@ static bool match_pid(const wcstring &cmd, const wchar_t *proc) { /// It should search the job list for something matching the given proc. static bool find_job_by_name(const wchar_t *proc, std::vector &ids) { - job_iterator_t jobs; bool found = false; - while (const job_t *j = jobs.next()) { + for (const auto j : jobs()) { if (j->command_is_empty()) continue; if (match_pid(j->command(), proc)) { @@ -179,7 +172,6 @@ static bool find_job_by_name(const wchar_t *proc, std::vector &ids) { int builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv) { ASSERT_IS_MAIN_THREAD(); int retval = STATUS_CMD_OK; - job_iterator_t jobs; const wchar_t *cmd = argv[0]; int argc = builtin_count_args(argv); bool any_flag = false; // flag for -n option diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 2034f0d56..8bd145c77 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -784,10 +784,8 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process( // Protect against exec with background processes running static uint32_t last_exec_run_counter = -1; if (process_type == process_type_t::exec && shell_is_interactive()) { - job_iterator_t jobs; bool have_bg = false; - const job_t *bg = nullptr; - while ((bg = jobs.next())) { + for (const auto bg : jobs()) { // The assumption here is that if it is a foreground job, // it's related to us. // This stops us from asking if we're doing `exec` inside a function. @@ -1130,6 +1128,16 @@ parse_execution_result_t parse_execution_context_t::populate_job_from_job_node( return result; } +static bool remove_job(job_t *job) { + for (auto j = jobs().begin(); j != jobs().end(); ++j) { + if (j->get() == job) { + jobs().erase(j); + return true; + } + } + return false; +} + parse_execution_result_t parse_execution_context_t::run_1_job(tnode_t job_node, const block_t *associated_block) { if (should_cancel_execution(associated_block)) { @@ -1253,7 +1261,7 @@ parse_execution_result_t parse_execution_context_t::run_1_job(tnode_t jo // Actually execute the job. if (!exec_job(*this->parser, job)) { - parser->job_remove(job.get()); + remove_job(job.get()); } // Only external commands require a new fishd barrier. diff --git a/src/parser.cpp b/src/parser.cpp index 15871ed03..2a94a6b8e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -570,19 +570,6 @@ void parser_t::job_add(shared_ptr job) { this->my_job_list.push_front(std::move(job)); } -bool parser_t::job_remove(job_t *job) { - for (auto iter = my_job_list.begin(); iter != my_job_list.end(); ++iter) { - if (iter->get() == job) { - my_job_list.erase(iter); - return true; - } - } - - debug(1, _(L"Job inconsistency")); - sanity_lose(); - return false; -} - void parser_t::job_promote(job_t *job) { job_list_t::iterator loc; for (loc = my_job_list.begin(); loc != my_job_list.end(); ++loc) { @@ -604,20 +591,17 @@ job_t *parser_t::job_get(job_id_t id) { } job_t *parser_t::job_get_from_pid(pid_t pid) const { - job_iterator_t jobs; - job_t *job; - pid_t pgid = getpgid(pid); if (pgid == -1) { return 0; } - while ((job = jobs.next())) { + for (auto job : jobs()) { if (job->pgid == pgid) { for (const process_ptr_t &p : job->processes) { if (p->pid == pid) { - return job; + return job.get(); } } } diff --git a/src/parser.h b/src/parser.h index 264b09cc8..e6409c283 100644 --- a/src/parser.h +++ b/src/parser.h @@ -288,9 +288,6 @@ class parser_t : public std::enable_shared_from_this { /// Return the function name for the specified stack frame. Default is one (current frame). const wchar_t *get_function_name(int level = 1); - /// Removes a job. - bool job_remove(job_t *job); - /// Promotes a job to the front of the list. void job_promote(job_t *job); diff --git a/src/proc.cpp b/src/proc.cpp index 119bbfeee..2f0dc6b12 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -59,20 +59,11 @@ bool job_list_is_empty() { return parser_t::principal_parser().job_list().empty(); } -void job_iterator_t::reset() { - this->current = job_list->begin(); - this->end = job_list->end(); -} - -job_iterator_t::job_iterator_t(job_list_t &jobs) : job_list(&jobs) { this->reset(); } - -job_iterator_t::job_iterator_t() : job_list(&parser_t::principal_parser().job_list()) { +job_list_t& jobs() { ASSERT_IS_MAIN_THREAD(); - this->reset(); + return parser_t::principal_parser().job_list(); } -size_t job_iterator_t::count() const { return this->job_list->size(); } - bool is_interactive_session = false; bool is_subshell = false; bool is_block = false; @@ -110,23 +101,15 @@ static std::vector interactive_stack; void proc_init() { proc_push_interactive(0); } -/// Remove job from list of jobs. -static int job_remove(job_t *j) { - ASSERT_IS_MAIN_THREAD(); - return parser_t::principal_parser().job_remove(j); -} - void job_t::promote() { ASSERT_IS_MAIN_THREAD(); parser_t::principal_parser().job_promote(this); } void proc_destroy() { - job_list_t &jobs = parser_t::principal_parser().job_list(); - while (!jobs.empty()) { - job_t *job = jobs.front().get(); - debug(2, L"freeing leaked job %ls", job->command_wcstr()); - job_remove(job); + for (auto job = jobs().begin(); job != jobs().end(); ++job) { + debug(2, L"freeing leaked job %ls", (*job)->command_wcstr()); + job = jobs().erase(job); } } @@ -364,8 +347,7 @@ static void process_mark_finished_children(bool block_ok) { topic_set_t reaptopics{}; generation_list_t gens{}; gens.fill(invalid_generation); - job_iterator_t jobs; - while (auto *j = jobs.next()) { + for (const auto j: jobs()) { for (const auto &proc : j->processes) { if (auto mtopic = j->reap_topic_for_process(proc.get())) { topic_t topic = *mtopic; @@ -390,8 +372,7 @@ static void process_mark_finished_children(bool block_ok) { // We got some changes. Since we last checked we received SIGCHLD, and or HUP/INT. // Update the hup/int generations and reap any reapable processes. - jobs.reset(); - while (auto *j = jobs.next()) { + for (const auto j : jobs()) { for (const auto &proc : j->processes) { if (auto mtopic = j->reap_topic_for_process(proc.get())) { // Update the signal hup/int gen. @@ -484,7 +465,7 @@ static bool process_clean_after_marking(bool allow_interactive) { // avoid infinite recursion). static bool locked = false; if (locked) { - return 0; + return false; } locked = true; @@ -492,9 +473,10 @@ static bool process_clean_after_marking(bool allow_interactive) { // don't try to print in that case (#3222) const bool interactive = allow_interactive && cur_term != NULL; - job_iterator_t jobs; - const bool only_one_job = jobs.count() == 1; - while (job_t *const j = jobs.next()) { + bool erased = false; + const bool only_one_job = jobs().size() == 1; + for (auto itr = jobs().begin(); itr != jobs().end(); itr = (erased ? itr : (std::advance(itr, 1), itr)), erased = false) { + job_t *j = itr->get(); // If we are reaping only jobs who do not need status messages sent to the console, do not // consider reaping jobs that need status messages. if ((!j->get_flag(job_flag_t::SKIP_NOTIFICATION)) && (!interactive) && @@ -587,7 +569,8 @@ static bool process_clean_after_marking(bool allow_interactive) { } proc_fire_event(L"JOB_EXIT", event_type_t::job_exit, j->job_id, 0); - job_remove(j); + itr = jobs().erase(itr); + erased = true; } else if (j->is_stopped() && !j->get_flag(job_flag_t::NOTIFIED)) { // Notify the user about newly stopped jobs. if (!j->get_flag(job_flag_t::SKIP_NOTIFICATION)) { @@ -663,10 +646,7 @@ unsigned long proc_get_jiffies(process_t *p) { /// Update the CPU time for all jobs. void proc_update_jiffies() { - job_t *job; - job_iterator_t j; - - for (job = j.next(); job; job = j.next()) { + for (auto job : jobs()) { for (process_ptr_t &p : job->processes) { gettimeofday(&p->last_time, 0); p->last_jiffies = proc_get_jiffies(p.get()); @@ -901,8 +881,7 @@ void job_t::continue_job(bool send_sigcont) { void proc_sanity_check() { const job_t *fg_job = NULL; - job_iterator_t jobs; - while (const job_t *j = jobs.next()) { + for (const auto j : jobs()) { if (!j->is_constructed()) continue; // More than one foreground job? @@ -912,7 +891,7 @@ void proc_sanity_check() { fg_job->command_wcstr(), j->command_wcstr()); sanity_lose(); } - fg_job = j; + fg_job = j.get(); } for (const process_ptr_t &p : j->processes) { @@ -959,9 +938,7 @@ void proc_wait_any() { } void hup_background_jobs() { - job_iterator_t jobs; - - while (job_t *j = jobs.next()) { + for (auto j : jobs()) { // Make sure we don't try to SIGHUP the calling builtin if (j->pgid == INVALID_PID || !j->get_flag(job_flag_t::JOB_CONTROL)) { continue; diff --git a/src/proc.h b/src/proc.h index 716fd42f7..dbc899a44 100644 --- a/src/proc.h +++ b/src/proc.h @@ -456,27 +456,8 @@ typedef std::list> job_list_t; bool job_list_is_empty(void); -/// A class to aid iteration over jobs list -class job_iterator_t { - job_list_t *const job_list; - job_list_t::iterator current, end; - - public: - void reset(void); - - job_t *next() { - job_t *job = NULL; - if (current != end) { - job = current->get(); - ++current; - } - return job; - } - - explicit job_iterator_t(job_list_t &jobs); - job_iterator_t(); - size_t count() const; -}; +/// A helper function to more easily access the job list +job_list_t &jobs(); /// Whether a universal variable barrier roundtrip has already been made for the currently executing /// command. Such a roundtrip only needs to be done once on a given command, unless a universal diff --git a/src/reader.cpp b/src/reader.cpp index 409e69b46..e2c072700 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2229,8 +2229,7 @@ void reader_bg_job_warning() { std::fputws(_(L"There are still jobs active:\n"), stdout); std::fputws(_(L"\n PID Command\n"), stdout); - job_iterator_t jobs; - while (job_t *j = jobs.next()) { + for (auto j : jobs()) { if (!j->is_completed()) { std::fwprintf(stdout, L"%6d %ls\n", j->processes[0]->pid, j->command_wcstr()); } @@ -2254,8 +2253,7 @@ static void handle_end_loop() { } bool bg_jobs = false; - job_iterator_t jobs; - while (const job_t *j = jobs.next()) { + for (const auto j : jobs()) { if (!j->is_completed()) { bg_jobs = true; break; From 6fab7836473b0012fb5eed81c4d7c9b0610810a4 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Sun, 30 Dec 2018 23:53:26 -0600 Subject: [PATCH 0182/1732] Convert job_list to a dequeue again Now that we have cleaned up access to the job list and removed transparent invalidation of iterators, it is safe to convert it to a dequeue. --- src/parser.cpp | 2 +- src/proc.cpp | 2 +- src/proc.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 2a94a6b8e..d6751dac0 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -580,7 +580,7 @@ void parser_t::job_promote(job_t *job) { assert(loc != my_job_list.end()); // Move the job to the beginning. - my_job_list.splice(my_job_list.begin(), my_job_list, loc); + std::rotate(my_job_list.begin(), loc, my_job_list.end()); } job_t *parser_t::job_get(job_id_t id) { diff --git a/src/proc.cpp b/src/proc.cpp index 2f0dc6b12..b556d1cc5 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -475,7 +475,7 @@ static bool process_clean_after_marking(bool allow_interactive) { bool erased = false; const bool only_one_job = jobs().size() == 1; - for (auto itr = jobs().begin(); itr != jobs().end(); itr = (erased ? itr : (std::advance(itr, 1), itr)), erased = false) { + for (auto itr = jobs().begin(); itr != jobs().end(); itr = erased ? itr : itr + 1, erased = false) { job_t *j = itr->get(); // If we are reaping only jobs who do not need status messages sent to the console, do not // consider reaping jobs that need status messages. diff --git a/src/proc.h b/src/proc.h index dbc899a44..e7106dabe 100644 --- a/src/proc.h +++ b/src/proc.h @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include @@ -451,8 +451,8 @@ extern bool is_login; /// nesting level. extern int is_event; -// List of jobs. We sometimes mutate this while iterating - hence it must be a list, not a vector -typedef std::list> job_list_t; +// List of jobs. +typedef std::deque> job_list_t; bool job_list_is_empty(void); From 1f59976c2c53cc58f2b2872ea165e3b2bc026dae Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Mon, 31 Dec 2018 00:24:32 -0600 Subject: [PATCH 0183/1732] Further clean up job list manipulation --- src/proc.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/proc.cpp b/src/proc.cpp index b556d1cc5..1530cdb9c 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -107,10 +107,10 @@ void job_t::promote() { } void proc_destroy() { - for (auto job = jobs().begin(); job != jobs().end(); ++job) { - debug(2, L"freeing leaked job %ls", (*job)->command_wcstr()); - job = jobs().erase(job); + for (const auto job : jobs()) { + debug(2, L"freeing leaked job %ls", job->command_wcstr()); } + jobs().clear(); } void proc_set_last_statuses(statuses_t s) { @@ -485,12 +485,11 @@ static bool process_clean_after_marking(bool allow_interactive) { } for (const process_ptr_t &p : j->processes) { - if (!p->completed) continue; - - if (!p->pid) continue; + if (!p->completed || !p->pid) { + continue; + } auto s = p->status; - // TODO: The generic process-exit event is useless and unused. // Remove this in future. // Update: This event is used for cleaning up the psub temporary files and folders. From d4d5c03a03636df0293b2056fbf847e08822a541 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 2 Jan 2019 12:10:54 -0600 Subject: [PATCH 0184/1732] Clean up invalid job id detection in `fg` builtin --- src/builtin_fg.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/builtin_fg.cpp b/src/builtin_fg.cpp index 0ef092740..befff322c 100644 --- a/src/builtin_fg.cpp +++ b/src/builtin_fg.cpp @@ -35,8 +35,8 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { job_t *job = nullptr; if (optind == argc) { - // Select last constructed job (I.e. first job in the job que) that is possible to put in - // the foreground. + // Select last constructed job (i.e. first job in the job queue) that can be brought + // to the foreground. for (auto j : jobs()) { if (j->is_constructed() && (!j->is_completed()) && @@ -51,15 +51,12 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { } } else if (optind + 1 < argc) { // Specifying more than one job to put to the foreground is a syntax error, we still - // try to locate the job argv[1], since we want to know if this is an ambigous job - // specification or if this is an malformed job id. - int pid; + // try to locate the job $argv[1], since we need to determine which error message to + // emit (ambigous job specification vs malformed job id). bool found_job = false; - - pid = fish_wcstoi(argv[optind]); - if (!(errno || pid < 0)) { - job = job_t::from_pid(pid); - if (job) found_job = true; + int pid = fish_wcstoi(argv[optind]); + if (errno == 0 && pid > 0) { + found_job = (job_t::from_pid(pid) != nullptr); } if (found_job) { @@ -68,9 +65,8 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { streams.err.append_format(_(L"%ls: '%ls' is not a job\n"), cmd, argv[optind]); } + job = nullptr; builtin_print_error_trailer(parser, streams.err, cmd); - - job = 0; } else { int pid = abs(fish_wcstoi(argv[optind])); if (errno) { @@ -85,7 +81,7 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { streams.err.append_format(_(L"%ls: Can't put job %d, '%ls' to foreground because " L"it is not under job control\n"), cmd, pid, job->command_wcstr()); - job = 0; + job = nullptr; } } } From 36f3a6d7e05ff55ac4b3e306c6c4c4c04d2a828f Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 20 Mar 2019 22:37:26 -0500 Subject: [PATCH 0185/1732] Use const auto for all jobs --- src/builtin_bg.cpp | 2 +- src/builtin_disown.cpp | 4 ++-- src/builtin_fg.cpp | 2 +- src/builtin_jobs.cpp | 4 ++-- src/builtin_wait.cpp | 8 ++++---- src/parse_execution.cpp | 2 +- src/parser.cpp | 2 +- src/proc.cpp | 10 +++++----- src/reader.cpp | 4 ++-- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/builtin_bg.cpp b/src/builtin_bg.cpp index 9af0cbbfc..e737edae4 100644 --- a/src/builtin_bg.cpp +++ b/src/builtin_bg.cpp @@ -52,7 +52,7 @@ int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (optind == argc) { // No jobs were specified so use the most recent (i.e., last) job. job_t *job = nullptr; - for (auto j : jobs()) { + for (const auto &j : jobs()) { if (j->is_stopped() && j->get_flag(job_flag_t::JOB_CONTROL) && (!j->is_completed())) { job = j.get(); break; diff --git a/src/builtin_disown.cpp b/src/builtin_disown.cpp index dc766cc34..ad965b693 100644 --- a/src/builtin_disown.cpp +++ b/src/builtin_disown.cpp @@ -65,7 +65,7 @@ int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) { // Foreground jobs can be disowned. // Even jobs that aren't under job control can be disowned! job_t *job = nullptr; - for (auto j : jobs()) { + for (const auto &j : jobs()) { if (j->is_constructed() && (!j->is_completed())) { job = j.get(); break; @@ -104,7 +104,7 @@ int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) { } // Disown all target jobs - for (auto j : jobs) { + for (const auto &j : jobs) { retval |= disown_job(cmd, parser, streams, j); } } diff --git a/src/builtin_fg.cpp b/src/builtin_fg.cpp index befff322c..5bd9221b6 100644 --- a/src/builtin_fg.cpp +++ b/src/builtin_fg.cpp @@ -38,7 +38,7 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { // Select last constructed job (i.e. first job in the job queue) that can be brought // to the foreground. - for (auto j : jobs()) { + for (const auto &j : jobs()) { if (j->is_constructed() && (!j->is_completed()) && ((j->is_stopped() || (!j->is_foreground())) && j->get_flag(job_flag_t::JOB_CONTROL))) { diff --git a/src/builtin_jobs.cpp b/src/builtin_jobs.cpp index c3673b89d..f4dab2411 100644 --- a/src/builtin_jobs.cpp +++ b/src/builtin_jobs.cpp @@ -174,7 +174,7 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) { if (print_last) { // Ignore unconstructed jobs, i.e. ourself. - for (auto j : jobs()) { + for (const auto &j : jobs()) { if (j->is_constructed() && !j->is_completed()) { builtin_jobs_print(j.get(), mode, !streams.out_is_redirected, streams); return STATUS_CMD_ERROR; @@ -215,7 +215,7 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) { } } } else { - for (auto j : jobs()) { + for (const auto &j : jobs()) { // Ignore unconstructed jobs, i.e. ourself. if (j->is_constructed() && !j->is_completed()) { builtin_jobs_print(j.get(), mode, !found && !streams.out_is_redirected, streams); diff --git a/src/builtin_wait.cpp b/src/builtin_wait.cpp index 34a687bb1..6df0d3abf 100644 --- a/src/builtin_wait.cpp +++ b/src/builtin_wait.cpp @@ -16,7 +16,7 @@ /// If a specified process has already finished but the job hasn't, parser_t::job_get_from_pid() /// doesn't work properly, so use this function in wait command. static job_id_t get_job_id_from_pid(pid_t pid) { - for (auto j : jobs()) { + for (const auto &j : jobs()) { if (j->pgid == pid) { return j->job_id; } @@ -31,7 +31,7 @@ static job_id_t get_job_id_from_pid(pid_t pid) { } static bool all_jobs_finished() { - for (auto j : jobs()) { + for (const auto &j : jobs()) { // If any job is not completed, return false. // If there are stopped jobs, they are ignored. if (j->is_constructed() && !j->is_completed() && !j->is_stopped()) { @@ -48,7 +48,7 @@ static bool any_jobs_finished(size_t jobs_len) { if (jobs_len != jobs().size()) { return true; } - for (auto j : jobs()) { + for (const auto &j : jobs()) { // If any job is completed, return true. if (j->is_constructed() && (j->is_completed() || j->is_stopped())) { return true; @@ -139,7 +139,7 @@ static bool match_pid(const wcstring &cmd, const wchar_t *proc) { static bool find_job_by_name(const wchar_t *proc, std::vector &ids) { bool found = false; - for (const auto j : jobs()) { + for (const auto &j : jobs()) { if (j->command_is_empty()) continue; if (match_pid(j->command(), proc)) { diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 8bd145c77..2af130d63 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -785,7 +785,7 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process( static uint32_t last_exec_run_counter = -1; if (process_type == process_type_t::exec && shell_is_interactive()) { bool have_bg = false; - for (const auto bg : jobs()) { + for (const auto &bg : jobs()) { // The assumption here is that if it is a foreground job, // it's related to us. // This stops us from asking if we're doing `exec` inside a function. diff --git a/src/parser.cpp b/src/parser.cpp index d6751dac0..4b0a75082 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -597,7 +597,7 @@ job_t *parser_t::job_get_from_pid(pid_t pid) const { return 0; } - for (auto job : jobs()) { + for (const auto &job : jobs()) { if (job->pgid == pgid) { for (const process_ptr_t &p : job->processes) { if (p->pid == pid) { diff --git a/src/proc.cpp b/src/proc.cpp index 1530cdb9c..cc4705ffb 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -107,7 +107,7 @@ void job_t::promote() { } void proc_destroy() { - for (const auto job : jobs()) { + for (const auto &job : jobs()) { debug(2, L"freeing leaked job %ls", job->command_wcstr()); } jobs().clear(); @@ -372,7 +372,7 @@ static void process_mark_finished_children(bool block_ok) { // We got some changes. Since we last checked we received SIGCHLD, and or HUP/INT. // Update the hup/int generations and reap any reapable processes. - for (const auto j : jobs()) { + for (const auto &j : jobs()) { for (const auto &proc : j->processes) { if (auto mtopic = j->reap_topic_for_process(proc.get())) { // Update the signal hup/int gen. @@ -645,7 +645,7 @@ unsigned long proc_get_jiffies(process_t *p) { /// Update the CPU time for all jobs. void proc_update_jiffies() { - for (auto job : jobs()) { + for (const auto &job : jobs()) { for (process_ptr_t &p : job->processes) { gettimeofday(&p->last_time, 0); p->last_jiffies = proc_get_jiffies(p.get()); @@ -880,7 +880,7 @@ void job_t::continue_job(bool send_sigcont) { void proc_sanity_check() { const job_t *fg_job = NULL; - for (const auto j : jobs()) { + for (const auto &j : jobs()) { if (!j->is_constructed()) continue; // More than one foreground job? @@ -937,7 +937,7 @@ void proc_wait_any() { } void hup_background_jobs() { - for (auto j : jobs()) { + for (const auto &j : jobs()) { // Make sure we don't try to SIGHUP the calling builtin if (j->pgid == INVALID_PID || !j->get_flag(job_flag_t::JOB_CONTROL)) { continue; diff --git a/src/reader.cpp b/src/reader.cpp index e2c072700..6ffd3da31 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2229,7 +2229,7 @@ void reader_bg_job_warning() { std::fputws(_(L"There are still jobs active:\n"), stdout); std::fputws(_(L"\n PID Command\n"), stdout); - for (auto j : jobs()) { + for (const auto &j : jobs()) { if (!j->is_completed()) { std::fwprintf(stdout, L"%6d %ls\n", j->processes[0]->pid, j->command_wcstr()); } @@ -2253,7 +2253,7 @@ static void handle_end_loop() { } bool bg_jobs = false; - for (const auto j : jobs()) { + for (const auto &j : jobs()) { if (!j->is_completed()) { bg_jobs = true; break; From 06adb1dc38f1b87dcd3e9a97a8a1f4adc55989c7 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 20 Mar 2019 22:57:38 -0500 Subject: [PATCH 0186/1732] Store jobs to erase in separate list --- src/proc.cpp | 47 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/proc.cpp b/src/proc.cpp index cc4705ffb..81584133b 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -473,10 +473,9 @@ static bool process_clean_after_marking(bool allow_interactive) { // don't try to print in that case (#3222) const bool interactive = allow_interactive && cur_term != NULL; - bool erased = false; + static std::vector erase_list; const bool only_one_job = jobs().size() == 1; - for (auto itr = jobs().begin(); itr != jobs().end(); itr = erased ? itr : itr + 1, erased = false) { - job_t *j = itr->get(); + for (const auto &j : jobs()) { // If we are reaping only jobs who do not need status messages sent to the console, do not // consider reaping jobs that need status messages. if ((!j->get_flag(job_flag_t::SKIP_NOTIFICATION)) && (!interactive) && @@ -554,7 +553,7 @@ static bool process_clean_after_marking(bool allow_interactive) { if (j->is_completed()) { if (!j->is_foreground() && !j->get_flag(job_flag_t::NOTIFIED) && !j->get_flag(job_flag_t::SKIP_NOTIFICATION)) { - print_job_status(j, JOB_ENDED); + print_job_status(j.get(), JOB_ENDED); found = true; } // TODO: The generic process-exit event is useless and unused. @@ -568,22 +567,52 @@ static bool process_clean_after_marking(bool allow_interactive) { } proc_fire_event(L"JOB_EXIT", event_type_t::job_exit, j->job_id, 0); - itr = jobs().erase(itr); - erased = true; + erase_list.push_back(j.get()); } else if (j->is_stopped() && !j->get_flag(job_flag_t::NOTIFIED)) { // Notify the user about newly stopped jobs. if (!j->get_flag(job_flag_t::SKIP_NOTIFICATION)) { - print_job_status(j, JOB_STOPPED); + print_job_status(j.get(), JOB_STOPPED); found = true; } j->set_flag(job_flag_t::NOTIFIED, true); } } - if (found) fflush(stdout); + if (!erase_list.empty()) { + // The intersection of the two lists is typically O(m*n), but we know the order + // of the entries in erase_list is the same as their matches in jobs(), so we can + // use that to our advantage. + auto to_erase = erase_list.begin(); + jobs().erase(std::remove_if(jobs().begin(), jobs().end(), + [&to_erase](const shared_ptr &j) { + if (to_erase == erase_list.end()) { + return false; + } + if (*to_erase == j.get()) { + ++to_erase; + return true; + } + return false; + }), jobs().end()); + + if (should_debug(2)) { + // Assertions prevent the application from continuing in case of invalid state. If we + // did not remove all objects from the list, it's not bad enough to abort and die, but + // leave this check here so that we can be alerted to the situtaion if running at a + // higher debug level. Or just remove it. But I wouldn't want to be the person that has + // to debug this without even this soft assertion in place when some C++ standard + // library decides to make std::remove_if iterate backwards or in random order! + assert(to_erase == erase_list.end() + && "Not all jobs slated for erasure have been erased!"); + } + } + erase_list.clear(); + + if (found) { + fflush(stdout); + } locked = false; - return found; } From 7f5e58ae69759dc1f930cd26500f3df8cb1716a7 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Thu, 28 Mar 2019 18:16:22 -0500 Subject: [PATCH 0187/1732] Only send JOB_EXIT after the job has been actually erased --- src/proc.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/proc.cpp b/src/proc.cpp index 81584133b..b1bb87431 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -461,7 +461,7 @@ static bool process_clean_after_marking(bool allow_interactive) { ASSERT_IS_MAIN_THREAD(); bool found = false; - // this function may fire an event handler, we do not want to call ourselves recursively (to + // This function may fire an event handler, we do not want to call ourselves recursively (to // avoid infinite recursion). static bool locked = false; if (locked) { @@ -469,11 +469,13 @@ static bool process_clean_after_marking(bool allow_interactive) { } locked = true; - // this may be invoked in an exit handler, after the TERM has been torn down - // don't try to print in that case (#3222) + // This may be invoked in an exit handler, after the TERM has been torn down + // Don't try to print in that case (#3222) const bool interactive = allow_interactive && cur_term != NULL; - static std::vector erase_list; + // If we ever drop the `static bool locked` above, this should be changed to a local or + // thread-local vector instead of a static vector. It is only static to reduce heap allocations. + static std::vector> erase_list; const bool only_one_job = jobs().size() == 1; for (const auto &j : jobs()) { // If we are reaping only jobs who do not need status messages sent to the console, do not @@ -565,9 +567,8 @@ static bool process_clean_after_marking(bool allow_interactive) { if (j->pgid != INVALID_PID) { proc_fire_event(L"JOB_EXIT", event_type_t::exit, -j->pgid, 0); } - proc_fire_event(L"JOB_EXIT", event_type_t::job_exit, j->job_id, 0); - erase_list.push_back(j.get()); + erase_list.push_back(j); } else if (j->is_stopped() && !j->get_flag(job_flag_t::NOTIFIED)) { // Notify the user about newly stopped jobs. if (!j->get_flag(job_flag_t::SKIP_NOTIFICATION)) { @@ -585,10 +586,7 @@ static bool process_clean_after_marking(bool allow_interactive) { auto to_erase = erase_list.begin(); jobs().erase(std::remove_if(jobs().begin(), jobs().end(), [&to_erase](const shared_ptr &j) { - if (to_erase == erase_list.end()) { - return false; - } - if (*to_erase == j.get()) { + if (to_erase != erase_list.end() && *to_erase == j) { ++to_erase; return true; } @@ -606,6 +604,12 @@ static bool process_clean_after_marking(bool allow_interactive) { && "Not all jobs slated for erasure have been erased!"); } } + + // Only now notify any listeners of the job exit, so that the contract isn't violated + for (const auto &j : erase_list) { + proc_fire_event(L"JOB_EXIT", event_type_t::job_exit, j->job_id, 0); + } + erase_list.clear(); if (found) { From f8b2e818ed6606e4fd10bc416f2f6c9ad8b49f86 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Thu, 28 Mar 2019 18:16:51 -0500 Subject: [PATCH 0188/1732] Remove legacy generic process/job exit events --- src/proc.cpp | 16 ---------------- tests/signal.out | 9 --------- 2 files changed, 25 deletions(-) diff --git a/src/proc.cpp b/src/proc.cpp index b1bb87431..24b266920 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -491,13 +491,6 @@ static bool process_clean_after_marking(bool allow_interactive) { } auto s = p->status; - // TODO: The generic process-exit event is useless and unused. - // Remove this in future. - // Update: This event is used for cleaning up the psub temporary files and folders. - // Removing it breaks the psub tests as a result. - proc_fire_event(L"PROCESS_EXIT", event_type_t::exit, p->pid, - (s.signal_exited() ? -1 : s.exit_code())); - // Ignore signal SIGPIPE.We issue it ourselves to the pipe writer when the pipe reader // dies. if (!s.signal_exited() || s.signal_code() == SIGPIPE) { @@ -558,15 +551,6 @@ static bool process_clean_after_marking(bool allow_interactive) { print_job_status(j.get(), JOB_ENDED); found = true; } - // TODO: The generic process-exit event is useless and unused. - // Remove this in future. - // Don't fire the exit-event for jobs with pgid INVALID_PID. - // That's our "sentinel" pgid, for jobs that don't (yet) have a pgid, - // or jobs that consist entirely of builtins (and hence don't have a process). - // This causes issues if fish is PID 2, which is quite common on WSL. See #4582. - if (j->pgid != INVALID_PID) { - proc_fire_event(L"JOB_EXIT", event_type_t::exit, -j->pgid, 0); - } erase_list.push_back(j); } else if (j->is_stopped() && !j->get_flag(job_flag_t::NOTIFIED)) { diff --git a/tests/signal.out b/tests/signal.out index 10aa9b5f3..f2cd4188c 100644 --- a/tests/signal.out +++ b/tests/signal.out @@ -1,17 +1,8 @@ ALRM received command false: -PROCESS_EXIT 1 -JOB_EXIT 0 command true: -PROCESS_EXIT 0 -JOB_EXIT 0 command false | true: -PROCESS_EXIT 1 -PROCESS_EXIT 0 -JOB_EXIT 0 This is the process whose exit event shuld be blocked This should come before the event handler -PROCESS_EXIT 0 -JOB_EXIT 0 Now event handler should have run PROCESS_EXIT 0 From 0be79038590d3473b75252bf50ade2f62ea9c207 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Thu, 28 Mar 2019 19:01:10 -0500 Subject: [PATCH 0189/1732] Drop realpath test built on assumption PWD cannot be a symlink The final test in `realpath.in` was based on the no-longer-valid assumption that $PWD cannot be a symlink. Since the recent changes in fish 3.0 to allow `cd`ing into "virtual" directories preserving symlinks as-is, when `make test` was run from a path that contained a symlink component, this test would fail the `pwd-resolved-to-itself` check. As the test is not designed to initialize then cd into an absolute path guaranteed to not be symbolic, so this final check is just wrong. --- tests/realpath.in | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/realpath.in b/tests/realpath.in index fc39889fe..abaccf4cd 100644 --- a/tests/realpath.in +++ b/tests/realpath.in @@ -73,13 +73,4 @@ else echo "fish-symlink/symlink_file not handled correctly: $real_path != expected_real_path" >&2 end -# The $PWD should undergo no further transformations because it should already -# be a "realpath". -set -l real_path (builtin realpath $PWD) -if test "$real_path" = "$PWD" - echo "pwd-resolved-to-itself" -else - echo "unexpected pwd-resolved-to-itself failure: $real_path != $PWD" >&2 -end - exit 0 From 4aea4c09b310e23ae5b06b9dd195ec8106dd6355 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Thu, 28 Mar 2019 22:08:19 -0500 Subject: [PATCH 0190/1732] Optimize identification of deferred process --- src/exec.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/exec.cpp b/src/exec.cpp index ddf612d9d..90bcd15d6 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -993,21 +993,21 @@ static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr< // This should show the output as it comes, not buffer until the end. // Any such process (only one per job) will be called the "deferred" process. static process_t *get_deferred_process(const shared_ptr &j) { - process_t *last_internal = nullptr; - for (const auto &p : j->processes) { + // By enumerating in reverse order, we can avoid walking the entire list + for (auto i = j->processes.rbegin(); i != j->processes.rend(); ++i) { + const auto &p = *i; if (p->type == process_type_t::exec) { // No tail reordering for execs. return nullptr; } else if (p->type != process_type_t::external) { - last_internal = p.get(); + if (p->is_last_in_job) { + return nullptr; + } + debug(1, "Deferring execution of %ls", p->argv0()); + return p.get(); } } - if (last_internal && !last_internal->is_last_in_job) { - // This is the last internal process, and it pipes to an external process. - return last_internal; - } else { - return nullptr; - } + return nullptr; } bool exec_job(parser_t &parser, shared_ptr j) { @@ -1086,17 +1086,17 @@ bool exec_job(parser_t &parser, shared_ptr j) { } pipe_next_read = std::move(pipes->read); proc_pipes.write = std::move(pipes->write); - } - if (p.get() == deferred_process) { - deferred_pipes = std::move(proc_pipes); - } else { - if (!exec_process_in_job(parser, p.get(), j, std::move(proc_pipes), all_ios, - deferred_pipes, stdout_read_limit)) { - exec_error = true; - break; + // The deferred process can never be the last in the job + if (p.get() == deferred_process) { + deferred_pipes = std::move(proc_pipes); } } + if (!exec_process_in_job(parser, p.get(), j, std::move(proc_pipes), all_ios, deferred_pipes, + stdout_read_limit)) { + exec_error = true; + break; + } } pipe_next_read.close(); From 7231d86676ddea2c27ee3e6d2d04f98c23d01534 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Thu, 28 Mar 2019 20:16:57 -0700 Subject: [PATCH 0191/1732] Fix the tests Remove 'pwd-resolved-to-itself' message --- tests/realpath.out | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/realpath.out b/tests/realpath.out index 5a8ac9014..56102523a 100644 --- a/tests/realpath.out +++ b/tests/realpath.out @@ -8,4 +8,3 @@ nonexistent-file in PWD correctly converted fish-symlink handled correctly fish-symlink/nonexistent-file-relative-to-a-symlink correctly converted fish-symlink/symlink_file handled correctly -pwd-resolved-to-itself From 0b11b8cffbcfc2c2512227904ba666f929775b1a Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Thu, 28 Mar 2019 20:22:58 -0700 Subject: [PATCH 0192/1732] Revert "Optimize identification of deferred process" This reverts commit 4aea4c09b310e23ae5b06b9dd195ec8106dd6355. Said commit broke many tests --- src/exec.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/exec.cpp b/src/exec.cpp index 90bcd15d6..ddf612d9d 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -993,21 +993,21 @@ static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr< // This should show the output as it comes, not buffer until the end. // Any such process (only one per job) will be called the "deferred" process. static process_t *get_deferred_process(const shared_ptr &j) { - // By enumerating in reverse order, we can avoid walking the entire list - for (auto i = j->processes.rbegin(); i != j->processes.rend(); ++i) { - const auto &p = *i; + process_t *last_internal = nullptr; + for (const auto &p : j->processes) { if (p->type == process_type_t::exec) { // No tail reordering for execs. return nullptr; } else if (p->type != process_type_t::external) { - if (p->is_last_in_job) { - return nullptr; - } - debug(1, "Deferring execution of %ls", p->argv0()); - return p.get(); + last_internal = p.get(); } } - return nullptr; + if (last_internal && !last_internal->is_last_in_job) { + // This is the last internal process, and it pipes to an external process. + return last_internal; + } else { + return nullptr; + } } bool exec_job(parser_t &parser, shared_ptr j) { @@ -1086,16 +1086,16 @@ bool exec_job(parser_t &parser, shared_ptr j) { } pipe_next_read = std::move(pipes->read); proc_pipes.write = std::move(pipes->write); - - // The deferred process can never be the last in the job - if (p.get() == deferred_process) { - deferred_pipes = std::move(proc_pipes); - } } - if (!exec_process_in_job(parser, p.get(), j, std::move(proc_pipes), all_ios, deferred_pipes, - stdout_read_limit)) { - exec_error = true; - break; + + if (p.get() == deferred_process) { + deferred_pipes = std::move(proc_pipes); + } else { + if (!exec_process_in_job(parser, p.get(), j, std::move(proc_pipes), all_ios, + deferred_pipes, stdout_read_limit)) { + exec_error = true; + break; + } } } pipe_next_read.close(); From a361d987f86f91bc56e1769969985d6b5a1568ef Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 29 Mar 2019 19:08:25 +0100 Subject: [PATCH 0193/1732] docs: Add toctree back Apparently there must indeed be a toctree somewhere in the document to get the links to the other docs to show up. Even a ":hidden:" toctree doesn't help - that just leads to an empty toc in the sidebar (no idea yet where that's defined!). I've added it to the end so it's not that weird "Commands" section in the middle. [ci skip] --- sphinx_doc_src/index.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index bc62c5d7f..c0e6a501c 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -1808,3 +1808,16 @@ If you have a question not answered by this documentation, there are several ave If you have an improvement for fish, you can submit it via the mailing list or the GitHub page. + +.. _other_pages: + +Other help pages +================ +.. toctree:: + :maxdepth: 1 + + commands + design + tutorial + faq + license From ebc0bee40415a268cfc3b82a3f2109d1fa0d3307 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 29 Mar 2019 19:09:57 +0100 Subject: [PATCH 0194/1732] docs: Correct link We're gonna have a bunch of these, aren't we? [ci skip] --- sphinx_doc_src/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index c0e6a501c..3065d1cd8 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -1375,7 +1375,7 @@ Builtin commands Many other shells have a large library of builtin commands. Most of these commands are also available as standalone commands, but have been implemented in the shell anyway. To avoid code duplication, and to avoid the confusion of subtly differing versions of the same command, ``fish`` generally only implements builtins for actions which cannot be performed by a regular command. -For a list of all builtins, functions and commands shipped with fish, see the `table of contents <#toc-commands>`_. The documentation is also available by using the ``--help`` switch of the command. +For a list of all builtins, functions and commands shipped with fish, see the `list of commands `_. The documentation is also available by using the ``--help`` switch of the command. .. _editor: From b8570a9e8a4665c1368b90467d9fac15b7d11918 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 29 Mar 2019 20:05:42 +0100 Subject: [PATCH 0195/1732] docs/cmds/string: Improve synopsis This both formats it as a code-block, and adds the synopsis of each subcommand to the corresponding section again so you don't need to scroll back-and-forth so much. [ci skip] --- sphinx_doc_src/cmds/string.rst | 79 ++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/sphinx_doc_src/cmds/string.rst b/sphinx_doc_src/cmds/string.rst index 99e7970d8..3ed356a02 100644 --- a/sphinx_doc_src/cmds/string.rst +++ b/sphinx_doc_src/cmds/string.rst @@ -4,28 +4,33 @@ string - manipulate strings Synopsis -------- -string escape [(-n | --no-quoted)] [--style=xxx] [STRING...] -string join [(-q | --quiet)] SEP [STRING...] -string join0 [(-q | --quiet)] [STRING...] -string length [(-q | --quiet)] [STRING...] -string lower [(-q | --quiet)] [STRING...] -string match [(-a | --all)] [(-e | --entire)] [(-i | --ignore-case)] [(-r | --regex)] - [(-n | --index)] [(-q | --quiet)] [(-v | --invert)] PATTERN [STRING...] -string repeat [(-n | --count) COUNT] [(-m | --max) MAX] [(-N | --no-newline)] - [(-q | --quiet)] [STRING...] -string replace [(-a | --all)] [(-f | --filter)] [(-i | --ignore-case)] [(-r | --regex)] - [(-q | --quiet)] PATTERN REPLACEMENT [STRING...] -string split [(-m | --max) MAX] [(-n | --no-empty)] [(-q | --quiet)] [(-r | --right)] SEP - [STRING...] -string split0 [(-m | --max) MAX] [(-n | --no-empty)] [(-q | --quiet)] [(-r | --right)] - [STRING...] -string sub [(-s | --start) START] [(-l | --length) LENGTH] [(-q | --quiet)] - [STRING...] -string trim [(-l | --left)] [(-r | --right)] [(-c | --chars CHARS)] - [(-q | --quiet)] [STRING...] -string unescape [--style=xxx] [STRING...] -string upper [(-q | --quiet)] [STRING...] +``string escape [(-n | --no-quoted)] [--style=xxx] [STRING...]`` +``string join [(-q | --quiet)] SEP [STRING...]`` + +``string join0 [(-q | --quiet)] [STRING...]`` + +``string length [(-q | --quiet)] [STRING...]`` + +``string lower [(-q | --quiet)] [STRING...]`` + +``string match [(-a | --all)] [(-e | --entire)] [(-i | --ignore-case)] [(-r | --regex)] [(-n | --index)] [(-q | --quiet)] [(-v | --invert)] PATTERN [STRING...]`` + +``string repeat [(-n | --count) COUNT] [(-m | --max) MAX] [(-N | --no-newline)] [(-q | --quiet)] [STRING...]`` + +``string replace [(-a | --all)] [(-f | --filter)] [(-i | --ignore-case)] [(-r | --regex)] [(-q | --quiet)] PATTERN REPLACEMENT [STRING...]`` + +``string split [(-m | --max) MAX] [(-n | --no-empty)] [(-q | --quiet)] [(-r | --right)] SEP [STRING...]`` + +``string split0 [(-m | --max) MAX] [(-n | --no-empty)] [(-q | --quiet)] [(-r | --right)] [STRING...]`` + +``string sub [(-s | --start) START] [(-l | --length) LENGTH] [(-q | --quiet)] [STRING...]`` + +``string trim [(-l | --left)] [(-r | --right)] [(-c | --chars CHARS)] [(-q | --quiet)] [STRING...]`` + +``string unescape [--style=xxx] [STRING...]`` + +``string upper [(-q | --quiet)] [STRING...]`` Description @@ -41,8 +46,10 @@ Most subcommands accept a ``-q`` or ``--quiet`` switch, which suppresses the usu The following subcommands are available. -"escape" subcommand -------------------- +"escape" and "unescape" subcommands +----------------------------------- + +``string escape [(-n | --no-quoted)] [--style=xxx] [STRING...]`` ``string escape`` escapes each STRING in one of three ways. The first is ``--style=script``. This is the default. It alters the string such that it can be passed back to ``eval`` to produce the original argument again. By default, all special characters are escaped, and quotes are used to simplify the output when possible. If ``-n`` or ``--no-quoted`` is given, the simplifying quoted format is not used. Exit status: 0 if at least one string was escaped, or 1 otherwise. @@ -52,31 +59,43 @@ The following subcommands are available. ``--style=regex`` escapes an input string for literal matching within a regex expression. The string is first converted to UTF-8 before being encoded. +``string unescape [--style=xxx] [STRING...]`` + ``string unescape`` performs the inverse of the ``string escape`` command. If the string to be unescaped is not properly formatted it is ignored. For example, doing ``string unescape --style=var (string escape --style=var $str)`` will return the original string. There is no support for unescaping ``--style=regex``. "join" subcommand ----------------- +``string join [(-q | --quiet)] SEP [STRING...]`` + ``string join`` joins its STRING arguments into a single string separated by SEP, which can be an empty string. Exit status: 0 if at least one join was performed, or 1 otherwise. "join0" subcommand ------------------ +``string join0 [(-q | --quiet)] [STRING...]`` + ``string join`` joins its STRING arguments into a single string separated by the zero byte (NUL), and adds a trailing NUL. This is most useful in conjunction with tools that accept NUL-delimited input, such as ``sort -z``. Exit status: 0 if at least one join was performed, or 1 otherwise. "length" subcommand ------------------- +``string length [(-q | --quiet)] [STRING...]`` + ``string length`` reports the length of each string argument in characters. Exit status: 0 if at least one non-empty STRING was given, or 1 otherwise. "lower" subcommand ------------------ +``string lower [(-q | --quiet)] [STRING...]`` + ``string lower`` converts each string argument to lowercase. Exit status: 0 if at least one string was converted to lowercase, else 1. This means that in conjunction with the ``-q`` flag you can readily test whether a string is already lowercase. "match" subcommand ------------------ +``string match [(-a | --all)] [(-e | --entire)] [(-i | --ignore-case)] [(-r | --regex)] [(-n | --index)] [(-q | --quiet)] [(-v | --invert)] PATTERN [STRING...]`` + ``string match`` tests each STRING against PATTERN and prints matching substrings. Only the first match for each STRING is reported unless ``-a`` or ``--all`` is given, in which case all matches are reported. If you specify the ``-e`` or ``--entire`` then each matching string is printed including any prefix or suffix not matched by the pattern (equivalent to ``grep`` without the ``-o`` flag). You can, obviously, achieve the same result by prepending and appending ``*`` or ``.*`` depending on whether or not you have specified the ``--regex`` flag. The ``--entire`` flag is simply a way to avoid having to complicate the pattern in that fashion and make the intent of the ``string match`` clearer. Without ``--entire`` and ``--regex``, a PATTERN will need to match the entire STRING before it will be reported. @@ -94,11 +113,15 @@ Exit status: 0 if at least one match was found, or 1 otherwise. "repeat" subcommand ------------------- +``string repeat [(-n | --count) COUNT] [(-m | --max) MAX] [(-N | --no-newline)] [(-q | --quiet)] [STRING...]`` + ``string repeat`` repeats the STRING ``-n`` or ``--count`` times. The ``-m`` or ``--max`` option will limit the number of outputted char (excluding the newline). This option can be used by itself or in conjunction with ``--count``. If both ``--count`` and ``--max`` are present, max char will be outputed unless the final repeated string size is less than max, in that case, the string will repeat until count has been reached. Both ``--count`` and ``--max`` will accept a number greater than or equal to zero, in the case of zero, nothing will be outputed. If ``-N`` or ``--no-newline`` is given, the output won't contain a newline character at the end. Exit status: 0 if yielded string is not empty, 1 otherwise. "replace" subcommand -------------------- +``string replace [(-a | --all)] [(-f | --filter)] [(-i | --ignore-case)] [(-r | --regex)] [(-q | --quiet)] PATTERN REPLACEMENT [STRING...]`` + ``string replace`` is similar to ``string match`` but replaces non-overlapping matching substrings with a replacement string and prints the result. By default, PATTERN is treated as a literal substring to be matched. If ``-r`` or ``--regex`` is given, PATTERN is interpreted as a Perl-compatible regular expression, and REPLACEMENT can contain C-style escape sequences like ``\t`` as well as references to capturing groups by number or name as ``$n`` or ``${n}``. @@ -110,6 +133,8 @@ Exit status: 0 if at least one replacement was performed, or 1 otherwise. "split" subcommand ------------------ +``string split [(-m | --max) MAX] [(-n | --no-empty)] [(-q | --quiet)] [(-r | --right)] SEP [STRING...]`` + ``string split`` splits each STRING on the separator SEP, which can be an empty string. If ``-m`` or ``--max`` is specified, at most MAX splits are done on each STRING. If ``-r`` or ``--right`` is given, splitting is performed right-to-left. This is useful in combination with ``-m`` or ``--max``. With ``-n`` or ``--no-empty``, empty results are excluded from consideration (e.g. ``hello\n\nworld`` would expand to two strings and not three). Exit status: 0 if at least one split was performed, or 1 otherwise. See also ``read --delimiter``. @@ -117,6 +142,8 @@ See also ``read --delimiter``. "split0" subcommand ------------------- +``string split0 [(-m | --max) MAX] [(-n | --no-empty)] [(-q | --quiet)] [(-r | --right)] [STRING...]`` + ``string split0`` splits each STRING on the zero byte (NUL). Options are the same as ``string split`` except that no separator is given. ``split0`` has the important property that its output is not further split when used in a command substitution, allowing for the command substitution to produce elements containing newlines. This is most useful when used with Unix tools that produce zero bytes, such as ``find -print0`` or ``sort -z``. See split0 examples below. @@ -124,16 +151,22 @@ See also ``read --delimiter``. "sub" subcommand ---------------- +``string sub [(-s | --start) START] [(-l | --length) LENGTH] [(-q | --quiet)] [STRING...]`` + ``string sub`` prints a substring of each string argument. The start of the substring can be specified with ``-s`` or ``--start`` followed by a 1-based index value. Positive index values are relative to the start of the string and negative index values are relative to the end of the string. The default start value is 1. The length of the substring can be specified with ``-l`` or ``--length``. If the length is not specified, the substring continues to the end of each STRING. Exit status: 0 if at least one substring operation was performed, 1 otherwise. "trim" subcommand ----------------- +``string trim [(-l | --left)] [(-r | --right)] [(-c | --chars CHARS)] [(-q | --quiet)] [STRING...]`` + ``string trim`` removes leading and trailing whitespace from each STRING. If ``-l`` or ``--left`` is given, only leading whitespace is removed. If ``-r`` or ``--right`` is given, only trailing whitespace is trimmed. The ``-c`` or ``--chars`` switch causes the characters in CHARS to be removed instead of whitespace. Exit status: 0 if at least one character was trimmed, or 1 otherwise. "upper" subcommand ------------------ +``string upper [(-q | --quiet)] [STRING...]`` + ``string upper`` converts each string argument to uppercase. Exit status: 0 if at least one string was converted to uppercase, else 1. This means that in conjunction with the ``-q`` flag you can readily test whether a string is already uppercase. Regular Expressions From 21bac8428e805a9d8f2163f58709f8ee85824ac7 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 29 Mar 2019 20:12:28 +0100 Subject: [PATCH 0196/1732] docs/cmds/string: Fix lists sphinx _really_ likes its empty lines before lists! [ci skip] --- sphinx_doc_src/cmds/string.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sphinx_doc_src/cmds/string.rst b/sphinx_doc_src/cmds/string.rst index 3ed356a02..4009588e3 100644 --- a/sphinx_doc_src/cmds/string.rst +++ b/sphinx_doc_src/cmds/string.rst @@ -177,6 +177,7 @@ Both the ``match`` and ``replace`` subcommand support regular expressions when u In general, special characters are special by default, so ``a+`` matches one or more "a"s, while ``a\+`` matches an "a" and then a "+". ``(a+)`` matches one or more "a"s in a capturing group (``(?:XXXX)`` denotes a non-capturing group). For the replacement parameter of ``replace``, ``$n`` refers to the n-th group of the match. In the match parameter, ``\n`` (e.g. ``\1``) refers back to groups. Some features include repetitions: + - ``*`` refers to 0 or more repetitions of the previous expression - ``+`` 1 or more - ``?`` 0 or 1. @@ -185,6 +186,7 @@ Some features include repetitions: - ``{n,}`` n or more Character classes, some of the more important: + - ``.`` any character except newline - ``\d`` a decimal digit and ``\D``, not a decimal digit - ``\s`` whitespace and ``\S``, not whitespace @@ -210,12 +212,14 @@ Character classes, some of the more important: - ``[[:xdigit:]]`` : "hexadecimal digit" Groups: + - ``(...)`` is a capturing group - ``(?:...)`` is a non-capturing group - ``\n`` is a backreference (where n is the number of the group, starting with 1) - ``$n`` is a reference from the replacement expression to a group in the match expression. And some other things: + - ``\b`` denotes a word boundary, ``\B`` is not a word boundary. - ``^`` is the start of the string or line, ``$`` the end. - ``|`` is "alternation", i.e. the "or". From 408c555bd6825cb5d1839674374e5eda8c6e98ca Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 29 Mar 2019 20:15:59 +0100 Subject: [PATCH 0197/1732] docs/cmds/alias: Fix emphasis --- sphinx_doc_src/cmds/alias.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_doc_src/cmds/alias.rst b/sphinx_doc_src/cmds/alias.rst index 487b35c5c..538ab3c67 100644 --- a/sphinx_doc_src/cmds/alias.rst +++ b/sphinx_doc_src/cmds/alias.rst @@ -19,7 +19,7 @@ Description - ``NAME`` is the name of the alias - ``DEFINITION`` is the actual command to execute. The string ``$argv`` will be appended. -You cannot create an alias to a function with the same name. Note that spaces need to be escaped in the call to ``alias`` just like at the command line, _even inside quoted parts_. +You cannot create an alias to a function with the same name. Note that spaces need to be escaped in the call to ``alias`` just like at the command line, *even inside quoted parts*. The following options are available: From 3912d86ed8030f52f6a54b565409f077e49b25f7 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 29 Mar 2019 20:16:10 +0100 Subject: [PATCH 0198/1732] docs/cmds/bind: Fix synopsis --- sphinx_doc_src/cmds/bind.rst | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sphinx_doc_src/cmds/bind.rst b/sphinx_doc_src/cmds/bind.rst index 1d9c6ddc1..a7b028800 100644 --- a/sphinx_doc_src/cmds/bind.rst +++ b/sphinx_doc_src/cmds/bind.rst @@ -4,16 +4,17 @@ bind - handle fish key bindings Synopsis -------- -bind [(-M | --mode) MODE] [(-m | --sets-mode) NEW_MODE] - [--preset | --user] - [(-s | --silent)] [(-k | --key)] SEQUENCE COMMAND [COMMAND...] -bind [(-M | --mode) MODE] [(-k | --key)] [--preset] [--user] SEQUENCE -bind (-K | --key-names) [(-a | --all)] [--preset] [--user] -bind (-f | --function-names) -bind (-L | --list-modes) -bind (-e | --erase) [(-M | --mode) MODE] - [--preset] [--user] - (-a | --all | [(-k | --key)] SEQUENCE [SEQUENCE...]) +``bind [(-M | --mode) MODE] [(-m | --sets-mode) NEW_MODE] [--preset | --user] [(-s | --silent)] [(-k | --key)] SEQUENCE COMMAND [COMMAND...]`` + +``bind [(-M | --mode) MODE] [(-k | --key)] [--preset] [--user] SEQUENCE`` + +``bind (-K | --key-names) [(-a | --all)] [--preset] [--user]`` + +``bind (-f | --function-names)`` + +``bind (-L | --list-modes)`` + +``bind (-e | --erase) [(-M | --mode) MODE] [--preset] [--user] (-a | --all | [(-k | --key)] SEQUENCE [SEQUENCE...])`` Description From 191b74df6fa44c96dbf283b84859147249814b47 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 29 Mar 2019 20:55:28 +0100 Subject: [PATCH 0199/1732] docs: Fix some sphinx errors See #5696. [ci skip] --- sphinx_doc_src/cmds/bind.rst | 2 +- sphinx_doc_src/cmds/complete.rst | 30 ++++++++++--------- sphinx_doc_src/cmds/disown.rst | 4 +-- .../cmds/fish_breakpoint_prompt.rst | 2 ++ sphinx_doc_src/cmds/fish_git_prompt.rst | 4 +-- sphinx_doc_src/cmds/fish_opt.rst | 7 +++-- sphinx_doc_src/cmds/fish_prompt.rst | 8 +++-- sphinx_doc_src/cmds/fish_right_prompt.rst | 8 +++-- sphinx_doc_src/cmds/fish_svn_prompt.rst | 1 - sphinx_doc_src/cmds/umask.rst | 2 +- sphinx_doc_src/index.rst | 3 +- 11 files changed, 39 insertions(+), 32 deletions(-) diff --git a/sphinx_doc_src/cmds/bind.rst b/sphinx_doc_src/cmds/bind.rst index a7b028800..5fb4d38b1 100644 --- a/sphinx_doc_src/cmds/bind.rst +++ b/sphinx_doc_src/cmds/bind.rst @@ -26,7 +26,7 @@ SEQUENCE is the character sequence to bind to. These should be written as Date: Fri, 29 Mar 2019 21:07:36 +0100 Subject: [PATCH 0200/1732] docs: Fix warnings This was: - Some `` mismatches - it's "``something``", not "``something`". - Some "explicit targets", which IMHO are quite a misfeature - `word `_ has to be unique, which I don't see a usecase for. Instead use `word `__, with a double-underscore at the end. - One case of `||` which I just removed See #5696. [ci skip] --- sphinx_doc_src/index.rst | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index d8b060778..11d27c5be 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -92,7 +92,7 @@ Commands versus Programs **Programs** in other languages can often be regarded as black boxes: they get complex input and return complex output. Sometimes they produce side effects such as writing to a file or reporting an error, but the emphasis is on: arguments in and return values out: -Arguments → |Program| → Return Values +Arguments → Program → Return Values **Shell commands** are different: @@ -1185,13 +1185,13 @@ Special variables The user can change the settings of ``fish`` by changing the values of certain variables. -- A large number of variable starting with the prefixes ``fish_color`` and ``fish_pager_color``. See `Variables for changing highlighting colors <#variables-color>`_ for more information. +- A large number of variable starting with the prefixes ``fish_color`` and ``fish_pager_color``. See `Variables for changing highlighting colors <#variables-color>`__ for more information. - ``fish_emoji_width`` controls the computed width of certain characters, in particular emoji, whose rendered width varies across terminal emulators. This should be set to 1 if your terminal emulator renders emoji single-width, or 2 if double-width. Set this only if you see graphical glitching when printing emoji. - ``fish_ambiguous_width`` controls the computed width of ambiguous East Asian characters. This should be set to 1 if your terminal emulator renders these characters as single-width (typical), or 2 if double-width. -- ``fish_escape_delay_ms`` overrides the default timeout of 30ms after seeing an escape character before giving up on matching a key binding. See the documentation for the `bind `_ builtin command. This delay facilitates using escape as a meta key. +- ``fish_escape_delay_ms`` overrides the default timeout of 30ms after seeing an escape character before giving up on matching a key binding. See the documentation for the `bind `__ builtin command. This delay facilitates using escape as a meta key. - ``fish_greeting``, the greeting message printed on startup. @@ -1416,15 +1416,15 @@ Some bindings are shared between emacs- and vi-mode because they aren't text edi - :kbd:`Control+D` delete one character to the right of the cursor. If the command line is empty, :kbd:`Control+D` will exit fish. -- :kbd:`Control+U` moves contents from the beginning of line to the cursor to the `killring <#killring>`_. +- :kbd:`Control+U` moves contents from the beginning of line to the cursor to the `killring <#killring>`__. - :kbd:`Control+L` clears and repaints the screen. -- :kbd:`Control+W` moves the previous path component (everything up to the previous "/") to the `killring <#killring>`_. +- :kbd:`Control+W` moves the previous path component (everything up to the previous "/") to the `killring <#killring>`__. - :kbd:`Control+X` copies the current buffer to the system's clipboard, :kbd:`Control+V` inserts the clipboard contents. -- :kbd:`Alt+d` moves the next word to the `killring <#killring>`_. +- :kbd:`Alt+d` moves the next word to the `killring <#killring>`__. - :kbd:`Alt+h` (or :kbd:`F1`) shows the manual page for the current command, if one exists. @@ -1451,7 +1451,7 @@ Emacs mode commands - :kbd:`Delete` and :kbd:`Backspace` removes one character forwards or backwards respectively. -- :kbd:`Control+K` moves contents from the cursor to the end of line to the `killring <#killring>`_. +- :kbd:`Control+K` moves contents from the cursor to the end of line to the `killring <#killring>`__. - :kbd:`Alt+c` capitalizes the current word. @@ -1462,7 +1462,7 @@ Emacs mode commands - :kbd:`Alt+t` transposes the last two words -You can change these key bindings using the `bind `_ builtin. +You can change these key bindings using the `bind `__ builtin. .. _vi-mode: @@ -1508,11 +1508,11 @@ Command mode is also known as normal mode. - :kbd:`0` (zero) moves the cursor to beginning of line (remaining in command mode). -- :kbd:`d`:kbd:`d` deletes the current line and moves it to the `killring <#killring>`_. +- :kbd:`d`:kbd:`d` deletes the current line and moves it to the `killring <#killring>`__. -- :kbd:`Shift,D` deletes text after the current cursor position and moves it to the `killring <#killring>`_. +- :kbd:`Shift,D` deletes text after the current cursor position and moves it to the `killring <#killring>`__. -- :kbd:`p` pastes text from the `killring <#killring>`_. +- :kbd:`p` pastes text from the `killring <#killring>`__. - :kbd:`u` search history backwards. @@ -1538,7 +1538,7 @@ Visual mode - :kbd:`b` and :kbd:`w` extend the selection backward/forward by one word. -- :kbd:`d` and :kbd:`x` move the selection to the `killring <#killring>`_ and enter `command mode <#vi-mode-command>`_. +- :kbd:`d` and :kbd:`x` move the selection to the `killring <#killring>`__ and enter `command mode <#vi-mode-command>`__. - :kbd:`Escape` and :kbd:`Control+C` enter `command mode <#vi-mode-command>`_. @@ -1615,8 +1615,11 @@ Initialization files On startup, Fish evaluates a number of configuration files, which can be used to control the behavior of the shell. The location of these configuration variables is controlled by a number of environment variables, and their default or usual location is given below. Configuration files are evaluated in the following order: -- Configuration shipped with fish, which should not be edited, in ``$__fish_data_dir/config.fish`` (usually ``/usr/share/fish/config.fish`). + +- Configuration shipped with fish, which should not be edited, in ``$__fish_data_dir/config.fish`` (usually ``/usr/share/fish/config.fish``). + - Configuration snippets in files ending in ``.fish``, in the directories: + - ``$__fish_config_dir/conf.d`` (by default, ``~/.config/fish/conf.d/``) - ``$__fish_sysconf_dir/conf.d`` (by default, ``/etc/fish/conf.d``) - ``/usr/share/fish/vendor_conf.d`` (set at compile time; by default, ``$__fish_data_dir/vendor_conf.d``) @@ -1709,7 +1712,7 @@ Detected errors include: When the cursor is over a parenthesis or a quote, ``fish`` also highlights its matching quote or parenthesis. -To customize the syntax highlighting, you can set the environment variables listed in the `Variables for changing highlighting colors `_ section. +To customize the syntax highlighting, you can set the environment variables listed in the `Variables for changing highlighting colors <#variables-color>`__ section. .. _title: @@ -1738,7 +1741,7 @@ To show the last command in the title:: Programmable prompt ------------------- -When fish waits for input, it will display a prompt by evaluating the ``fish_prompt`` and `fish_right_prompt` functions. The output of the former is displayed on the left and the latter's output on the right side of the terminal. The output of ``fish_mode_prompt`` will be prepended on the left, though the default function only does this when in `vi-mode `_. +When fish waits for input, it will display a prompt by evaluating the ``fish_prompt`` and `fish_right_prompt` functions. The output of the former is displayed on the left and the latter's output on the right side of the terminal. The output of ``fish_mode_prompt`` will be prepended on the left, though the default function only does this when in `vi-mode <#vi-mode>`__. .. _greeting: @@ -1752,7 +1755,7 @@ If a function named ``fish_greeting`` exists, it will be run when entering inter Private mode ------------- -fish supports launching in private mode via ``fish --private`` (or ``fish -P`` for short). In private mode, old history is not available and any interactive commands you execute will not be appended to the global history file, making it useful both for avoiding inadvertently leaking personal information (e.g. for screencasts) and when dealing with sensitive information to prevent it being persisted to disk. You can query the global variable `fish_private_mode`` (``if set -q fish_private_mode ...`) if you would like to respect the user's wish for privacy and alter the behavior of your own fish scripts. +fish supports launching in private mode via ``fish --private`` (or ``fish -P`` for short). In private mode, old history is not available and any interactive commands you execute will not be appended to the global history file, making it useful both for avoiding inadvertently leaking personal information (e.g. for screencasts) and when dealing with sensitive information to prevent it being persisted to disk. You can query the global variable `fish_private_mode`` (``if set -q fish_private_mode ...``) if you would like to respect the user's wish for privacy and alter the behavior of your own fish scripts. .. _event: From 03a6fb4a69ea5192427ab436142f422566b24c19 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 29 Mar 2019 21:13:10 +0100 Subject: [PATCH 0201/1732] docs/license: Fix "anonymous hyperlink" warning Apparently an anonymous hyperlink looks like `__something__`. I had to find this by deleting parts of the document and building to narrow it down until I had the line, because sphinx wouldn't give a line number. See #5696. [ci skip] --- sphinx_doc_src/license.rst | 268 +------------------------------------ 1 file changed, 1 insertion(+), 267 deletions(-) diff --git a/sphinx_doc_src/license.rst b/sphinx_doc_src/license.rst index 36153bd6b..91a378218 100644 --- a/sphinx_doc_src/license.rst +++ b/sphinx_doc_src/license.rst @@ -97,7 +97,7 @@ The precise terms and conditions for copying, distribution and modification foll 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - __NO WARRANTY__ + **NO WARRANTY** 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. @@ -120,269 +120,3 @@ Redistribution and use in source and binary forms, with or without modification, -# Neither the name of the University of Cambridge nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----- - -**License for CMake** - -The ``fish`` source code contains files from [CMake](https://cmake.org) to support the build system. -This code is distributed under the terms of a BSD-style license. Copyright 2000-2017 Kitware, Inc. -and Contributors. - -The BSD license for CMake follows. - -CMake - Cross Platform Makefile Generator -Copyright 2000-2017 Kitware, Inc. and Contributors -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the name of Kitware, Inc. nor the names of Contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----- - -**License for wcslcpy and code derived from tmux** - -``fish`` also contains small amounts of code under the OpenBSD license, namely a version of the function strlcpy, modified for use with wide character strings. This code is copyrighted by Todd C. Miller (1998). It also contains code from [tmux](http://tmux.sourceforge.net), copyrighted by Nicholas Marriott (2007), and made available under an identical license. - -The OpenBSD license is included below. - -Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ----- - -**License for glibc** - -Fish contains code from the glibc library, namely the wcstok function. This code is licensed under the LGPL, version 2 or later. Version 2 of the LPGL license agreement is included below. - -**GNU LESSER GENERAL PUBLIC LICENSE** - -Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - -[This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] - -**Preamble** - -The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software - to make sure the software is free for all its users. - -This license, the Lesser General Public License, applies to some specially designated software packages - typically libraries - of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. - -When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. - -To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. - -For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. - -We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. - -To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. - -Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. - -Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. - -When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. - -We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. - -For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. - -In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. - -Although the Lesser General Public License is Less protective of the users'freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. - -The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. - -**TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION** - -- This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) - - "Source code for a work" means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. - - Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. - -1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. - - You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: - - 1. The modified work must itself be a software library. - - 2. You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. - - 3. You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. - - 4. If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. - - (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) - - These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. - - Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. - - In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. - -3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. - - Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of the Library into a program that is not a library. - -4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. - -5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. - -6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: - - 1. Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine- readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) - - 2. Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. - - 3. Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. - - 4. If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. - - 5. Verify that the user has already received a copy of these materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. - - It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. - -7. You may place library facilities that are a work based on the Library side- by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: - - 1. Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. - - 2. Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. - -8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. - -9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. - -10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients'exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. - -11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. - - If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. - - It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. - - This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - -12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. - -13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. - -14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - - **NO WARRANTY** - -15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - ----- - -**License for UTF8** - -``fish`` also contains small amounts of code under the ISC license, namely the UTF-8 conversion functions. This code is copyright © 2007 Alexey Vatchenko \. - -The ISC license agreement follows. - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ----- - -**License for flock** - -``fish`` also contains small amounts of code from NetBSD, namely the ``flock`` fallback function. This code is copyright 2001 The NetBSD Foundation, Inc., and derived from software contributed to The NetBSD Foundation by Todd Vierling. - -The NetBSD license follows. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - ----- - -**MIT License** - -``fish`` includes a copy of AngularJS, which is copyright 2010-2012 Google, Inc. and licensed under the MIT License. - -The MIT license follows. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From fc7d11d7b8990e1d22d9eda49334452a3e23d765 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 17:11:44 +0100 Subject: [PATCH 0202/1732] Update zpool completions to use `string` instead of `grep` --- share/completions/zpool.fish | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/share/completions/zpool.fish b/share/completions/zpool.fish index 20d47f41c..933660100 100644 --- a/share/completions/zpool.fish +++ b/share/completions/zpool.fish @@ -37,20 +37,21 @@ function __fish_zpool_using_command # zpool command whose completions are looked end function __fish_zpool_list_used_vdevs -a pool - if test -z "$pool" - zpool list -H -v | grep -E "^\s" | cut -f2 | grep -x -E -v "(spare|log|cache|mirror|raidz.?)" - else - zpool list -H -v $pool | grep -E "^\s" | cut -f2 | grep -x -E -v "(spare|log|cache|mirror|raidz.?)" - end + # See discussion and variants discussed at + # https://github.com/fish-shell/fish-shell/pull/5743#pullrequestreview-217432149 + zpool list -Hv | string replace -rf "^\t([^\t]+).*" '$1' | string match -rv '^(spare|log|cache|mirror|raidz.?)' end function __fish_zpool_list_available_vdevs if test $OS = 'Linux' - find /dev -type b | cut -d'/' -f3 + find /dev -type b | string replace '/dev/' '' else if test $OS = 'FreeBSD' - for i in (camcontrol devlist | cut -d "(" -f 2 | cut -d "," -f 1); ls /dev | grep "^$i"; end + for i in (camcontrol devlist | cut -d "(" -f 2 | cut -d "," -f 1) + set -l files /dev/* + string replace /dev/ '' -- $files | string match -r "^$i" + end else if test $OS = 'SunOS' - ls /dev/dsk + find /dev/dsk -type b | string replace '/dev/' '' end end @@ -88,11 +89,10 @@ function __fish_zpool_complete_vdevs return case "" # Au cas où echo "" > /dev/null - case "*" - if echo "$i" | grep -q -E '^((-.*)|(.*(=|,).*))$' # The token is an option or an option argument; as no option uses a vdev as its argument, we can abandon commandline parsing - __fish_zpool_list_vdev_types - return - end + case "-*" "*=*" "*,*" + # The token is an option or an option argument; as no option uses a vdev as its argument, we can abandon commandline parsing + __fish_zpool_list_vdev_types + return end set tokens (math $tokens+1) end @@ -126,7 +126,7 @@ function __fish_zpool_list_ro_properties echo -e "bootsize\t"(_ "System boot partition size") end echo -e "capacity\t"(_ "Usage percentage of pool") - echo -e "dedupratio\t"(_ "Deduplication ratio") + echo -e "dedupratio\t"(_ "Deduplication ratio") echo -e "expandsize\t"(_ "Amount of uninitialized space within the pool") echo -e "fragmentation\t"(_ "Fragmentation percentage of pool") echo -e "free\t"(_ "Free pool space") @@ -136,7 +136,7 @@ function __fish_zpool_list_ro_properties echo -e "size\t"(_ "Total pool space") echo -e "used\t"(_ "Used pool space") # Unsupported features - for i in (zpool list -o all | head -n1 | tr -s "[:blank:]" | tr ' ' '\n' | tr "[:upper:]" "[:lower:]" | grep unsupported); echo $i; end + zpool list -o all | head -n1 | string replace -ra ' +' '\n' | string lower | string match -r unsupported end function __fish_zpool_list_device_properties @@ -167,11 +167,7 @@ function __fish_zpool_list_rw_properties echo -e "listsnaps\t"(_ "Display snapshots even if 'zfs list' does not use '-t'")" (on, off)" echo -e "version\t"(_ "On-disk version of pool")" (VERSION)" # Feature properties - for featureLong in (zpool list -o all | tr -s "[:blank:]" | tr ' ' '\n' | tr "[:upper:]" "[:lower:]" | grep '^feature@') - set -l featureShort (echo $featureLong | sed -e 's/feature@\(.*\)/\1/g') - set featureLong (echo -e "$featureLong\t") - printf (_ "%sEnable the %s feature\n") $featureLong $featureShort - end + zpool list -o all | string replace -ra ' +' '\n' | string lower | string replace -rf '^feature@(.*)' '$1' end complete -c zpool -f -n '__fish_zpool_needs_command' -s '?' -d 'Display a help message' From 93b02dcec4d55b406f1cdd127577e3ca1df58c28 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Fri, 29 Mar 2019 17:43:03 -0500 Subject: [PATCH 0203/1732] Don't use camcontrol in FreeBSD zpool completions It requires root/su privileges to list devices, and we have a great alternative that already produces the desired results. --- share/completions/zpool.fish | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/share/completions/zpool.fish b/share/completions/zpool.fish index 933660100..fc93826c6 100644 --- a/share/completions/zpool.fish +++ b/share/completions/zpool.fish @@ -46,10 +46,7 @@ function __fish_zpool_list_available_vdevs if test $OS = 'Linux' find /dev -type b | string replace '/dev/' '' else if test $OS = 'FreeBSD' - for i in (camcontrol devlist | cut -d "(" -f 2 | cut -d "," -f 1) - set -l files /dev/* - string replace /dev/ '' -- $files | string match -r "^$i" - end + sysctl -an kern.disks | string split ' ' else if test $OS = 'SunOS' find /dev/dsk -type b | string replace '/dev/' '' end From 1937e409f7e860c040047a3a06b8b7c7f65c4828 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 14 Mar 2019 17:13:31 +0100 Subject: [PATCH 0204/1732] completions/find: Fix typo --- share/completions/find.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/completions/find.fish b/share/completions/find.fish index fa120d57b..e7301ef00 100644 --- a/share/completions/find.fish +++ b/share/completions/find.fish @@ -20,7 +20,7 @@ complete -c find -o mindepth -d "Do not apply any tests or actions at levels les complete -c find -o mount -o xdev -d "Don't descend directories on other filesystems" complete -c find -o noignore_readdir_race -d "Print error messages for files that are deleted while running find" complete -c find -o noleaf -d "Do not optimize by assuming that directories contain 2 fewer subdirectories than their hard link count" -complete -c find -o regextype -d "Specify regular expression type" -a "emacs posix-awk posix-basic posiz-egrep posix-extended" +complete -c find -o regextype -d "Specify regular expression type" -a "emacs posix-awk posix-basic posix-egrep posix-extended" complete -c find -o version -l version -d "Display version and exit" complete -c find -o warn -d "Turn warnings on" complete -c find -o nowarn -d "Turn warnings off" From 0aa0dceeb323b9248eda6401ab202c7457804801 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Fri, 29 Mar 2019 20:56:02 -0700 Subject: [PATCH 0205/1732] End coalescing repaints on check-exits Hopeful fix for #5766 --- src/reader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/reader.cpp b/src/reader.cpp index 6ffd3da31..87d31f0ed 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -3267,6 +3267,7 @@ maybe_t reader_data_t::readline(int nchars_or_0) { } if (!event_needing_handling || event_needing_handling->is_check_exit()) { + rls.coalescing_repaints = false; repaint_if_needed(); continue; } else if (event_needing_handling->is_eof()) { From 7aaa3b8553a6ab182672beed17f34a4da132307d Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 30 Mar 2019 19:25:09 +0100 Subject: [PATCH 0206/1732] Keep the order for $PATH and $MANPATH when reading /etc/paths (#5767) * Keep the order for $PATH and $MANPATH when reading /etc/paths Fixes #5456. --- share/config.fish | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/share/config.fish b/share/config.fish index f6176361d..c5268fa6b 100644 --- a/share/config.fish +++ b/share/config.fish @@ -173,7 +173,9 @@ if status --is-login # executable for fish; see # https://opensource.apple.com/source/shell_cmds/shell_cmds-203/path_helper/path_helper.c.auto.html . function __fish_macos_set_env -d "set an environment variable like path_helper does (macOS only)" - set -l result + # The first argument is the variable name, the others are the files. + # Keep the components already there so we don't change the order + set -l result $$argv[1] for path_file in $argv[2] $argv[3]/* if [ -f $path_file ] @@ -185,12 +187,6 @@ if status --is-login end end - for entry in $$argv[1] - if not contains -- $entry $result - set result $result $entry - end - end - set -xg $argv[1] $result end From 203927245d7422038814913bbfb676b6d2ebdf6f Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 30 Mar 2019 20:27:30 +0100 Subject: [PATCH 0207/1732] docs: Fix reference syntax Fixes #5776. [ci skip] --- sphinx_doc_src/faq.rst | 14 +++++++------- sphinx_doc_src/index.rst | 6 +++--- sphinx_doc_src/tutorial.rst | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/sphinx_doc_src/faq.rst b/sphinx_doc_src/faq.rst index 35742d8b9..e08a58e55 100644 --- a/sphinx_doc_src/faq.rst +++ b/sphinx_doc_src/faq.rst @@ -3,7 +3,7 @@ Frequently asked questions How do I set or clear an environment variable? ---------------------------------------------- -Use the ``set`` command:: +Use the `set `__ command:: set -x key value set -e key @@ -26,7 +26,7 @@ The prompt is the output of the ``fish_prompt`` function. Put it in ``~/.config/ end -You can also use the Web configuration tool, ``fish_config``, to preview and choose from a gallery of sample prompts. +You can also use the Web configuration tool, `fish_config `__, to preview and choose from a gallery of sample prompts. How do I run a command from history? @@ -93,7 +93,7 @@ If you are just interested in success or failure, you can run the command direct end -See the documentation for ``test`` and ``if`` for more information. +See the documentation for `test `__ and `if `__ for more information. ~~ How do I set an environment variable for just one command? @@ -154,7 +154,7 @@ variables. This means that the global value takes precedence over the universal value. To avoid this problem, consider changing the setting which fish inherits. If this is not possible, -add a statement to your user initialization file (usually +add a statement to your `user initialization file `__ (usually ``~/.config/fish/config.fish``):: set -gx EDITOR vim @@ -162,12 +162,12 @@ add a statement to your user initialization file (usua How do I customize my syntax highlighting colors? ------------------------------------------------- -Use the web configuration tool, ``fish_config``, or alter the ``fish_color`` family of environment variables. +Use the web configuration tool, `fish_config `__, or alter the `fish_color family of environment variables `__. ~~ How do I update man page completions? ------------------------------------- -Use the ``fish_update_completions`` command. +Use the `fish_update_completions `__ command. ~~ I accidentally entered a directory path and fish changed directory. What happened? @@ -177,7 +177,7 @@ If fish is unable to locate a command with a given name, and it starts with '``. The open command doesn't work. ------------------------------ -The ``open`` command uses the MIME type database and the ``.desktop`` files used by Gnome and KDE to identify filetypes and default actions. If at least one of these environments is installed, but the open command is not working, this probably means that the relevant files are installed in a non-standard location. Consider asking for more help. +The ``open`` command uses the MIME type database and the ``.desktop`` files used by Gnome and KDE to identify filetypes and default actions. If at least one of these environments is installed, but the open command is not working, this probably means that the relevant files are installed in a non-standard location. Consider `asking for more help `__. How do I make fish my default shell? diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index 11d27c5be..96e5b4424 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -719,7 +719,7 @@ Examples: - ``**`` matches any files and directories in the current directory and all of its subdirectories. -Note that for most commands, if any wildcard fails to expand, the command is not executed, ```$status`` <#variables-status>`_ is set to nonzero, and a warning is printed. This behavior is consistent with setting ``shopt -s failglob`` in bash. There are exactly 3 exceptions, namely `set `_, `count `_ and `for `_. Their globs are permitted to expand to zero arguments, as with ``shopt -s nullglob`` in bash. +Note that for most commands, if any wildcard fails to expand, the command is not executed, `$status <#variables-status>`_ is set to nonzero, and a warning is printed. This behavior is consistent with setting ``shopt -s failglob`` in bash. There are exactly 3 exceptions, namely `set `_, `count `_ and `for `_. Their globs are permitted to expand to zero arguments, as with ``shopt -s nullglob`` in bash. Examples:: @@ -1191,7 +1191,7 @@ The user can change the settings of ``fish`` by changing the values of certain v - ``fish_ambiguous_width`` controls the computed width of ambiguous East Asian characters. This should be set to 1 if your terminal emulator renders these characters as single-width (typical), or 2 if double-width. -- ``fish_escape_delay_ms`` overrides the default timeout of 30ms after seeing an escape character before giving up on matching a key binding. See the documentation for the `bind `__ builtin command. This delay facilitates using escape as a meta key. +- ``fish_escape_delay_ms`` overrides the default timeout of 30ms after seeing an escape character before giving up on matching a key binding. See the documentation for the `bind `__ builtin command. This delay facilitates using escape as a meta key. - ``fish_greeting``, the greeting message printed on startup. @@ -1627,7 +1627,7 @@ Configuration files are evaluated in the following order: If there are multiple files with the same name in these directories, only the first will be executed. They are executed in order of their filename, sorted (like globs) in a natural order (i.e. "01" sorts before "2"). -- System-wide configuration files, where administrators can include initialization that should be run for all users on the system - similar to ``/etc/profile`` for POSIX-style shells - in ``$__fish_sysconf_dir``` (usually ``/etc/fish/config.fish``); +- System-wide configuration files, where administrators can include initialization that should be run for all users on the system - similar to ``/etc/profile`` for POSIX-style shells - in ``$__fish_sysconf_dir` (usually /etc/fish/config.fish``); - User initialization, usually in `~/.config/fish/config.fish` (controlled by the ``XDG_CONFIG_HOME`` environment variable, and accessible as ``$__fish_config_dir``). These paths are controlled by parameters set at build, install, or run time, and may vary from the defaults listed above. diff --git a/sphinx_doc_src/tutorial.rst b/sphinx_doc_src/tutorial.rst index 01503482b..ef64c480f 100644 --- a/sphinx_doc_src/tutorial.rst +++ b/sphinx_doc_src/tutorial.rst @@ -338,7 +338,7 @@ You can iterate over a list (or a slice) with a for loop:: entry: /usr/local/bin -Lists adjacent to other lists or strings are expanded as cartesian products unless quoted (see Variable expansion):: +Lists adjacent to other lists or strings are expanded as `cartesian products `__ unless quoted (see `Variable expansion `__):: >_ set a 1 2 3 >_ set 1 a b c @@ -350,7 +350,7 @@ Lists adjacent to other lists or strings are expanded as Brace expansion. +This is similar to `Brace expansion `__. Command Substitutions --------------------- @@ -445,7 +445,7 @@ Use ``if``, ``else if``, and ``else`` to conditionally execute code, based on th end -To compare strings or numbers or check file properties (whether a file exists or is writeable and such), use test, like +To compare strings or numbers or check file properties (whether a file exists or is writeable and such), use `test `__, like @@ -650,7 +650,7 @@ This is the preferred way to define your prompt as well:: end -See the documentation for funced and funcsave for ways to create these files automatically. +See the documentation for `funced `__ and `funcsave `__ for ways to create these files automatically. Universal Variables ------------------- From 0c4580d8743e1745a14c4fda05ccb2c19d404331 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 30 Mar 2019 20:44:07 +0100 Subject: [PATCH 0208/1732] docs: Fix moar reference syntax --- sphinx_doc_src/cmds/alias.rst | 4 ++-- sphinx_doc_src/cmds/and.rst | 4 ++-- sphinx_doc_src/cmds/argparse.rst | 10 +++++----- sphinx_doc_src/cmds/bg.rst | 2 +- sphinx_doc_src/cmds/bind.rst | 6 +++--- sphinx_doc_src/cmds/block.rst | 2 +- sphinx_doc_src/cmds/break.rst | 2 +- sphinx_doc_src/cmds/breakpoint.rst | 2 +- sphinx_doc_src/cmds/cd.rst | 4 ++-- sphinx_doc_src/cmds/disown.rst | 2 +- sphinx_doc_src/cmds/exit.rst | 2 +- sphinx_doc_src/cmds/fg.rst | 2 +- sphinx_doc_src/cmds/fish_breakpoint_prompt.rst | 2 +- sphinx_doc_src/cmds/fish_opt.rst | 2 +- sphinx_doc_src/cmds/fish_prompt.rst | 2 +- sphinx_doc_src/cmds/function.rst | 6 +++--- sphinx_doc_src/cmds/jobs.rst | 2 +- sphinx_doc_src/faq.rst | 4 ++-- sphinx_doc_src/tutorial.rst | 4 ++-- 19 files changed, 32 insertions(+), 32 deletions(-) diff --git a/sphinx_doc_src/cmds/alias.rst b/sphinx_doc_src/cmds/alias.rst index 538ab3c67..ff1e87757 100644 --- a/sphinx_doc_src/cmds/alias.rst +++ b/sphinx_doc_src/cmds/alias.rst @@ -12,7 +12,7 @@ alias [OPTIONS] NAME=DEFINITION Description ----------- -``alias`` is a simple wrapper for the ``function`` builtin, which creates a function wrapping a command. It has similar syntax to POSIX shell ``alias``. For other uses, it is recommended to define a function. +``alias`` is a simple wrapper for the ``function`` builtin, which creates a function wrapping a command. It has similar syntax to POSIX shell ``alias``. For other uses, it is recommended to define a `function `__. ``fish`` marks functions that have been created by ``alias`` by including the command used to create them in the function description. You can list ``alias``-created functions by running ``alias`` without arguments. They must be erased using ``functions -e``. @@ -25,7 +25,7 @@ The following options are available: - ``-h`` or ``--help`` displays help about using this command. -- ``-s`` or ``--save`` Automatically save the function created by the alias into your fish configuration directory using funcsave. +- ``-s`` or ``--save`` Automatically save the function created by the alias into your fish configuration directory using `funcsave `__. Example ------- diff --git a/sphinx_doc_src/cmds/and.rst b/sphinx_doc_src/cmds/and.rst index a5614c4ad..1b80978ad 100644 --- a/sphinx_doc_src/cmds/and.rst +++ b/sphinx_doc_src/cmds/and.rst @@ -12,9 +12,9 @@ Description ``and`` is used to execute a command if the previous command was successful (returned a status of 0). -``and`` statements may be used as part of the condition in an ``if`` or ``while`` block. See the documentation for ``if`` and ``while`` for examples. +``and`` statements may be used as part of the condition in an `while `__ or `if `__ block. -``and`` does not change the current exit status itself, but the command it runs most likely will. The exit status of the last foreground command to exit can always be accessed using the $status variable. +``and`` does not change the current exit status itself, but the command it runs most likely will. The exit status of the last foreground command to exit can always be accessed using the `$status `__ variable. Example ------- diff --git a/sphinx_doc_src/cmds/argparse.rst b/sphinx_doc_src/cmds/argparse.rst index c328e205b..d00afa6a7 100644 --- a/sphinx_doc_src/cmds/argparse.rst +++ b/sphinx_doc_src/cmds/argparse.rst @@ -10,9 +10,9 @@ argparse [OPTIONS] OPTION_SPEC... -- [ARG...] Description ----------- -This command makes it easy for fish scripts and functions to handle arguments in a manner 100% identical to how fish builtin commands handle their arguments. You pass a sequence of arguments that define the options recognized, followed by a literal ``--``, then the arguments to be parsed (which might also include a literal ``--``). More on this in the usage section below. +This command makes it easy for fish scripts and functions to handle arguments in a manner 100% identical to how fish builtin commands handle their arguments. You pass a sequence of arguments that define the options recognized, followed by a literal ``--``, then the arguments to be parsed (which might also include a literal ``--``). More on this in the `usage <#argparse-usage>`__ section below. -Each OPTION_SPEC can be written in the domain specific language described below or created using the companion ``fish_opt`` command. All OPTION_SPECs must appear after any argparse flags and before the ``--`` that separates them from the arguments to be parsed. +Each OPTION_SPEC can be written in the `domain specific language <#argparse-option-specs>`__ described below or created using the companion `fish_opt `__ command. All OPTION_SPECs must appear after any argparse flags and before the ``--`` that separates them from the arguments to be parsed. Each option that is seen in the ARG list will result in a var name of the form ``_flag_X``, where ``X`` is the short flag letter and the long flag name. The OPTION_SPEC always requires a short flag even if it can't be used. So there will always be ``_flag_X`` var set using the short flag letter if the corresponding short or long flag is seen. The long flag name var (e.g., ``_flag_help``) will only be defined, obviously, if the OPTION_SPEC includes a long flag name. @@ -48,7 +48,7 @@ Using this command involves passing two sets of arguments separated by ``--``. T or return -If ``$argv`` is empty then there is nothing to parse and ``argparse`` returns zero to indicate success. If ``$argv`` is not empty then it is checked for flags ``-h``, ``--help``, ``-n`` and ``--name``. If they are found they are removed from the arguments and local variables (more on this below) are set so the script can determine which options were seen. Assuming ``$argv`` doesn't have any errors, such as a missing mandatory value for an option, then ``argparse`` exits with status zero. Otherwise it writes appropriate error messages to stderr and exits with a status of one. +If ``$argv`` is empty then there is nothing to parse and ``argparse`` returns zero to indicate success. If ``$argv`` is not empty then it is checked for flags ``-h``, ``--help``, ``-n`` and ``--name``. If they are found they are removed from the arguments and local variables (more on this `below `__) are set so the script can determine which options were seen. Assuming ``$argv`` doesn't have any errors, such as a missing mandatory value for an option, then ``argparse`` exits with status zero. Otherwise it writes appropriate error messages to stderr and exits with a status of one. The ``--`` argument is required. You do not have to include any arguments after the ``--`` but you must include the ``--``. For example, this is acceptable: @@ -91,9 +91,9 @@ Each option specification is a string composed of - ``=+`` if it requires a value and each instance of the flag is saved. -- Optionally a ``!`` followed by fish script to validate the value. Typically this will be a function to run. If the return status is zero the value for the flag is valid. If non-zero the value is invalid. Any error messages should be written to stdout (not stderr). See the section on Flag Value Validation for more information. +- Optionally a ``!`` followed by fish script to validate the value. Typically this will be a function to run. If the return status is zero the value for the flag is valid. If non-zero the value is invalid. Any error messages should be written to stdout (not stderr). See the section on `Flag Value Validation <#arparse-validation>`__ for more information. -See the ``fish_opt`` command for a friendlier but more verbose way to create option specifications. +See the `fish_opt `__ command for a friendlier but more verbose way to create option specifications. In the following examples if a flag is not seen when parsing the arguments then the corresponding _flag_X var(s) will not be set. diff --git a/sphinx_doc_src/cmds/bg.rst b/sphinx_doc_src/cmds/bg.rst index a90e8cfb9..fd4aead37 100644 --- a/sphinx_doc_src/cmds/bg.rst +++ b/sphinx_doc_src/cmds/bg.rst @@ -10,7 +10,7 @@ bg [PID...] Description ----------- -``bg`` sends jobs to the background, resuming them if they are stopped. +``bg`` sends `jobs `__ to the background, resuming them if they are stopped. A background job is executed simultaneously with fish, and does not have access to the keyboard. If no job is specified, the last job to be used is put in the background. If PID is specified, the jobs with the specified process group IDs are put in the background. diff --git a/sphinx_doc_src/cmds/bind.rst b/sphinx_doc_src/cmds/bind.rst index 5fb4d38b1..ff270cd83 100644 --- a/sphinx_doc_src/cmds/bind.rst +++ b/sphinx_doc_src/cmds/bind.rst @@ -22,7 +22,7 @@ Description ``bind`` adds a binding for the specified key sequence to the specified command. -SEQUENCE is the character sequence to bind to. These should be written as fish escape sequences. For example, because pressing the Alt key and another character sends that character prefixed with an escape character, Alt-based key bindings can be written using the ``\e`` escape. For example, :kbd:`Alt+w` can be written as ``\ew``. The control character can be written in much the same way using the ``\c`` escape, for example :kbd:`Control+X` (^X) can be written as ``\cx``. Note that Alt-based key bindings are case sensitive and Control-based key bindings are not. This is a constraint of text-based terminals, not ``fish``. +SEQUENCE is the character sequence to bind to. These should be written as `fish escape sequences `__. For example, because pressing the Alt key and another character sends that character prefixed with an escape character, Alt-based key bindings can be written using the ``\e`` escape. For example, :kbd:`Alt+w` can be written as ``\ew``. The control character can be written in much the same way using the ``\c`` escape, for example :kbd:`Control+X` (^X) can be written as ``\cx``. Note that Alt-based key bindings are case sensitive and Control-based key bindings are not. This is a constraint of text-based terminals, not ``fish``. The default key binding can be set by specifying a ``SEQUENCE`` of the empty string (that is, ``''`` ). It will be used whenever no other binding matches. For most key bindings, it makes sense to use the ``self-insert`` function (i.e. ``````bind '' self-insert``````) as the default keybinding. This will insert any keystrokes not specifically bound to into the editor. Non- printable characters are ignored by the editor, so this will not result in control sequences being printable. @@ -30,7 +30,7 @@ If the ``-k`` switch is used, the name of the key (such as 'down', 'up' or 'back ``COMMAND`` can be any fish command, but it can also be one of a set of special input functions. These include functions for moving the cursor, operating on the kill-ring, performing tab completion, etc. Use ``bind --function-names`` for a complete list of these input functions. -When ``COMMAND`` is a shellscript command, it is a good practice to put the actual code into a function and simply bind to the function name. This way it becomes significantly easier to test the function while editing, and the result is usually more readable as well. +When ``COMMAND`` is a shellscript command, it is a good practice to put the actual code into a `function <#function>`__ and simply bind to the function name. This way it becomes significantly easier to test the function while editing, and the result is usually more readable as well. If a script produces output, it should finish by calling ``commandline -f repaint`` to tell fish that a repaint is in order. @@ -38,7 +38,7 @@ When multiple ``COMMAND``s are provided, they are all run in the specified order If no ``SEQUENCE`` is provided, all bindings (or just the bindings in the specified ``MODE``) are printed. If ``SEQUENCE`` is provided without ``COMMAND``, just the binding matching that sequence is printed. -To save custom keybindings, put the ``bind`` statements into config.fish. Alternatively, fish also automatically executes a function called ``fish_user_key_bindings`` if it exists. +To save custom keybindings, put the ``bind`` statements into `config.fish `__. Alternatively, fish also automatically executes a function called ``fish_user_key_bindings`` if it exists. Key bindings may use "modes", which mimics Vi's modal input behavior. The default mode is "default", and every bind applies to a single mode. The mode can be viewed/changed with the ``$fish_bind_mode`` variable. diff --git a/sphinx_doc_src/cmds/block.rst b/sphinx_doc_src/cmds/block.rst index db9914d0b..e825b6b32 100644 --- a/sphinx_doc_src/cmds/block.rst +++ b/sphinx_doc_src/cmds/block.rst @@ -10,7 +10,7 @@ block [OPTIONS...] Description ----------- -``block`` prevents events triggered by ``fish`` or the ``emit`` command from being delivered and acted upon while the block is in place. +``block`` prevents events triggered by ``fish`` or the `emit `__ command from being delivered and acted upon while the block is in place. In functions, ``block`` can be useful while performing work that should not be interrupted by the shell. diff --git a/sphinx_doc_src/cmds/break.rst b/sphinx_doc_src/cmds/break.rst index b4b55870e..ea921ac90 100644 --- a/sphinx_doc_src/cmds/break.rst +++ b/sphinx_doc_src/cmds/break.rst @@ -10,7 +10,7 @@ LOOP_CONSTRUCT; [COMMANDS...] break; [COMMANDS...] end Description ----------- -``break`` halts a currently running loop, such as a for loop or a while loop. It is usually added inside of a conditional block such as an if statement or a switch statement. +``break`` halts a currently running loop, such as a `switch `__, `for `__ or `while `__ loop. It is usually added inside of a conditional block such as an `if Debugging fish scripts in the ``fish`` manual. +For more details, see `Debugging fish scripts `__ in the ``fish`` manual. There are no parameters for ``breakpoint``. diff --git a/sphinx_doc_src/cmds/cd.rst b/sphinx_doc_src/cmds/cd.rst index 623d853b8..5090449e1 100644 --- a/sphinx_doc_src/cmds/cd.rst +++ b/sphinx_doc_src/cmds/cd.rst @@ -17,7 +17,7 @@ If ``DIRECTORY`` is a relative path, the paths found in the ``CDPATH`` list will Note that the shell will attempt to change directory without requiring ``cd`` if the name of a directory is provided (starting with ``.``, ``/`` or ``~``, or ending with ``/``). -Fish also ships a wrapper function around the builtin ``cd`` that understands ``cd -`` as changing to the previous directory. See also ``prevd``. This wrapper function maintains a history of the 25 most recently visited directories in the ``$dirprev`` and ``$dirnext`` global variables. If you make those universal variables your ``cd`` history is shared among all fish instances. +Fish also ships a wrapper function around the builtin ``cd`` that understands ``cd -`` as changing to the previous directory. See also `prevd `__. This wrapper function maintains a history of the 25 most recently visited directories in the ``$dirprev`` and ``$dirnext`` global variables. If you make those universal variables your ``cd`` history is shared among all fish instances. As a special case, ``cd .`` is equivalent to ``cd $PWD``, which is useful in cases where a mountpoint has been recycled or a directory has been removed and recreated. @@ -38,4 +38,4 @@ Examples See Also -------- -See also the ``cdh`` command for changing to a recently visited directory. +See also the `cdh `__ command for changing to a recently visited directory. diff --git a/sphinx_doc_src/cmds/disown.rst b/sphinx_doc_src/cmds/disown.rst index 3d726f557..58d8d9ad3 100644 --- a/sphinx_doc_src/cmds/disown.rst +++ b/sphinx_doc_src/cmds/disown.rst @@ -10,7 +10,7 @@ Synopsis Description ----------- -``disown`` removes the specified job from the list of jobs. The job itself continues to exist, but fish does not keep track of it any longer. +``disown`` removes the specified `job `__ from the list of jobs. The job itself continues to exist, but fish does not keep track of it any longer. Jobs in the list of jobs are sent a hang-up signal when fish terminates, which usually causes the job to terminate; ``disown`` allows these processes to continue regardless. diff --git a/sphinx_doc_src/cmds/exit.rst b/sphinx_doc_src/cmds/exit.rst index bc9fe2de1..2f3f75594 100644 --- a/sphinx_doc_src/cmds/exit.rst +++ b/sphinx_doc_src/cmds/exit.rst @@ -12,4 +12,4 @@ Description ``exit`` causes fish to exit. If ``STATUS`` is supplied, it will be converted to an integer and used as the exit code. Otherwise, the exit code will be that of the last command executed. -If exit is called while sourcing a file (using the source builtin) the rest of the file will be skipped, but the shell itself will not exit. +If exit is called while sourcing a file (using the `source `__ builtin) the rest of the file will be skipped, but the shell itself will not exit. diff --git a/sphinx_doc_src/cmds/fg.rst b/sphinx_doc_src/cmds/fg.rst index 33831232b..f5c8a7d73 100644 --- a/sphinx_doc_src/cmds/fg.rst +++ b/sphinx_doc_src/cmds/fg.rst @@ -10,7 +10,7 @@ fg [PID] Description ----------- -``fg`` brings the specified job to the foreground, resuming it if it is stopped. While a foreground job is executed, fish is suspended. If no job is specified, the last job to be used is put in the foreground. If PID is specified, the job with the specified group ID is put in the foreground. +``fg`` brings the specified `job `__ to the foreground, resuming it if it is stopped. While a foreground job is executed, fish is suspended. If no job is specified, the last job to be used is put in the foreground. If PID is specified, the job with the specified group ID is put in the foreground. Example diff --git a/sphinx_doc_src/cmds/fish_breakpoint_prompt.rst b/sphinx_doc_src/cmds/fish_breakpoint_prompt.rst index e5c8f4d0f..51cfc020c 100644 --- a/sphinx_doc_src/cmds/fish_breakpoint_prompt.rst +++ b/sphinx_doc_src/cmds/fish_breakpoint_prompt.rst @@ -16,7 +16,7 @@ Description By defining the ``fish_breakpoint_prompt`` function, the user can choose a custom prompt when asking for input in response to a ``breakpoint`` command. The ``fish_breakpoint_prompt`` function is executed when the prompt is to be shown, and the output is used as a prompt. -The exit status of commands within ``fish_breakpoint_prompt`` will not modify the value of $status outside of the ``fish_breakpoint_prompt`` function. +The exit status of commands within ``fish_breakpoint_prompt`` will not modify the value of `$status `__ outside of the ``fish_breakpoint_prompt`` function. ``fish`` ships with a default version of this function that displays the function name and line number of the current execution context. diff --git a/sphinx_doc_src/cmds/fish_opt.rst b/sphinx_doc_src/cmds/fish_opt.rst index e0032b58c..dc8639978 100644 --- a/sphinx_doc_src/cmds/fish_opt.rst +++ b/sphinx_doc_src/cmds/fish_opt.rst @@ -13,7 +13,7 @@ Synopsis Description ----------- -This command provides a way to produce option specifications suitable for use with the ``argparse`` command. You can, of course, write the option specs by hand without using this command. But you might prefer to use this for the clarity it provides. +This command provides a way to produce option specifications suitable for use with the `argparse `__ command. You can, of course, write the option specs by hand without using this command. But you might prefer to use this for the clarity it provides. The following ``argparse`` options are available: diff --git a/sphinx_doc_src/cmds/fish_prompt.rst b/sphinx_doc_src/cmds/fish_prompt.rst index db302d9e7..f89edadcd 100644 --- a/sphinx_doc_src/cmds/fish_prompt.rst +++ b/sphinx_doc_src/cmds/fish_prompt.rst @@ -16,7 +16,7 @@ Description By defining the ``fish_prompt`` function, the user can choose a custom prompt. The ``fish_prompt`` function is executed when the prompt is to be shown, and the output is used as a prompt. -The exit status of commands within ``fish_prompt`` will not modify the value of $status outside of the ``fish_prompt`` function. +The exit status of commands within ``fish_prompt`` will not modify the value of `$status `__ outside of the ``fish_prompt`` function. ``fish`` ships with a number of example prompts that can be chosen with the ``fish_config`` command. diff --git a/sphinx_doc_src/cmds/function.rst b/sphinx_doc_src/cmds/function.rst index bf6623d93..093f46ee0 100644 --- a/sphinx_doc_src/cmds/function.rst +++ b/sphinx_doc_src/cmds/function.rst @@ -20,7 +20,7 @@ The following options are available: - ``-d DESCRIPTION`` or ``--description=DESCRIPTION`` is a description of what the function does, suitable as a completion description. -- ``-w WRAPPED_COMMAND`` or ``--wraps=WRAPPED_COMMAND`` causes the function to inherit completions from the given wrapped command. See the documentation for ``complete`` for more information. +- ``-w WRAPPED_COMMAND`` or ``--wraps=WRAPPED_COMMAND`` causes the function to inherit completions from the given wrapped command. See the documentation for `complete `__ for more information. - ``-e`` or ``--on-event EVENT_NAME`` tells fish to run this function when the specified named event is emitted. Fish internally generates named events e.g. when showing the prompt. @@ -39,9 +39,9 @@ The following options are available: - ``-V`` or ``--inherit-variable NAME`` snapshots the value of the variable ``NAME`` and defines a local variable with that same name and value when the function is defined. This is similar to a closure in other languages like Python but a bit different. Note the word "snapshot" in the first sentence. If you change the value of the variable after defining the function, even if you do so in the same scope (typically another function) the new value will not be used by the function you just created using this option. See the ``function notify`` example below for how this might be used. -If the user enters any additional arguments after the function, they are inserted into the environment variable array ``$argv``. If the ``--argument-names`` option is provided, the arguments are also assigned to names specified in that option. +If the user enters any additional arguments after the function, they are inserted into the environment `variable array `__ ``$argv``. If the ``--argument-names`` option is provided, the arguments are also assigned to names specified in that option. -By using one of the event handler switches, a function can be made to run automatically at specific events. The user may generate new events using the emit builtin. Fish generates the following named events: +By using one of the event handler switches, a function can be made to run automatically at specific events. The user may generate new events using the `emit `__ builtin. Fish generates the following named events: - ``fish_prompt``, which is emitted whenever a new fish prompt is about to be displayed. diff --git a/sphinx_doc_src/cmds/jobs.rst b/sphinx_doc_src/cmds/jobs.rst index 3874f2f8d..b2da7b6dc 100644 --- a/sphinx_doc_src/cmds/jobs.rst +++ b/sphinx_doc_src/cmds/jobs.rst @@ -10,7 +10,7 @@ jobs [OPTIONS] [PID] Description ----------- -``jobs`` prints a list of the currently running jobs and their status. +``jobs`` prints a list of the currently running `jobs `__ and their status. jobs accepts the following switches: diff --git a/sphinx_doc_src/faq.rst b/sphinx_doc_src/faq.rst index e08a58e55..ebac28e2d 100644 --- a/sphinx_doc_src/faq.rst +++ b/sphinx_doc_src/faq.rst @@ -241,7 +241,7 @@ Fish history recall is very simple yet effective: - If you want to reuse several arguments from the same line ("!!:3*" and the like), consider recalling the whole line and removing what you don't need (:kbd:`Alt+D` and :kbd:`Alt+Backspace` are your friends). -See documentation for more details about line editing in fish. +See `documentation `__ for more details about line editing in fish. How can I use ``-`` as a shortcut for ``cd -``? @@ -266,7 +266,7 @@ Next, do the following (assuming fish was installed to /usr/local):: Unicode private-use characters reserved by fish ----------------------------------------------- -Fish reserves the Unicode private-use character range from U+F600 thru U+F73F for internal use. Any attempt to feed characters in that range to fish will result in them being replaced by the Unicode "replacement character" U+FFFD. This includes both interactive input as well as any file read by fish (but not programs run by fish). +Fish reserves the `Unicode private-use character range `__ from U+F600 thru U+F73F for internal use. Any attempt to feed characters in that range to fish will result in them being replaced by the Unicode "replacement character" U+FFFD. This includes both interactive input as well as any file read by fish (but not programs run by fish). Where can I find extra tools for fish? diff --git a/sphinx_doc_src/tutorial.rst b/sphinx_doc_src/tutorial.rst index ef64c480f..809164dbd 100644 --- a/sphinx_doc_src/tutorial.rst +++ b/sphinx_doc_src/tutorial.rst @@ -419,7 +419,7 @@ fish also supports ``and``, ``or``, and ``not``. The first two are job modifiers Backup failed -As mentioned in the section on the semicolon, this can also be written in multiple lines, like so:: +As mentioned in `the section on the semicolon <#tut_semicolon>`__, this can also be written in multiple lines, like so:: cp file1.txt file1_bak.txt && cp file2.txt file2_bak.txt and echo "Backup successful" @@ -464,7 +464,7 @@ To compare strings or numbers or check file properties (whether a file exists or end -Combiners can also be used to make more complex conditions, like +`Combiners <#tut_combiners>`__ can also be used to make more complex conditions, like From 64ff3492a7a699018aa610f70a392d3fa46c5a95 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 30 Mar 2019 21:13:32 +0100 Subject: [PATCH 0209/1732] srht: Remove NetBSD build This isn't officially supported (yet?), and it's currently broken. It doesn't include ssl certificates, and I can't see a way to add them or disable verification before it attempts to clone the git repo. Ironically: [ci skip] --- .builds/netbsd.yml | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 .builds/netbsd.yml diff --git a/.builds/netbsd.yml b/.builds/netbsd.yml deleted file mode 100644 index 5756e2745..000000000 --- a/.builds/netbsd.yml +++ /dev/null @@ -1,23 +0,0 @@ -image: netbsd/latest -packages: - - ncurses - - gettext - - tcl-expect - - cmake - - gmake - - pcre2 -tasks: - - build: | - git -c http.sslVerify=false clone https://git.sr.ht/~faho/fish - cd fish - mkdir build || : - cd build - cmake .. \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DCMAKE_INSTALL_DATADIR=share \ - -DCMAKE_INSTALL_DOCDIR=share/doc/fish \ - -DCMAKE_INSTALL_SYSCONFDIR=/etc - gmake -j2 - - test: | - cd fish/build - gmake test SHOW_INTERACTIVE_LOG=1 From 90958f24020e86b2e9eddd8b7900fcf34f6bbd9c Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 30 Mar 2019 21:25:27 +0100 Subject: [PATCH 0210/1732] CHANGELOG $PATH reordering [ci skip] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 508e1bdc4..8a2a7f789 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - fish no longer requires buffering for the last function in a pipeline. - cd now always checks the current directory, even if $CDPATH does not include it or "." (#4484). - Error messages no longer include a (rather large) help summary and the stacktrace has been shortened (#3404, #5434). +- $PATH is no longer reordered in child fishes (#5456). ### Syntax changes and new commands - None yet. From c6936878120d56ac8a8b4dfc7f7201df9b428d8c Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 31 Mar 2019 10:55:17 +0200 Subject: [PATCH 0211/1732] docs: Add missing > "Anonymous hyperlink" strikes again! [ci skip] --- sphinx_doc_src/cmds/break.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_doc_src/cmds/break.rst b/sphinx_doc_src/cmds/break.rst index ea921ac90..3af73d731 100644 --- a/sphinx_doc_src/cmds/break.rst +++ b/sphinx_doc_src/cmds/break.rst @@ -10,7 +10,7 @@ LOOP_CONSTRUCT; [COMMANDS...] break; [COMMANDS...] end Description ----------- -``break`` halts a currently running loop, such as a `switch `__, `for `__ or `while `__ loop. It is usually added inside of a conditional block such as an `if `__, `for `__ or `while `__ loop. It is usually added inside of a conditional block such as an `if `__ block. There are no parameters for ``break``. From cf9b8fa3fa2a51627a4166534a0e34ce61207ddd Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 31 Mar 2019 11:05:09 +0200 Subject: [PATCH 0212/1732] docs: Add labels to all commands This allows us to use :ref: references, which don't require hardcoding it as html [ci skip] --- sphinx_doc_src/cmds/abbr.rst | 2 ++ sphinx_doc_src/cmds/alias.rst | 2 ++ sphinx_doc_src/cmds/and.rst | 2 ++ sphinx_doc_src/cmds/argparse.rst | 2 ++ sphinx_doc_src/cmds/begin.rst | 2 ++ sphinx_doc_src/cmds/bg.rst | 2 ++ sphinx_doc_src/cmds/bind.rst | 2 ++ sphinx_doc_src/cmds/block.rst | 2 ++ sphinx_doc_src/cmds/break.rst | 2 ++ sphinx_doc_src/cmds/breakpoint.rst | 2 ++ sphinx_doc_src/cmds/builtin.rst | 2 ++ sphinx_doc_src/cmds/case.rst | 2 ++ sphinx_doc_src/cmds/cd.rst | 2 ++ sphinx_doc_src/cmds/cdh.rst | 2 ++ sphinx_doc_src/cmds/command.rst | 2 ++ sphinx_doc_src/cmds/commandline.rst | 2 ++ sphinx_doc_src/cmds/complete.rst | 2 ++ sphinx_doc_src/cmds/contains.rst | 2 ++ sphinx_doc_src/cmds/continue.rst | 2 ++ sphinx_doc_src/cmds/count.rst | 2 ++ sphinx_doc_src/cmds/dirh.rst | 2 ++ sphinx_doc_src/cmds/dirs.rst | 2 ++ sphinx_doc_src/cmds/disown.rst | 2 ++ sphinx_doc_src/cmds/echo.rst | 2 ++ sphinx_doc_src/cmds/else.rst | 2 ++ sphinx_doc_src/cmds/emit.rst | 2 ++ sphinx_doc_src/cmds/end.rst | 2 ++ sphinx_doc_src/cmds/eval.rst | 2 ++ sphinx_doc_src/cmds/exec.rst | 2 ++ sphinx_doc_src/cmds/exit.rst | 2 ++ sphinx_doc_src/cmds/false.rst | 2 ++ sphinx_doc_src/cmds/fg.rst | 2 ++ sphinx_doc_src/cmds/fish.rst | 2 ++ sphinx_doc_src/cmds/fish_breakpoint_prompt.rst | 2 ++ sphinx_doc_src/cmds/fish_config.rst | 2 ++ sphinx_doc_src/cmds/fish_git_prompt.rst | 2 ++ sphinx_doc_src/cmds/fish_hg_prompt.rst | 2 ++ sphinx_doc_src/cmds/fish_indent.rst | 2 ++ sphinx_doc_src/cmds/fish_key_reader.rst | 2 ++ sphinx_doc_src/cmds/fish_mode_prompt.rst | 2 ++ sphinx_doc_src/cmds/fish_opt.rst | 2 ++ sphinx_doc_src/cmds/fish_prompt.rst | 2 ++ sphinx_doc_src/cmds/fish_right_prompt.rst | 2 ++ sphinx_doc_src/cmds/fish_svn_prompt.rst | 2 ++ sphinx_doc_src/cmds/fish_update_completions.rst | 2 ++ sphinx_doc_src/cmds/fish_vcs_prompt.rst | 2 ++ sphinx_doc_src/cmds/fish_vi_mode.rst | 2 ++ sphinx_doc_src/cmds/for.rst | 2 ++ sphinx_doc_src/cmds/funced.rst | 2 ++ sphinx_doc_src/cmds/funcsave.rst | 2 ++ sphinx_doc_src/cmds/function.rst | 2 ++ sphinx_doc_src/cmds/functions.rst | 2 ++ sphinx_doc_src/cmds/help.rst | 2 ++ sphinx_doc_src/cmds/history.rst | 2 ++ sphinx_doc_src/cmds/if.rst | 2 ++ sphinx_doc_src/cmds/isatty.rst | 2 ++ sphinx_doc_src/cmds/jobs.rst | 2 ++ sphinx_doc_src/cmds/math.rst | 2 ++ sphinx_doc_src/cmds/nextd.rst | 2 ++ sphinx_doc_src/cmds/not.rst | 2 ++ sphinx_doc_src/cmds/open.rst | 2 ++ sphinx_doc_src/cmds/or.rst | 2 ++ sphinx_doc_src/cmds/popd.rst | 2 ++ sphinx_doc_src/cmds/prevd.rst | 2 ++ sphinx_doc_src/cmds/printf.rst | 2 ++ sphinx_doc_src/cmds/prompt_pwd.rst | 2 ++ sphinx_doc_src/cmds/psub.rst | 2 ++ sphinx_doc_src/cmds/pushd.rst | 2 ++ sphinx_doc_src/cmds/pwd.rst | 2 ++ sphinx_doc_src/cmds/random.rst | 2 ++ sphinx_doc_src/cmds/read.rst | 2 ++ sphinx_doc_src/cmds/realpath.rst | 2 ++ sphinx_doc_src/cmds/return.rst | 2 ++ sphinx_doc_src/cmds/set.rst | 2 ++ sphinx_doc_src/cmds/set_color.rst | 2 ++ sphinx_doc_src/cmds/source.rst | 2 ++ sphinx_doc_src/cmds/status.rst | 2 ++ sphinx_doc_src/cmds/string.rst | 2 ++ sphinx_doc_src/cmds/suspend.rst | 2 ++ sphinx_doc_src/cmds/switch.rst | 2 ++ sphinx_doc_src/cmds/test.rst | 2 ++ sphinx_doc_src/cmds/trap.rst | 2 ++ sphinx_doc_src/cmds/true.rst | 2 ++ sphinx_doc_src/cmds/type.rst | 2 ++ sphinx_doc_src/cmds/ulimit.rst | 2 ++ sphinx_doc_src/cmds/umask.rst | 2 ++ sphinx_doc_src/cmds/vared.rst | 2 ++ sphinx_doc_src/cmds/wait.rst | 2 ++ sphinx_doc_src/cmds/while.rst | 2 ++ sphinx_doc_src/conf.py | 17 +++++++++-------- 90 files changed, 187 insertions(+), 8 deletions(-) diff --git a/sphinx_doc_src/cmds/abbr.rst b/sphinx_doc_src/cmds/abbr.rst index 6b30925d2..638ad7b93 100644 --- a/sphinx_doc_src/cmds/abbr.rst +++ b/sphinx_doc_src/cmds/abbr.rst @@ -1,3 +1,5 @@ +.. _cmd-abbr: + abbr - manage fish abbreviations ================================ diff --git a/sphinx_doc_src/cmds/alias.rst b/sphinx_doc_src/cmds/alias.rst index ff1e87757..3fd043ed7 100644 --- a/sphinx_doc_src/cmds/alias.rst +++ b/sphinx_doc_src/cmds/alias.rst @@ -1,3 +1,5 @@ +.. _cmd-alias: + alias - create a function ========================= diff --git a/sphinx_doc_src/cmds/and.rst b/sphinx_doc_src/cmds/and.rst index 1b80978ad..4a6b211e3 100644 --- a/sphinx_doc_src/cmds/and.rst +++ b/sphinx_doc_src/cmds/and.rst @@ -1,3 +1,5 @@ +.. _cmd-and: + and - conditionally execute a command ===================================== diff --git a/sphinx_doc_src/cmds/argparse.rst b/sphinx_doc_src/cmds/argparse.rst index d00afa6a7..05a773336 100644 --- a/sphinx_doc_src/cmds/argparse.rst +++ b/sphinx_doc_src/cmds/argparse.rst @@ -1,3 +1,5 @@ +.. _cmd-argparse: + argparse - parse options passed to a fish script or function ============================================================ diff --git a/sphinx_doc_src/cmds/begin.rst b/sphinx_doc_src/cmds/begin.rst index 101d7e89b..b903b7408 100644 --- a/sphinx_doc_src/cmds/begin.rst +++ b/sphinx_doc_src/cmds/begin.rst @@ -1,3 +1,5 @@ +.. _cmd-begin: + begin - start a new block of code ================================= diff --git a/sphinx_doc_src/cmds/bg.rst b/sphinx_doc_src/cmds/bg.rst index fd4aead37..2c5da16fe 100644 --- a/sphinx_doc_src/cmds/bg.rst +++ b/sphinx_doc_src/cmds/bg.rst @@ -1,3 +1,5 @@ +.. _cmd-bg: + bg - send jobs to background ============================ diff --git a/sphinx_doc_src/cmds/bind.rst b/sphinx_doc_src/cmds/bind.rst index ff270cd83..e6a7b0656 100644 --- a/sphinx_doc_src/cmds/bind.rst +++ b/sphinx_doc_src/cmds/bind.rst @@ -1,3 +1,5 @@ +.. _cmd-bind: + bind - handle fish key bindings =============================== diff --git a/sphinx_doc_src/cmds/block.rst b/sphinx_doc_src/cmds/block.rst index e825b6b32..61dee85df 100644 --- a/sphinx_doc_src/cmds/block.rst +++ b/sphinx_doc_src/cmds/block.rst @@ -1,3 +1,5 @@ +.. _cmd-block: + block - temporarily block delivery of events ============================================ diff --git a/sphinx_doc_src/cmds/break.rst b/sphinx_doc_src/cmds/break.rst index 3af73d731..2de9dc959 100644 --- a/sphinx_doc_src/cmds/break.rst +++ b/sphinx_doc_src/cmds/break.rst @@ -1,3 +1,5 @@ +.. _cmd-break: + break - stop the current inner loop =================================== diff --git a/sphinx_doc_src/cmds/breakpoint.rst b/sphinx_doc_src/cmds/breakpoint.rst index e1bca933e..c51d2fa1c 100644 --- a/sphinx_doc_src/cmds/breakpoint.rst +++ b/sphinx_doc_src/cmds/breakpoint.rst @@ -1,3 +1,5 @@ +.. _cmd-breakpoint: + breakpoint - Launch debug mode ============================== diff --git a/sphinx_doc_src/cmds/builtin.rst b/sphinx_doc_src/cmds/builtin.rst index ff6643724..8649961cb 100644 --- a/sphinx_doc_src/cmds/builtin.rst +++ b/sphinx_doc_src/cmds/builtin.rst @@ -1,3 +1,5 @@ +.. _cmd-builtin: + builtin - run a builtin command =============================== diff --git a/sphinx_doc_src/cmds/case.rst b/sphinx_doc_src/cmds/case.rst index 2568f4fd0..a5f0c85ae 100644 --- a/sphinx_doc_src/cmds/case.rst +++ b/sphinx_doc_src/cmds/case.rst @@ -1,3 +1,5 @@ +.. _cmd-case: + case - conditionally execute a block of commands ================================================ diff --git a/sphinx_doc_src/cmds/cd.rst b/sphinx_doc_src/cmds/cd.rst index 5090449e1..8984d1794 100644 --- a/sphinx_doc_src/cmds/cd.rst +++ b/sphinx_doc_src/cmds/cd.rst @@ -1,3 +1,5 @@ +.. _cmd-cd: + cd - change directory ===================== diff --git a/sphinx_doc_src/cmds/cdh.rst b/sphinx_doc_src/cmds/cdh.rst index d013107f1..90ad1df5a 100644 --- a/sphinx_doc_src/cmds/cdh.rst +++ b/sphinx_doc_src/cmds/cdh.rst @@ -1,3 +1,5 @@ +.. _cmd-cdh: + cdh - change to a recently visited directory ============================================ diff --git a/sphinx_doc_src/cmds/command.rst b/sphinx_doc_src/cmds/command.rst index 8fc7c5dc5..69e25c8dd 100644 --- a/sphinx_doc_src/cmds/command.rst +++ b/sphinx_doc_src/cmds/command.rst @@ -1,3 +1,5 @@ +.. _cmd-command: + command - run a program ======================= diff --git a/sphinx_doc_src/cmds/commandline.rst b/sphinx_doc_src/cmds/commandline.rst index 7782c02d2..67e35cb7d 100644 --- a/sphinx_doc_src/cmds/commandline.rst +++ b/sphinx_doc_src/cmds/commandline.rst @@ -1,3 +1,5 @@ +.. _cmd-commandline: + commandline - set or get the current command line buffer ======================================================== diff --git a/sphinx_doc_src/cmds/complete.rst b/sphinx_doc_src/cmds/complete.rst index d1e3f1cec..0f7bdeaa4 100644 --- a/sphinx_doc_src/cmds/complete.rst +++ b/sphinx_doc_src/cmds/complete.rst @@ -1,3 +1,5 @@ +.. _cmd-complete: + complete - edit command specific tab-completions ================================================ diff --git a/sphinx_doc_src/cmds/contains.rst b/sphinx_doc_src/cmds/contains.rst index 081e15fd3..32b0354f4 100644 --- a/sphinx_doc_src/cmds/contains.rst +++ b/sphinx_doc_src/cmds/contains.rst @@ -1,3 +1,5 @@ +.. _cmd-contains: + contains - test if a word is present in a list ============================================== diff --git a/sphinx_doc_src/cmds/continue.rst b/sphinx_doc_src/cmds/continue.rst index b5cac1b57..d31c9e545 100644 --- a/sphinx_doc_src/cmds/continue.rst +++ b/sphinx_doc_src/cmds/continue.rst @@ -1,3 +1,5 @@ +.. _cmd-continue: + continue - skip the remainder of the current iteration of the current inner loop ================================================================================ diff --git a/sphinx_doc_src/cmds/count.rst b/sphinx_doc_src/cmds/count.rst index 981acc915..566c140b0 100644 --- a/sphinx_doc_src/cmds/count.rst +++ b/sphinx_doc_src/cmds/count.rst @@ -1,3 +1,5 @@ +.. _cmd-count: + count - count the number of elements of an array ================================================ diff --git a/sphinx_doc_src/cmds/dirh.rst b/sphinx_doc_src/cmds/dirh.rst index 2b9749521..7dd874b7b 100644 --- a/sphinx_doc_src/cmds/dirh.rst +++ b/sphinx_doc_src/cmds/dirh.rst @@ -1,3 +1,5 @@ +.. _cmd-dirh: + dirh - print directory history ============================== diff --git a/sphinx_doc_src/cmds/dirs.rst b/sphinx_doc_src/cmds/dirs.rst index d888489e4..f5f9440dc 100644 --- a/sphinx_doc_src/cmds/dirs.rst +++ b/sphinx_doc_src/cmds/dirs.rst @@ -1,3 +1,5 @@ +.. _cmd-dirs: + dirs - print directory stack ============================ diff --git a/sphinx_doc_src/cmds/disown.rst b/sphinx_doc_src/cmds/disown.rst index 58d8d9ad3..f423b4563 100644 --- a/sphinx_doc_src/cmds/disown.rst +++ b/sphinx_doc_src/cmds/disown.rst @@ -1,3 +1,5 @@ +.. _cmd-disown: + disown - remove a process from the list of jobs =============================================== diff --git a/sphinx_doc_src/cmds/echo.rst b/sphinx_doc_src/cmds/echo.rst index 065023e3c..003761187 100644 --- a/sphinx_doc_src/cmds/echo.rst +++ b/sphinx_doc_src/cmds/echo.rst @@ -1,3 +1,5 @@ +.. _cmd-echo: + echo - display a line of text ============================= diff --git a/sphinx_doc_src/cmds/else.rst b/sphinx_doc_src/cmds/else.rst index 71523a694..bfda1527e 100644 --- a/sphinx_doc_src/cmds/else.rst +++ b/sphinx_doc_src/cmds/else.rst @@ -1,3 +1,5 @@ +.. _cmd-else: + else - execute command if a condition is not met ================================================ diff --git a/sphinx_doc_src/cmds/emit.rst b/sphinx_doc_src/cmds/emit.rst index 1a5cbc386..85dbc2a5e 100644 --- a/sphinx_doc_src/cmds/emit.rst +++ b/sphinx_doc_src/cmds/emit.rst @@ -1,3 +1,5 @@ +.. _cmd-emit: + emit - Emit a generic event =========================== diff --git a/sphinx_doc_src/cmds/end.rst b/sphinx_doc_src/cmds/end.rst index e1e7b2182..9da25489f 100644 --- a/sphinx_doc_src/cmds/end.rst +++ b/sphinx_doc_src/cmds/end.rst @@ -1,3 +1,5 @@ +.. _cmd-end: + end - end a block of commands. ============================== diff --git a/sphinx_doc_src/cmds/eval.rst b/sphinx_doc_src/cmds/eval.rst index f34dbd767..e3d7d8e5e 100644 --- a/sphinx_doc_src/cmds/eval.rst +++ b/sphinx_doc_src/cmds/eval.rst @@ -1,3 +1,5 @@ +.. _cmd-eval: + eval - evaluate the specified commands ====================================== diff --git a/sphinx_doc_src/cmds/exec.rst b/sphinx_doc_src/cmds/exec.rst index 8acc7d6be..7ad7b422d 100644 --- a/sphinx_doc_src/cmds/exec.rst +++ b/sphinx_doc_src/cmds/exec.rst @@ -1,3 +1,5 @@ +.. _cmd-exec: + exec - execute command in current process ========================================= diff --git a/sphinx_doc_src/cmds/exit.rst b/sphinx_doc_src/cmds/exit.rst index 2f3f75594..e5155c76d 100644 --- a/sphinx_doc_src/cmds/exit.rst +++ b/sphinx_doc_src/cmds/exit.rst @@ -1,3 +1,5 @@ +.. _cmd-exit: + exit - exit the shell ===================== diff --git a/sphinx_doc_src/cmds/false.rst b/sphinx_doc_src/cmds/false.rst index d972f5864..67fd17a22 100644 --- a/sphinx_doc_src/cmds/false.rst +++ b/sphinx_doc_src/cmds/false.rst @@ -1,3 +1,5 @@ +.. _cmd-false: + false - return an unsuccessful result ===================================== diff --git a/sphinx_doc_src/cmds/fg.rst b/sphinx_doc_src/cmds/fg.rst index f5c8a7d73..88a7b1aca 100644 --- a/sphinx_doc_src/cmds/fg.rst +++ b/sphinx_doc_src/cmds/fg.rst @@ -1,3 +1,5 @@ +.. _cmd-fg: + fg - bring job to foreground ============================ diff --git a/sphinx_doc_src/cmds/fish.rst b/sphinx_doc_src/cmds/fish.rst index b3b8a090b..572ed360f 100644 --- a/sphinx_doc_src/cmds/fish.rst +++ b/sphinx_doc_src/cmds/fish.rst @@ -1,3 +1,5 @@ +.. _cmd-fish: + fish - the friendly interactive shell ===================================== diff --git a/sphinx_doc_src/cmds/fish_breakpoint_prompt.rst b/sphinx_doc_src/cmds/fish_breakpoint_prompt.rst index 51cfc020c..1c2722e63 100644 --- a/sphinx_doc_src/cmds/fish_breakpoint_prompt.rst +++ b/sphinx_doc_src/cmds/fish_breakpoint_prompt.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_breakpoint_prompt: + fish_breakpoint_prompt - define the prompt when stopped at a breakpoint ======================================================================= diff --git a/sphinx_doc_src/cmds/fish_config.rst b/sphinx_doc_src/cmds/fish_config.rst index 386797299..7b2c57b76 100644 --- a/sphinx_doc_src/cmds/fish_config.rst +++ b/sphinx_doc_src/cmds/fish_config.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_config: + fish_config - start the web-based configuration interface ========================================================= diff --git a/sphinx_doc_src/cmds/fish_git_prompt.rst b/sphinx_doc_src/cmds/fish_git_prompt.rst index 221feefa8..9a589aa1b 100644 --- a/sphinx_doc_src/cmds/fish_git_prompt.rst +++ b/sphinx_doc_src/cmds/fish_git_prompt.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_git_prompt: + fish_git_prompt - output git information for use in a prompt ============================================================ diff --git a/sphinx_doc_src/cmds/fish_hg_prompt.rst b/sphinx_doc_src/cmds/fish_hg_prompt.rst index 5c8a1a0cb..f0d1d0caa 100644 --- a/sphinx_doc_src/cmds/fish_hg_prompt.rst +++ b/sphinx_doc_src/cmds/fish_hg_prompt.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_hg_prompt: + fish_hg_prompt - output mercurial information for use in a prompt ================================================================= diff --git a/sphinx_doc_src/cmds/fish_indent.rst b/sphinx_doc_src/cmds/fish_indent.rst index 56dd7e798..081265f87 100644 --- a/sphinx_doc_src/cmds/fish_indent.rst +++ b/sphinx_doc_src/cmds/fish_indent.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_indent: + fish_indent - indenter and prettifier ===================================== diff --git a/sphinx_doc_src/cmds/fish_key_reader.rst b/sphinx_doc_src/cmds/fish_key_reader.rst index ea8f4d4c3..265aa6ab3 100644 --- a/sphinx_doc_src/cmds/fish_key_reader.rst +++ b/sphinx_doc_src/cmds/fish_key_reader.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_key_reader: + fish_key_reader - explore what characters keyboard keys send ============================================================ diff --git a/sphinx_doc_src/cmds/fish_mode_prompt.rst b/sphinx_doc_src/cmds/fish_mode_prompt.rst index 88e1cb2e7..83588ec04 100644 --- a/sphinx_doc_src/cmds/fish_mode_prompt.rst +++ b/sphinx_doc_src/cmds/fish_mode_prompt.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_mode_prompt: + fish_mode_prompt - define the appearance of the mode indicator ============================================================== diff --git a/sphinx_doc_src/cmds/fish_opt.rst b/sphinx_doc_src/cmds/fish_opt.rst index dc8639978..35d3222a8 100644 --- a/sphinx_doc_src/cmds/fish_opt.rst +++ b/sphinx_doc_src/cmds/fish_opt.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_opt: + fish_opt - create an option spec for the argparse command ========================================================= diff --git a/sphinx_doc_src/cmds/fish_prompt.rst b/sphinx_doc_src/cmds/fish_prompt.rst index f89edadcd..f11c6036d 100644 --- a/sphinx_doc_src/cmds/fish_prompt.rst +++ b/sphinx_doc_src/cmds/fish_prompt.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_prompt: + fish_prompt - define the appearance of the command line prompt ============================================================== diff --git a/sphinx_doc_src/cmds/fish_right_prompt.rst b/sphinx_doc_src/cmds/fish_right_prompt.rst index 55237d703..c2c66b8a2 100644 --- a/sphinx_doc_src/cmds/fish_right_prompt.rst +++ b/sphinx_doc_src/cmds/fish_right_prompt.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_right_prompt: + fish_right_prompt - define the appearance of the right-side command line prompt =============================================================================== diff --git a/sphinx_doc_src/cmds/fish_svn_prompt.rst b/sphinx_doc_src/cmds/fish_svn_prompt.rst index 5770585f8..f3d450590 100644 --- a/sphinx_doc_src/cmds/fish_svn_prompt.rst +++ b/sphinx_doc_src/cmds/fish_svn_prompt.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_svn_prompt: + fish_svn_prompt - output svn information for use in a prompt ============================================================ diff --git a/sphinx_doc_src/cmds/fish_update_completions.rst b/sphinx_doc_src/cmds/fish_update_completions.rst index b269d56bf..b3f75b585 100644 --- a/sphinx_doc_src/cmds/fish_update_completions.rst +++ b/sphinx_doc_src/cmds/fish_update_completions.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_update_completions: + fish_update_completions - Update completions using manual pages =============================================================== diff --git a/sphinx_doc_src/cmds/fish_vcs_prompt.rst b/sphinx_doc_src/cmds/fish_vcs_prompt.rst index 92a7d72ab..8ab93d32f 100644 --- a/sphinx_doc_src/cmds/fish_vcs_prompt.rst +++ b/sphinx_doc_src/cmds/fish_vcs_prompt.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_vcs_prompt: + fish_vcs_prompt - output vcs information for use in a prompt ============================================================ diff --git a/sphinx_doc_src/cmds/fish_vi_mode.rst b/sphinx_doc_src/cmds/fish_vi_mode.rst index 590538b3b..61d8bb713 100644 --- a/sphinx_doc_src/cmds/fish_vi_mode.rst +++ b/sphinx_doc_src/cmds/fish_vi_mode.rst @@ -1,3 +1,5 @@ +.. _cmd-fish_vi_mode: + fish_vi_mode - Enable vi mode ============================= diff --git a/sphinx_doc_src/cmds/for.rst b/sphinx_doc_src/cmds/for.rst index cfb02bf01..4c06c5912 100644 --- a/sphinx_doc_src/cmds/for.rst +++ b/sphinx_doc_src/cmds/for.rst @@ -1,3 +1,5 @@ +.. _cmd-for: + for - perform a set of commands multiple times. =============================================== diff --git a/sphinx_doc_src/cmds/funced.rst b/sphinx_doc_src/cmds/funced.rst index 2f33c6906..df205b015 100644 --- a/sphinx_doc_src/cmds/funced.rst +++ b/sphinx_doc_src/cmds/funced.rst @@ -1,3 +1,5 @@ +.. _cmd-funced: + funced - edit a function interactively ====================================== diff --git a/sphinx_doc_src/cmds/funcsave.rst b/sphinx_doc_src/cmds/funcsave.rst index fad1550b6..a93f23814 100644 --- a/sphinx_doc_src/cmds/funcsave.rst +++ b/sphinx_doc_src/cmds/funcsave.rst @@ -1,3 +1,5 @@ +.. _cmd-funcsave: + funcsave - save the definition of a function to the user's autoload directory ============================================================================= diff --git a/sphinx_doc_src/cmds/function.rst b/sphinx_doc_src/cmds/function.rst index 093f46ee0..d95e2b357 100644 --- a/sphinx_doc_src/cmds/function.rst +++ b/sphinx_doc_src/cmds/function.rst @@ -1,3 +1,5 @@ +.. _cmd-function: + function - create a function ============================ diff --git a/sphinx_doc_src/cmds/functions.rst b/sphinx_doc_src/cmds/functions.rst index abb1d4398..44bad3035 100644 --- a/sphinx_doc_src/cmds/functions.rst +++ b/sphinx_doc_src/cmds/functions.rst @@ -1,3 +1,5 @@ +.. _cmd-functions: + functions - print or erase functions ==================================== diff --git a/sphinx_doc_src/cmds/help.rst b/sphinx_doc_src/cmds/help.rst index 314f3c0fc..24ea5b75d 100644 --- a/sphinx_doc_src/cmds/help.rst +++ b/sphinx_doc_src/cmds/help.rst @@ -1,3 +1,5 @@ +.. _cmd-help: + help - display fish documentation ================================= diff --git a/sphinx_doc_src/cmds/history.rst b/sphinx_doc_src/cmds/history.rst index 3056f262e..af239e7d1 100644 --- a/sphinx_doc_src/cmds/history.rst +++ b/sphinx_doc_src/cmds/history.rst @@ -1,3 +1,5 @@ +.. _cmd-history: + history - Show and manipulate command history ============================================= diff --git a/sphinx_doc_src/cmds/if.rst b/sphinx_doc_src/cmds/if.rst index ba90693ba..7e5c0fa4c 100644 --- a/sphinx_doc_src/cmds/if.rst +++ b/sphinx_doc_src/cmds/if.rst @@ -1,3 +1,5 @@ +.. _cmd-if: + if - conditionally execute a command ==================================== diff --git a/sphinx_doc_src/cmds/isatty.rst b/sphinx_doc_src/cmds/isatty.rst index 744003049..1d4711c36 100644 --- a/sphinx_doc_src/cmds/isatty.rst +++ b/sphinx_doc_src/cmds/isatty.rst @@ -1,3 +1,5 @@ +.. _cmd-isatty: + isatty - test if a file descriptor is a tty. ============================================ diff --git a/sphinx_doc_src/cmds/jobs.rst b/sphinx_doc_src/cmds/jobs.rst index b2da7b6dc..1c0f435cc 100644 --- a/sphinx_doc_src/cmds/jobs.rst +++ b/sphinx_doc_src/cmds/jobs.rst @@ -1,3 +1,5 @@ +.. _cmd-jobs: + jobs - print currently running jobs =================================== diff --git a/sphinx_doc_src/cmds/math.rst b/sphinx_doc_src/cmds/math.rst index 254055047..b5107ead5 100644 --- a/sphinx_doc_src/cmds/math.rst +++ b/sphinx_doc_src/cmds/math.rst @@ -1,3 +1,5 @@ +.. _cmd-math: + math - Perform mathematics calculations ======================================= diff --git a/sphinx_doc_src/cmds/nextd.rst b/sphinx_doc_src/cmds/nextd.rst index df8e10a05..4bb862b5b 100644 --- a/sphinx_doc_src/cmds/nextd.rst +++ b/sphinx_doc_src/cmds/nextd.rst @@ -1,3 +1,5 @@ +.. _cmd-nextd: + nextd - move forward through directory history ============================================== diff --git a/sphinx_doc_src/cmds/not.rst b/sphinx_doc_src/cmds/not.rst index 524f69605..55931a70b 100644 --- a/sphinx_doc_src/cmds/not.rst +++ b/sphinx_doc_src/cmds/not.rst @@ -1,3 +1,5 @@ +.. _cmd-not: + not - negate the exit status of a job ===================================== diff --git a/sphinx_doc_src/cmds/open.rst b/sphinx_doc_src/cmds/open.rst index b4e5ac63d..092a9f57d 100644 --- a/sphinx_doc_src/cmds/open.rst +++ b/sphinx_doc_src/cmds/open.rst @@ -1,3 +1,5 @@ +.. _cmd-open: + open - open file in its default application =========================================== diff --git a/sphinx_doc_src/cmds/or.rst b/sphinx_doc_src/cmds/or.rst index 258d22158..9d5436139 100644 --- a/sphinx_doc_src/cmds/or.rst +++ b/sphinx_doc_src/cmds/or.rst @@ -1,3 +1,5 @@ +.. _cmd-or: + or - conditionally execute a command ==================================== diff --git a/sphinx_doc_src/cmds/popd.rst b/sphinx_doc_src/cmds/popd.rst index 945912777..772dbb690 100644 --- a/sphinx_doc_src/cmds/popd.rst +++ b/sphinx_doc_src/cmds/popd.rst @@ -1,3 +1,5 @@ +.. _cmd-popd: + popd - move through directory stack =================================== diff --git a/sphinx_doc_src/cmds/prevd.rst b/sphinx_doc_src/cmds/prevd.rst index 10a749803..b96338c51 100644 --- a/sphinx_doc_src/cmds/prevd.rst +++ b/sphinx_doc_src/cmds/prevd.rst @@ -1,3 +1,5 @@ +.. _cmd-prevd: + prevd - move backward through directory history =============================================== diff --git a/sphinx_doc_src/cmds/printf.rst b/sphinx_doc_src/cmds/printf.rst index 6c1717be0..10a4b4821 100644 --- a/sphinx_doc_src/cmds/printf.rst +++ b/sphinx_doc_src/cmds/printf.rst @@ -1,3 +1,5 @@ +.. _cmd-printf: + printf - display text according to a format string ================================================== diff --git a/sphinx_doc_src/cmds/prompt_pwd.rst b/sphinx_doc_src/cmds/prompt_pwd.rst index 3d9ac5b37..5af850c94 100644 --- a/sphinx_doc_src/cmds/prompt_pwd.rst +++ b/sphinx_doc_src/cmds/prompt_pwd.rst @@ -1,3 +1,5 @@ +.. _cmd-prompt_pwd: + prompt_pwd - Print pwd suitable for prompt ========================================== diff --git a/sphinx_doc_src/cmds/psub.rst b/sphinx_doc_src/cmds/psub.rst index f61a183f2..d63edb3d0 100644 --- a/sphinx_doc_src/cmds/psub.rst +++ b/sphinx_doc_src/cmds/psub.rst @@ -1,3 +1,5 @@ +.. _cmd-psub: + psub - perform process substitution =================================== diff --git a/sphinx_doc_src/cmds/pushd.rst b/sphinx_doc_src/cmds/pushd.rst index a524ac93f..82cc1a0bc 100644 --- a/sphinx_doc_src/cmds/pushd.rst +++ b/sphinx_doc_src/cmds/pushd.rst @@ -1,3 +1,5 @@ +.. _cmd-pushd: + pushd - push directory to directory stack ========================================= diff --git a/sphinx_doc_src/cmds/pwd.rst b/sphinx_doc_src/cmds/pwd.rst index 0521514a5..1cf815a0f 100644 --- a/sphinx_doc_src/cmds/pwd.rst +++ b/sphinx_doc_src/cmds/pwd.rst @@ -1,3 +1,5 @@ +.. _cmd-pwd: + pwd - output the current working directory ========================================== diff --git a/sphinx_doc_src/cmds/random.rst b/sphinx_doc_src/cmds/random.rst index 9b5a19ab2..916aae5d0 100644 --- a/sphinx_doc_src/cmds/random.rst +++ b/sphinx_doc_src/cmds/random.rst @@ -1,3 +1,5 @@ +.. _cmd-random: + random - generate random number =============================== diff --git a/sphinx_doc_src/cmds/read.rst b/sphinx_doc_src/cmds/read.rst index a420b5382..0aca5e884 100644 --- a/sphinx_doc_src/cmds/read.rst +++ b/sphinx_doc_src/cmds/read.rst @@ -1,3 +1,5 @@ +.. _cmd-read: + read - read line of input into variables ======================================== diff --git a/sphinx_doc_src/cmds/realpath.rst b/sphinx_doc_src/cmds/realpath.rst index 859c6458b..2fee264de 100644 --- a/sphinx_doc_src/cmds/realpath.rst +++ b/sphinx_doc_src/cmds/realpath.rst @@ -1,3 +1,5 @@ +.. _cmd-realpath: + realpath - Convert a path to an absolute path without symlinks ============================================================== diff --git a/sphinx_doc_src/cmds/return.rst b/sphinx_doc_src/cmds/return.rst index 6de7c1dd7..3ad6cc315 100644 --- a/sphinx_doc_src/cmds/return.rst +++ b/sphinx_doc_src/cmds/return.rst @@ -1,3 +1,5 @@ +.. _cmd-return: + return - stop the current inner function ======================================== diff --git a/sphinx_doc_src/cmds/set.rst b/sphinx_doc_src/cmds/set.rst index dd588c1f8..4e4c2845c 100644 --- a/sphinx_doc_src/cmds/set.rst +++ b/sphinx_doc_src/cmds/set.rst @@ -1,3 +1,5 @@ +.. _cmd-set: + set - display and change shell variables. ========================================= diff --git a/sphinx_doc_src/cmds/set_color.rst b/sphinx_doc_src/cmds/set_color.rst index e616fb58e..b9dc44761 100644 --- a/sphinx_doc_src/cmds/set_color.rst +++ b/sphinx_doc_src/cmds/set_color.rst @@ -1,3 +1,5 @@ +.. _cmd-set_color: + set_color - set the terminal color ================================== diff --git a/sphinx_doc_src/cmds/source.rst b/sphinx_doc_src/cmds/source.rst index 21fd13b2b..2d07e24ce 100644 --- a/sphinx_doc_src/cmds/source.rst +++ b/sphinx_doc_src/cmds/source.rst @@ -1,3 +1,5 @@ +.. _cmd-source: + source - evaluate contents of file. =================================== diff --git a/sphinx_doc_src/cmds/status.rst b/sphinx_doc_src/cmds/status.rst index 397933939..c058e5986 100644 --- a/sphinx_doc_src/cmds/status.rst +++ b/sphinx_doc_src/cmds/status.rst @@ -1,3 +1,5 @@ +.. _cmd-status: + status - query fish runtime information ======================================= diff --git a/sphinx_doc_src/cmds/string.rst b/sphinx_doc_src/cmds/string.rst index 4009588e3..b7fa6752c 100644 --- a/sphinx_doc_src/cmds/string.rst +++ b/sphinx_doc_src/cmds/string.rst @@ -1,3 +1,5 @@ +.. _cmd-string: + string - manipulate strings =========================== diff --git a/sphinx_doc_src/cmds/suspend.rst b/sphinx_doc_src/cmds/suspend.rst index 7e1b92129..5c8c69a47 100644 --- a/sphinx_doc_src/cmds/suspend.rst +++ b/sphinx_doc_src/cmds/suspend.rst @@ -1,3 +1,5 @@ +.. _cmd-suspend: + suspend - suspend the current shell =================================== diff --git a/sphinx_doc_src/cmds/switch.rst b/sphinx_doc_src/cmds/switch.rst index d0a106b2f..3613d68e8 100644 --- a/sphinx_doc_src/cmds/switch.rst +++ b/sphinx_doc_src/cmds/switch.rst @@ -1,3 +1,5 @@ +.. _cmd-switch: + switch - conditionally execute a block of commands ================================================== diff --git a/sphinx_doc_src/cmds/test.rst b/sphinx_doc_src/cmds/test.rst index 834415e32..0c8914398 100644 --- a/sphinx_doc_src/cmds/test.rst +++ b/sphinx_doc_src/cmds/test.rst @@ -1,3 +1,5 @@ +.. _cmd-test: + test - perform tests on files and text ====================================== diff --git a/sphinx_doc_src/cmds/trap.rst b/sphinx_doc_src/cmds/trap.rst index 318fbd1b4..dbe8ce890 100644 --- a/sphinx_doc_src/cmds/trap.rst +++ b/sphinx_doc_src/cmds/trap.rst @@ -1,3 +1,5 @@ +.. _cmd-trap: + trap - perform an action when the shell receives a signal ========================================================= diff --git a/sphinx_doc_src/cmds/true.rst b/sphinx_doc_src/cmds/true.rst index c8607d6ff..c6aa4d889 100644 --- a/sphinx_doc_src/cmds/true.rst +++ b/sphinx_doc_src/cmds/true.rst @@ -1,3 +1,5 @@ +.. _cmd-true: + true - return a successful result ================================= diff --git a/sphinx_doc_src/cmds/type.rst b/sphinx_doc_src/cmds/type.rst index 5f2347084..31e5ccf70 100644 --- a/sphinx_doc_src/cmds/type.rst +++ b/sphinx_doc_src/cmds/type.rst @@ -1,3 +1,5 @@ +.. _cmd-type: + type - indicate how a command would be interpreted ================================================== diff --git a/sphinx_doc_src/cmds/ulimit.rst b/sphinx_doc_src/cmds/ulimit.rst index 846e06993..ce03ba10e 100644 --- a/sphinx_doc_src/cmds/ulimit.rst +++ b/sphinx_doc_src/cmds/ulimit.rst @@ -1,3 +1,5 @@ +.. _cmd-ulimit: + ulimit - set or get resource usage limits ========================================= diff --git a/sphinx_doc_src/cmds/umask.rst b/sphinx_doc_src/cmds/umask.rst index ff18bfac2..bafbca7aa 100644 --- a/sphinx_doc_src/cmds/umask.rst +++ b/sphinx_doc_src/cmds/umask.rst @@ -1,3 +1,5 @@ +.. _cmd-umask: + umask - set or get the file creation mode mask ============================================== diff --git a/sphinx_doc_src/cmds/vared.rst b/sphinx_doc_src/cmds/vared.rst index 2fb29bf98..aec694ab6 100644 --- a/sphinx_doc_src/cmds/vared.rst +++ b/sphinx_doc_src/cmds/vared.rst @@ -1,3 +1,5 @@ +.. _cmd-vared: + vared - interactively edit the value of an environment variable =============================================================== diff --git a/sphinx_doc_src/cmds/wait.rst b/sphinx_doc_src/cmds/wait.rst index 763d42191..6268d616b 100644 --- a/sphinx_doc_src/cmds/wait.rst +++ b/sphinx_doc_src/cmds/wait.rst @@ -1,3 +1,5 @@ +.. _cmd-wait: + wait - wait for jobs to complete ================================ diff --git a/sphinx_doc_src/cmds/while.rst b/sphinx_doc_src/cmds/while.rst index ccc022857..0bc41f9d8 100644 --- a/sphinx_doc_src/cmds/while.rst +++ b/sphinx_doc_src/cmds/while.rst @@ -1,3 +1,5 @@ +.. _cmd-while: + while - perform a command multiple times ======================================== diff --git a/sphinx_doc_src/conf.py b/sphinx_doc_src/conf.py index 52a49debb..edf1b4a29 100644 --- a/sphinx_doc_src/conf.py +++ b/sphinx_doc_src/conf.py @@ -144,14 +144,15 @@ latex_documents = [ # -- Options for manual page output ------------------------------------------ -def get_command_description(path): - """ Return the description for a command, by parsing its first line """ +def get_command_description(path, name): + """ Return the description for a command, by parsing its synopsis line """ with open(path) as fd: - title = fd.readline() - if ' - ' not in title: - raise SphinxWarning('No description in file %s' % os.path.basename(path)) - _, desc = title.split(' - ', 1) - return desc.strip() + for line in fd: + if line.startswith(name + " - "): + _, desc = line.split(' - ', 1) + return desc.strip() + raise SphinxWarning('No description in file %s' % os.path.basename(path)) + # One entry per manual page. List of tuples @@ -163,7 +164,7 @@ man_pages = [ for path in sorted(glob.glob('cmds/*')): docname = strip_ext(path) cmd = os.path.basename(docname) - man_pages.append((docname, cmd, get_command_description(path), '', 1)) + man_pages.append((docname, cmd, get_command_description(path, cmd), '', 1)) # -- Options for Texinfo output ---------------------------------------------- From cb94dd4d304f32938618d82ee33d68da85e29784 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 31 Mar 2019 11:07:59 +0200 Subject: [PATCH 0213/1732] docs: Use command labels [ci skip] --- sphinx_doc_src/cmds/alias.rst | 4 ++-- sphinx_doc_src/cmds/and.rst | 2 +- sphinx_doc_src/cmds/argparse.rst | 4 ++-- sphinx_doc_src/cmds/block.rst | 2 +- sphinx_doc_src/cmds/break.rst | 2 +- sphinx_doc_src/cmds/cd.rst | 4 ++-- sphinx_doc_src/cmds/exit.rst | 2 +- sphinx_doc_src/cmds/fish_opt.rst | 2 +- sphinx_doc_src/cmds/function.rst | 4 ++-- sphinx_doc_src/faq.rst | 10 +++++----- sphinx_doc_src/tutorial.rst | 4 ++-- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sphinx_doc_src/cmds/alias.rst b/sphinx_doc_src/cmds/alias.rst index 3fd043ed7..0ed7988e9 100644 --- a/sphinx_doc_src/cmds/alias.rst +++ b/sphinx_doc_src/cmds/alias.rst @@ -14,7 +14,7 @@ alias [OPTIONS] NAME=DEFINITION Description ----------- -``alias`` is a simple wrapper for the ``function`` builtin, which creates a function wrapping a command. It has similar syntax to POSIX shell ``alias``. For other uses, it is recommended to define a `function `__. +``alias`` is a simple wrapper for the ``function`` builtin, which creates a function wrapping a command. It has similar syntax to POSIX shell ``alias``. For other uses, it is recommended to define a :ref:`function `. ``fish`` marks functions that have been created by ``alias`` by including the command used to create them in the function description. You can list ``alias``-created functions by running ``alias`` without arguments. They must be erased using ``functions -e``. @@ -27,7 +27,7 @@ The following options are available: - ``-h`` or ``--help`` displays help about using this command. -- ``-s`` or ``--save`` Automatically save the function created by the alias into your fish configuration directory using `funcsave `__. +- ``-s`` or ``--save`` Automatically save the function created by the alias into your fish configuration directory using :ref:`funcsave `. Example ------- diff --git a/sphinx_doc_src/cmds/and.rst b/sphinx_doc_src/cmds/and.rst index 4a6b211e3..a0c1070f2 100644 --- a/sphinx_doc_src/cmds/and.rst +++ b/sphinx_doc_src/cmds/and.rst @@ -14,7 +14,7 @@ Description ``and`` is used to execute a command if the previous command was successful (returned a status of 0). -``and`` statements may be used as part of the condition in an `while `__ or `if `__ block. +``and`` statements may be used as part of the condition in an :ref:`while ` or :ref:`if ` block. ``and`` does not change the current exit status itself, but the command it runs most likely will. The exit status of the last foreground command to exit can always be accessed using the `$status `__ variable. diff --git a/sphinx_doc_src/cmds/argparse.rst b/sphinx_doc_src/cmds/argparse.rst index 05a773336..e714a3150 100644 --- a/sphinx_doc_src/cmds/argparse.rst +++ b/sphinx_doc_src/cmds/argparse.rst @@ -14,7 +14,7 @@ Description This command makes it easy for fish scripts and functions to handle arguments in a manner 100% identical to how fish builtin commands handle their arguments. You pass a sequence of arguments that define the options recognized, followed by a literal ``--``, then the arguments to be parsed (which might also include a literal ``--``). More on this in the `usage <#argparse-usage>`__ section below. -Each OPTION_SPEC can be written in the `domain specific language <#argparse-option-specs>`__ described below or created using the companion `fish_opt `__ command. All OPTION_SPECs must appear after any argparse flags and before the ``--`` that separates them from the arguments to be parsed. +Each OPTION_SPEC can be written in the `domain specific language <#argparse-option-specs>`__ described below or created using the companion :ref:`fish_opt ` command. All OPTION_SPECs must appear after any argparse flags and before the ``--`` that separates them from the arguments to be parsed. Each option that is seen in the ARG list will result in a var name of the form ``_flag_X``, where ``X`` is the short flag letter and the long flag name. The OPTION_SPEC always requires a short flag even if it can't be used. So there will always be ``_flag_X`` var set using the short flag letter if the corresponding short or long flag is seen. The long flag name var (e.g., ``_flag_help``) will only be defined, obviously, if the OPTION_SPEC includes a long flag name. @@ -95,7 +95,7 @@ Each option specification is a string composed of - Optionally a ``!`` followed by fish script to validate the value. Typically this will be a function to run. If the return status is zero the value for the flag is valid. If non-zero the value is invalid. Any error messages should be written to stdout (not stderr). See the section on `Flag Value Validation <#arparse-validation>`__ for more information. -See the `fish_opt `__ command for a friendlier but more verbose way to create option specifications. +See the :ref:`fish_opt ` command for a friendlier but more verbose way to create option specifications. In the following examples if a flag is not seen when parsing the arguments then the corresponding _flag_X var(s) will not be set. diff --git a/sphinx_doc_src/cmds/block.rst b/sphinx_doc_src/cmds/block.rst index 61dee85df..dc786dd9a 100644 --- a/sphinx_doc_src/cmds/block.rst +++ b/sphinx_doc_src/cmds/block.rst @@ -12,7 +12,7 @@ block [OPTIONS...] Description ----------- -``block`` prevents events triggered by ``fish`` or the `emit `__ command from being delivered and acted upon while the block is in place. +``block`` prevents events triggered by ``fish`` or the :ref:`emit ` command from being delivered and acted upon while the block is in place. In functions, ``block`` can be useful while performing work that should not be interrupted by the shell. diff --git a/sphinx_doc_src/cmds/break.rst b/sphinx_doc_src/cmds/break.rst index 2de9dc959..82bc2797d 100644 --- a/sphinx_doc_src/cmds/break.rst +++ b/sphinx_doc_src/cmds/break.rst @@ -12,7 +12,7 @@ LOOP_CONSTRUCT; [COMMANDS...] break; [COMMANDS...] end Description ----------- -``break`` halts a currently running loop, such as a `switch `__, `for `__ or `while `__ loop. It is usually added inside of a conditional block such as an `if `__ block. +``break`` halts a currently running loop, such as a :ref:`switch `, :ref:`for ` or :ref:`while ` loop. It is usually added inside of a conditional block such as an :ref:`if ` block. There are no parameters for ``break``. diff --git a/sphinx_doc_src/cmds/cd.rst b/sphinx_doc_src/cmds/cd.rst index 8984d1794..404a5fce6 100644 --- a/sphinx_doc_src/cmds/cd.rst +++ b/sphinx_doc_src/cmds/cd.rst @@ -19,7 +19,7 @@ If ``DIRECTORY`` is a relative path, the paths found in the ``CDPATH`` list will Note that the shell will attempt to change directory without requiring ``cd`` if the name of a directory is provided (starting with ``.``, ``/`` or ``~``, or ending with ``/``). -Fish also ships a wrapper function around the builtin ``cd`` that understands ``cd -`` as changing to the previous directory. See also `prevd `__. This wrapper function maintains a history of the 25 most recently visited directories in the ``$dirprev`` and ``$dirnext`` global variables. If you make those universal variables your ``cd`` history is shared among all fish instances. +Fish also ships a wrapper function around the builtin ``cd`` that understands ``cd -`` as changing to the previous directory. See also :ref:`prevd `. This wrapper function maintains a history of the 25 most recently visited directories in the ``$dirprev`` and ``$dirnext`` global variables. If you make those universal variables your ``cd`` history is shared among all fish instances. As a special case, ``cd .`` is equivalent to ``cd $PWD``, which is useful in cases where a mountpoint has been recycled or a directory has been removed and recreated. @@ -40,4 +40,4 @@ Examples See Also -------- -See also the `cdh `__ command for changing to a recently visited directory. +See also the :ref:`cdh ` command for changing to a recently visited directory. diff --git a/sphinx_doc_src/cmds/exit.rst b/sphinx_doc_src/cmds/exit.rst index e5155c76d..256a15589 100644 --- a/sphinx_doc_src/cmds/exit.rst +++ b/sphinx_doc_src/cmds/exit.rst @@ -14,4 +14,4 @@ Description ``exit`` causes fish to exit. If ``STATUS`` is supplied, it will be converted to an integer and used as the exit code. Otherwise, the exit code will be that of the last command executed. -If exit is called while sourcing a file (using the `source `__ builtin) the rest of the file will be skipped, but the shell itself will not exit. +If exit is called while sourcing a file (using the :ref:`source ` builtin) the rest of the file will be skipped, but the shell itself will not exit. diff --git a/sphinx_doc_src/cmds/fish_opt.rst b/sphinx_doc_src/cmds/fish_opt.rst index 35d3222a8..bf4c5a537 100644 --- a/sphinx_doc_src/cmds/fish_opt.rst +++ b/sphinx_doc_src/cmds/fish_opt.rst @@ -15,7 +15,7 @@ Synopsis Description ----------- -This command provides a way to produce option specifications suitable for use with the `argparse `__ command. You can, of course, write the option specs by hand without using this command. But you might prefer to use this for the clarity it provides. +This command provides a way to produce option specifications suitable for use with the :ref:`argparse ` command. You can, of course, write the option specs by hand without using this command. But you might prefer to use this for the clarity it provides. The following ``argparse`` options are available: diff --git a/sphinx_doc_src/cmds/function.rst b/sphinx_doc_src/cmds/function.rst index d95e2b357..b7480331b 100644 --- a/sphinx_doc_src/cmds/function.rst +++ b/sphinx_doc_src/cmds/function.rst @@ -22,7 +22,7 @@ The following options are available: - ``-d DESCRIPTION`` or ``--description=DESCRIPTION`` is a description of what the function does, suitable as a completion description. -- ``-w WRAPPED_COMMAND`` or ``--wraps=WRAPPED_COMMAND`` causes the function to inherit completions from the given wrapped command. See the documentation for `complete `__ for more information. +- ``-w WRAPPED_COMMAND`` or ``--wraps=WRAPPED_COMMAND`` causes the function to inherit completions from the given wrapped command. See the documentation for :ref:`complete ` for more information. - ``-e`` or ``--on-event EVENT_NAME`` tells fish to run this function when the specified named event is emitted. Fish internally generates named events e.g. when showing the prompt. @@ -43,7 +43,7 @@ The following options are available: If the user enters any additional arguments after the function, they are inserted into the environment `variable array `__ ``$argv``. If the ``--argument-names`` option is provided, the arguments are also assigned to names specified in that option. -By using one of the event handler switches, a function can be made to run automatically at specific events. The user may generate new events using the `emit `__ builtin. Fish generates the following named events: +By using one of the event handler switches, a function can be made to run automatically at specific events. The user may generate new events using the :ref:`emit ` builtin. Fish generates the following named events: - ``fish_prompt``, which is emitted whenever a new fish prompt is about to be displayed. diff --git a/sphinx_doc_src/faq.rst b/sphinx_doc_src/faq.rst index ebac28e2d..423e630e7 100644 --- a/sphinx_doc_src/faq.rst +++ b/sphinx_doc_src/faq.rst @@ -3,7 +3,7 @@ Frequently asked questions How do I set or clear an environment variable? ---------------------------------------------- -Use the `set `__ command:: +Use the :ref:`set ` command:: set -x key value set -e key @@ -26,7 +26,7 @@ The prompt is the output of the ``fish_prompt`` function. Put it in ``~/.config/ end -You can also use the Web configuration tool, `fish_config `__, to preview and choose from a gallery of sample prompts. +You can also use the Web configuration tool, :ref:`fish_config `, to preview and choose from a gallery of sample prompts. How do I run a command from history? @@ -93,7 +93,7 @@ If you are just interested in success or failure, you can run the command direct end -See the documentation for `test `__ and `if `__ for more information. +See the documentation for :ref:`test ` and :ref:`if ` for more information. ~~ How do I set an environment variable for just one command? @@ -162,12 +162,12 @@ add a statement to your `user initialization file `_ How do I customize my syntax highlighting colors? ------------------------------------------------- -Use the web configuration tool, `fish_config `__, or alter the `fish_color family of environment variables `__. +Use the web configuration tool, :ref:`fish_config `, or alter the `fish_color family of environment variables `__. ~~ How do I update man page completions? ------------------------------------- -Use the `fish_update_completions `__ command. +Use the :ref:`fish_update_completions ` command. ~~ I accidentally entered a directory path and fish changed directory. What happened? diff --git a/sphinx_doc_src/tutorial.rst b/sphinx_doc_src/tutorial.rst index 809164dbd..e985c8c2d 100644 --- a/sphinx_doc_src/tutorial.rst +++ b/sphinx_doc_src/tutorial.rst @@ -445,7 +445,7 @@ Use ``if``, ``else if``, and ``else`` to conditionally execute code, based on th end -To compare strings or numbers or check file properties (whether a file exists or is writeable and such), use `test `__, like +To compare strings or numbers or check file properties (whether a file exists or is writeable and such), use :ref:`test `, like @@ -650,7 +650,7 @@ This is the preferred way to define your prompt as well:: end -See the documentation for `funced `__ and `funcsave `__ for ways to create these files automatically. +See the documentation for :ref:`funced ` and :ref:`funcsave ` for ways to create these files automatically. Universal Variables ------------------- From 86d457422282f0490d530b9080ce8bf17d622fdf Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 31 Mar 2019 11:24:04 +0200 Subject: [PATCH 0214/1732] docs: Use more command labels --- sphinx_doc_src/cmds/bind.rst | 2 +- sphinx_doc_src/cmds/continue.rst | 2 +- sphinx_doc_src/cmds/dirs.rst | 2 +- sphinx_doc_src/cmds/if.rst | 2 +- sphinx_doc_src/cmds/or.rst | 4 ++-- sphinx_doc_src/cmds/popd.rst | 2 +- sphinx_doc_src/cmds/pushd.rst | 2 +- sphinx_doc_src/cmds/return.rst | 2 +- sphinx_doc_src/cmds/while.rst | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sphinx_doc_src/cmds/bind.rst b/sphinx_doc_src/cmds/bind.rst index e6a7b0656..8347040c6 100644 --- a/sphinx_doc_src/cmds/bind.rst +++ b/sphinx_doc_src/cmds/bind.rst @@ -26,7 +26,7 @@ Description SEQUENCE is the character sequence to bind to. These should be written as `fish escape sequences `__. For example, because pressing the Alt key and another character sends that character prefixed with an escape character, Alt-based key bindings can be written using the ``\e`` escape. For example, :kbd:`Alt+w` can be written as ``\ew``. The control character can be written in much the same way using the ``\c`` escape, for example :kbd:`Control+X` (^X) can be written as ``\cx``. Note that Alt-based key bindings are case sensitive and Control-based key bindings are not. This is a constraint of text-based terminals, not ``fish``. -The default key binding can be set by specifying a ``SEQUENCE`` of the empty string (that is, ``''`` ). It will be used whenever no other binding matches. For most key bindings, it makes sense to use the ``self-insert`` function (i.e. ``````bind '' self-insert``````) as the default keybinding. This will insert any keystrokes not specifically bound to into the editor. Non- printable characters are ignored by the editor, so this will not result in control sequences being printable. +The default key binding can be set by specifying a ``SEQUENCE`` of the empty string (that is, ``''`` ). It will be used whenever no other binding matches. For most key bindings, it makes sense to use the ``self-insert`` function (i.e. ``bind '' self-insert``) as the default keybinding. This will insert any keystrokes not specifically bound to into the editor. Non- printable characters are ignored by the editor, so this will not result in control sequences being printable. If the ``-k`` switch is used, the name of the key (such as 'down', 'up' or 'backspace') is used instead of a sequence. The names used are the same as the corresponding curses variables, but without the 'key\_' prefix. (See ``terminfo(5)`` for more information, or use ``bind --key-names`` for a list of all available named keys.) If used in conjunction with the ``-s`` switch, ``bind`` will silently ignore bindings to named keys that are not found in termcap for the current ``$TERMINAL``, otherwise a warning is emitted. diff --git a/sphinx_doc_src/cmds/continue.rst b/sphinx_doc_src/cmds/continue.rst index d31c9e545..bef361bbc 100644 --- a/sphinx_doc_src/cmds/continue.rst +++ b/sphinx_doc_src/cmds/continue.rst @@ -12,7 +12,7 @@ LOOP_CONSTRUCT; [COMMANDS...;] continue; [COMMANDS...;] end Description ----------- -``continue`` skips the remainder of the current iteration of the current inner loop, such as a for loop or a while loop. It is usually added inside of a conditional block such as an if statement or a switch statement. +``continue`` skips the remainder of the current iteration of the current inner loop, such as a :ref:`for ` loop or a :ref:`while ` loop. It is usually added inside of a conditional block such as an :ref:`if ` statement or a :ref:`switch ` statement. Example ------- diff --git a/sphinx_doc_src/cmds/dirs.rst b/sphinx_doc_src/cmds/dirs.rst index f5f9440dc..286f2f679 100644 --- a/sphinx_doc_src/cmds/dirs.rst +++ b/sphinx_doc_src/cmds/dirs.rst @@ -13,7 +13,7 @@ dirs -c Description ----------- -``dirs`` prints the current directory stack, as created by the ``pushd`` command. +``dirs`` prints the current directory stack, as created by the :ref:`pushd ` command. With "-c", it clears the directory stack instead. diff --git a/sphinx_doc_src/cmds/if.rst b/sphinx_doc_src/cmds/if.rst index 7e5c0fa4c..cb44727fd 100644 --- a/sphinx_doc_src/cmds/if.rst +++ b/sphinx_doc_src/cmds/if.rst @@ -17,7 +17,7 @@ Description ``if`` will execute the command ``CONDITION``. If the condition's exit status is 0, the commands ``COMMANDS_TRUE`` will execute. If the exit status is not 0 and ``else`` is given, ``COMMANDS_FALSE`` will be executed. -You can use ``and`` or ``or`` in the condition. See the second example below. +You can use :ref:`and ` or :ref:`or ` in the condition. See the second example below. The exit status of the last foreground command to exit can always be accessed using the $status variable. diff --git a/sphinx_doc_src/cmds/or.rst b/sphinx_doc_src/cmds/or.rst index 9d5436139..f7037dfd0 100644 --- a/sphinx_doc_src/cmds/or.rst +++ b/sphinx_doc_src/cmds/or.rst @@ -14,8 +14,8 @@ Description ``or`` is used to execute a command if the previous command was not successful (returned a status of something other than 0). -``or`` statements may be used as part of the condition in an ``and`` or ``while`` block. See the documentation -for ``if`` and ``while`` for examples. +``or`` statements may be used as part of the condition in an :ref:`and ` or :ref:`while ` block. See the documentation +for :ref:`if ` and :ref:`while ` for examples. ``or`` does not change the current exit status itself, but the command it runs most likely will. The exit status of the last foreground command to exit can always be accessed using the $status variable. diff --git a/sphinx_doc_src/cmds/popd.rst b/sphinx_doc_src/cmds/popd.rst index 772dbb690..476ed8718 100644 --- a/sphinx_doc_src/cmds/popd.rst +++ b/sphinx_doc_src/cmds/popd.rst @@ -12,7 +12,7 @@ popd Description ----------- -``popd`` removes the top directory from the directory stack and changes the working directory to the new top directory. Use ``pushd`` to add directories to the stack. +``popd`` removes the top directory from the directory stack and changes the working directory to the new top directory. Use :ref:`pushd ` to add directories to the stack. You may be interested in the ``cdh`` command which provides a more intuitive way to navigate to recently visited directories. diff --git a/sphinx_doc_src/cmds/pushd.rst b/sphinx_doc_src/cmds/pushd.rst index 82cc1a0bc..713bee2e5 100644 --- a/sphinx_doc_src/cmds/pushd.rst +++ b/sphinx_doc_src/cmds/pushd.rst @@ -12,7 +12,7 @@ pushd [DIRECTORY] Description ----------- -The ``pushd`` function adds ``DIRECTORY`` to the top of the directory stack and makes it the current working directory. ``popd`` will pop it off and return to the original directory. +The ``pushd`` function adds ``DIRECTORY`` to the top of the directory stack and makes it the current working directory. :ref:`popd ` will pop it off and return to the original directory. Without arguments, it exchanges the top two directories in the stack. diff --git a/sphinx_doc_src/cmds/return.rst b/sphinx_doc_src/cmds/return.rst index 3ad6cc315..86b1202de 100644 --- a/sphinx_doc_src/cmds/return.rst +++ b/sphinx_doc_src/cmds/return.rst @@ -14,7 +14,7 @@ Description ``return`` halts a currently running function. The exit status is set to ``STATUS`` if it is given. -It is usually added inside of a conditional block such as an if statement or a switch statement to conditionally stop the executing function and return to the caller, but it can also be used to specify the exit status of a function. +It is usually added inside of a conditional block such as an :ref:`if ` statement or a :ref:`switch ` statement to conditionally stop the executing function and return to the caller, but it can also be used to specify the exit status of a function. Example diff --git a/sphinx_doc_src/cmds/while.rst b/sphinx_doc_src/cmds/while.rst index 0bc41f9d8..78d3c77d5 100644 --- a/sphinx_doc_src/cmds/while.rst +++ b/sphinx_doc_src/cmds/while.rst @@ -16,7 +16,7 @@ Description The exit status of the while loop is the exit status of the last iteration of the ``COMMANDS`` executed, or 0 if none were executed. (This matches other shells and is POSIX-compatible.) -You can use ``and`` or ``or`` for complex conditions. Even more complex control can be achieved with ``while true`` containing a break. +You can use :ref:`and ` or :ref:`or ` for complex conditions. Even more complex control can be achieved with ``while true`` containing a :ref:`break `. Example ------- From bda3fb774034c88c01544e47d8c83fa14ef627d5 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 31 Mar 2019 11:25:07 +0200 Subject: [PATCH 0215/1732] docs: Fix a few wrong verbatim blocks Wrong number of backticks. [ci skip] --- sphinx_doc_src/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index 96e5b4424..c7dfa73c9 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -629,7 +629,7 @@ Useful functions for writing completions ``fish`` ships with several functions that are very useful when writing command specific completions. Most of these functions name begins with the string '``__fish_``'. Such functions are internal to ``fish`` and their name and interface may change in future fish versions. Still, some of them may be very useful when writing completions. A few of these functions are described here. Be aware that they may be removed or changed in future versions of fish. -Functions beginning with the string ``__fish_print_`` print a newline separated list of strings. For example, ``__fish_print_filesystems` prints a list of all known file systems. Functions beginning with ``__fish_complete_``` print out a newline separated list of completions with descriptions. The description is separated from the completion by a tab character. +Functions beginning with the string ``__fish_print_`` print a newline separated list of strings. For example, ``__fish_print_filesystems`` prints a list of all known file systems. Functions beginning with ``__fish_complete_`` print out a newline separated list of completions with descriptions. The description is separated from the completion by a tab character. - ``__fish_complete_directories STRING DESCRIPTION`` performs path completion on STRING, allowing only directories, and giving them the description DESCRIPTION. @@ -645,7 +645,7 @@ Functions beginning with the string ``__fish_print_`` print a newline separated - ``__fish_print_filesystems`` prints a list of all known file systems. Currently, this is a static list, and not dependent on what file systems the host operating system actually understands. -- ``__fish_print_hostnames` prints a list of all known hostnames. This functions searches the fstab for nfs servers, ssh for known hosts and checks the ``/etc/hosts``` file. +- ``__fish_print_hostnames`` prints a list of all known hostnames. This functions searches the fstab for nfs servers, ssh for known hosts and checks the ``/etc/hosts`` file. - ``__fish_print_interfaces`` prints a list of all known network interfaces. From e2cf10dd4fb2725f4d86f06ebd0e3962151bb5c0 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 31 Mar 2019 11:28:13 +0200 Subject: [PATCH 0216/1732] docs: More command labels [ci skip] --- sphinx_doc_src/cmds/cdh.rst | 2 +- sphinx_doc_src/cmds/fish.rst | 2 +- sphinx_doc_src/cmds/nextd.rst | 2 +- sphinx_doc_src/cmds/popd.rst | 2 +- sphinx_doc_src/cmds/prevd.rst | 2 +- sphinx_doc_src/cmds/pushd.rst | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sphinx_doc_src/cmds/cdh.rst b/sphinx_doc_src/cmds/cdh.rst index 90ad1df5a..c1390a662 100644 --- a/sphinx_doc_src/cmds/cdh.rst +++ b/sphinx_doc_src/cmds/cdh.rst @@ -20,4 +20,4 @@ Note that the ``cd`` command limits directory history to the 25 most recently vi See Also -------- -See also the ``prevd`` and ``pushd`` commands which also work with the recent ``cd`` history and are provided for compatibility with other shells. +See also the :ref:`prevd ` and :ref:`pushd ` commands which also work with the recent ``cd`` history and are provided for compatibility with other shells. diff --git a/sphinx_doc_src/cmds/fish.rst b/sphinx_doc_src/cmds/fish.rst index 572ed360f..35cd9599b 100644 --- a/sphinx_doc_src/cmds/fish.rst +++ b/sphinx_doc_src/cmds/fish.rst @@ -12,7 +12,7 @@ fish [OPTIONS] [-c command] [FILE [ARGUMENTS...]] Description ----------- -``fish`` is a command-line shell written mainly with interactive use in mind. The full manual is available in HTML by using the help command from inside fish. +``fish`` is a command-line shell written mainly with interactive use in mind. The full manual is available in HTML by using the :ref:`help ` command from inside fish. The following options are available: diff --git a/sphinx_doc_src/cmds/nextd.rst b/sphinx_doc_src/cmds/nextd.rst index 4bb862b5b..05173e846 100644 --- a/sphinx_doc_src/cmds/nextd.rst +++ b/sphinx_doc_src/cmds/nextd.rst @@ -18,7 +18,7 @@ If the ``-l`` or ``--list`` flag is specified, the current directory history is Note that the ``cd`` command limits directory history to the 25 most recently visited directories. The history is stored in the ``$dirprev`` and ``$dirnext`` variables which this command manipulates. -You may be interested in the ``cdh`` command which provides a more intuitive way to navigate to recently visited directories. +You may be interested in the :ref:`cdh ` command which provides a more intuitive way to navigate to recently visited directories. Example ------- diff --git a/sphinx_doc_src/cmds/popd.rst b/sphinx_doc_src/cmds/popd.rst index 476ed8718..96cd28eb5 100644 --- a/sphinx_doc_src/cmds/popd.rst +++ b/sphinx_doc_src/cmds/popd.rst @@ -14,7 +14,7 @@ Description ``popd`` removes the top directory from the directory stack and changes the working directory to the new top directory. Use :ref:`pushd ` to add directories to the stack. -You may be interested in the ``cdh`` command which provides a more intuitive way to navigate to recently visited directories. +You may be interested in the :ref:`cdh ` command which provides a more intuitive way to navigate to recently visited directories. Example ------- diff --git a/sphinx_doc_src/cmds/prevd.rst b/sphinx_doc_src/cmds/prevd.rst index b96338c51..e5b444220 100644 --- a/sphinx_doc_src/cmds/prevd.rst +++ b/sphinx_doc_src/cmds/prevd.rst @@ -18,7 +18,7 @@ If the ``-l`` or ``--list`` flag is specified, the current history is also displ Note that the ``cd`` command limits directory history to the 25 most recently visited directories. The history is stored in the ``$dirprev`` and ``$dirnext`` variables which this command manipulates. -You may be interested in the ``cdh`` command which provides a more intuitive way to navigate to recently visited directories. +You may be interested in the :ref:`cdh ` command which provides a more intuitive way to navigate to recently visited directories. Example ------- diff --git a/sphinx_doc_src/cmds/pushd.rst b/sphinx_doc_src/cmds/pushd.rst index 713bee2e5..a4e97544d 100644 --- a/sphinx_doc_src/cmds/pushd.rst +++ b/sphinx_doc_src/cmds/pushd.rst @@ -22,7 +22,7 @@ Without arguments, it exchanges the top two directories in the stack. See also ``dirs`` and ``dirs -c``. -You may be interested in the ``cdh`` command which provides a more intuitive way to navigate to recently visited directories. +You may be interested in the :ref:`cdh ` command which provides a more intuitive way to navigate to recently visited directories. Example ------- From 127c0e9764ec7ea2857b3c9a400985d443488b4e Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 31 Mar 2019 11:32:40 +0200 Subject: [PATCH 0217/1732] docs: Fix remaining references Fixes #5775. --- sphinx_doc_src/cmds/fish.rst | 2 +- sphinx_doc_src/cmds/funcsave.rst | 2 +- sphinx_doc_src/cmds/if.rst | 2 +- sphinx_doc_src/cmds/or.rst | 2 +- sphinx_doc_src/cmds/set.rst | 2 +- sphinx_doc_src/cmds/test.rst | 2 +- sphinx_doc_src/cmds/trap.rst | 2 +- sphinx_doc_src/index.rst | 1 + sphinx_doc_src/tutorial.rst | 2 +- 9 files changed, 9 insertions(+), 8 deletions(-) diff --git a/sphinx_doc_src/cmds/fish.rst b/sphinx_doc_src/cmds/fish.rst index 35cd9599b..cb92df6ec 100644 --- a/sphinx_doc_src/cmds/fish.rst +++ b/sphinx_doc_src/cmds/fish.rst @@ -12,7 +12,7 @@ fish [OPTIONS] [-c command] [FILE [ARGUMENTS...]] Description ----------- -``fish`` is a command-line shell written mainly with interactive use in mind. The full manual is available in HTML by using the :ref:`help ` command from inside fish. +``fish`` is a command-line shell written mainly with interactive use in mind. The :ref:`full manual ` is available in HTML by using the :ref:`help ` command from inside fish. The following options are available: diff --git a/sphinx_doc_src/cmds/funcsave.rst b/sphinx_doc_src/cmds/funcsave.rst index a93f23814..34f9d63a8 100644 --- a/sphinx_doc_src/cmds/funcsave.rst +++ b/sphinx_doc_src/cmds/funcsave.rst @@ -14,4 +14,4 @@ Description ``funcsave`` saves the current definition of a function to a file in the fish configuration directory. This function will be automatically loaded by current and future fish sessions. This can be useful if you have interactively created a new function and wish to save it for later use. -Note that because fish loads functions on-demand, saved functions will not function as event handlers until they are run or sourced otherwise. To activate an event handler for every new shell, add the function to your shell initialization file instead of using ``funcsave``. +Note that because fish loads functions on-demand, saved functions will not function as :ref:`event handlers ` until they are run or sourced otherwise. To activate an event handler for every new shell, add the function to your :ref:`shell initialization file ` instead of using ``funcsave``. diff --git a/sphinx_doc_src/cmds/if.rst b/sphinx_doc_src/cmds/if.rst index cb44727fd..617f94f7d 100644 --- a/sphinx_doc_src/cmds/if.rst +++ b/sphinx_doc_src/cmds/if.rst @@ -19,7 +19,7 @@ Description You can use :ref:`and ` or :ref:`or ` in the condition. See the second example below. -The exit status of the last foreground command to exit can always be accessed using the $status variable. +The exit status of the last foreground command to exit can always be accessed using the :ref:`$status ` variable. Example ------- diff --git a/sphinx_doc_src/cmds/or.rst b/sphinx_doc_src/cmds/or.rst index f7037dfd0..1cbdb8178 100644 --- a/sphinx_doc_src/cmds/or.rst +++ b/sphinx_doc_src/cmds/or.rst @@ -17,7 +17,7 @@ Description ``or`` statements may be used as part of the condition in an :ref:`and ` or :ref:`while ` block. See the documentation for :ref:`if ` and :ref:`while ` for examples. -``or`` does not change the current exit status itself, but the command it runs most likely will. The exit status of the last foreground command to exit can always be accessed using the $status variable. +``or`` does not change the current exit status itself, but the command it runs most likely will. The exit status of the last foreground command to exit can always be accessed using the :ref:`$status ` variable. Example ------- diff --git a/sphinx_doc_src/cmds/set.rst b/sphinx_doc_src/cmds/set.rst index 4e4c2845c..df051318c 100644 --- a/sphinx_doc_src/cmds/set.rst +++ b/sphinx_doc_src/cmds/set.rst @@ -18,7 +18,7 @@ set ( -S | --show ) [SCOPE_OPTIONS] [VARIABLE_NAME]... Description ----------- -``set`` manipulates shell variables. +``set`` manipulates :ref:`shell variables `. If set is called with no arguments, the names and values of all shell variables are printed in sorted order. If some of the scope or export flags have been given, only the variables matching the specified scope are printed. diff --git a/sphinx_doc_src/cmds/test.rst b/sphinx_doc_src/cmds/test.rst index 0c8914398..cbdd6e65d 100644 --- a/sphinx_doc_src/cmds/test.rst +++ b/sphinx_doc_src/cmds/test.rst @@ -189,7 +189,7 @@ which is logically equivalent to the following: Standards --------- -``test`` implements a subset of the IEEE Std 1003.1-2008 (POSIX.1) standard. The following exceptions apply: +``test`` implements a subset of the `IEEE Std 1003.1-2008 (POSIX.1) standard `__. The following exceptions apply: - The ``<`` and ``>`` operators for comparing strings are not implemented. diff --git a/sphinx_doc_src/cmds/trap.rst b/sphinx_doc_src/cmds/trap.rst index dbe8ce890..770135cc5 100644 --- a/sphinx_doc_src/cmds/trap.rst +++ b/sphinx_doc_src/cmds/trap.rst @@ -12,7 +12,7 @@ trap [OPTIONS] [[ARG] REASON ... ] Description ----------- -``trap`` is a wrapper around the fish event delivery framework. It exists for backwards compatibility with POSIX shells. For other uses, it is recommended to define an event handler. +``trap`` is a wrapper around the fish event delivery framework. It exists for backwards compatibility with POSIX shells. For other uses, it is recommended to define an :ref:`event handler `. The following parameters are available: diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index c7dfa73c9..49aca598f 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -1,4 +1,5 @@ .. highlight:: fish +.. _intro: Introduction ============ diff --git a/sphinx_doc_src/tutorial.rst b/sphinx_doc_src/tutorial.rst index e985c8c2d..b98ef5061 100644 --- a/sphinx_doc_src/tutorial.rst +++ b/sphinx_doc_src/tutorial.rst @@ -696,4 +696,4 @@ with ``/bin/bash``, ``/bin/tcsh`` or ``/bin/zsh`` as appropriate in the steps ab Ready for more? --------------- -If you want to learn more about fish, there is lots of detailed documentation, an official mailing list, the IRC channel \#fish on ``irc.oftc.net``, and the github page. +If you want to learn more about fish, there is :ref:`lots of detailed documentation `, an `official mailing list `__, the IRC channel \#fish on ``irc.oftc.net``, and the `github page `__. From ac61d3f34dd9b454f65f1b8b4e944348ca9ec6f2 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 31 Mar 2019 11:46:26 +0200 Subject: [PATCH 0218/1732] docs: More references Including two more href. --- sphinx_doc_src/cmds/complete.rst | 3 +-- sphinx_doc_src/faq.rst | 5 ++--- sphinx_doc_src/index.rst | 6 +++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/sphinx_doc_src/cmds/complete.rst b/sphinx_doc_src/cmds/complete.rst index 0f7bdeaa4..fe6330a7f 100644 --- a/sphinx_doc_src/cmds/complete.rst +++ b/sphinx_doc_src/cmds/complete.rst @@ -27,8 +27,7 @@ Synopsis Description ----------- -For an introduction to specifying completions, see Writing your own completions in +For an introduction to specifying completions, see :ref:`Writing your own completions ` in the fish manual. - ``COMMAND`` is the name of the command for which to add a completion. diff --git a/sphinx_doc_src/faq.rst b/sphinx_doc_src/faq.rst index 423e630e7..7dd133fe3 100644 --- a/sphinx_doc_src/faq.rst +++ b/sphinx_doc_src/faq.rst @@ -146,15 +146,14 @@ A global variable of the same name already exists. Environment variables such as ``EDITOR`` or ``TZ`` can be set universally using ``set -Ux``. However, if there is an environment variable already set before fish starts (such as by login scripts or system -administrators), it is imported into fish as a global variable. The variable scopes are searched from the "inside out", which +administrators), it is imported into fish as a global variable. The :ref:`variable scopes ` are searched from the "inside out", which means that local variables are checked first, followed by global variables, and finally universal variables. This means that the global value takes precedence over the universal value. To avoid this problem, consider changing the setting which fish inherits. If this is not possible, -add a statement to your `user initialization file `__ (usually +add a statement to your :ref:`user initialization file ` (usually ``~/.config/fish/config.fish``):: set -gx EDITOR vim diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index 49aca598f..4df9dd268 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -1055,7 +1055,7 @@ To see universal variables in action, start two fish sessions side by side, and `Universal variables <#variables-universal>`_ are stored in the file ``.config/fish/fish_variables``. Do not edit this file directly, as your edits may be overwritten. Edit the variables through fish scripts or by using fish interactively instead. -Do not append to universal variables in `config.fish <#initialization>`_, because these variables will then get longer with each new shell instance. Instead, simply set them once at the command line. +Do not append to universal variables in :ref:`config.fish `, because these variables will then get longer with each new shell instance. Instead, simply set them once at the command line. .. _variables-functions: @@ -1779,9 +1779,9 @@ To specify a signal handler for the WINCH signal, write:: echo Got WINCH signal! end -Please note that event handlers only become active when a function is loaded, which means you might need to otherwise `source `_ or execute a function instead of relying on `autoloading <#syntax-function-autoloading>`_. One approach is to put it into your `initialization file <#initialization>`_. +Please note that event handlers only become active when a function is loaded, which means you might need to otherwise :ref:`source ` or execute a function instead of relying on :ref:`autoloading `. One approach is to put it into your :ref:`initialization file `. -For more information on how to define new event handlers, see the documentation for the `function `_ command. +For more information on how to define new event handlers, see the documentation for the :ref:`function ` command. .. _debugging: From eb3bbb13607d4b17153153f7b9723cebd387a789 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 31 Mar 2019 11:50:28 +0200 Subject: [PATCH 0219/1732] docs: Fix example link --- sphinx_doc_src/tutorial.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sphinx_doc_src/tutorial.rst b/sphinx_doc_src/tutorial.rst index b98ef5061..fa40ac1ec 100644 --- a/sphinx_doc_src/tutorial.rst +++ b/sphinx_doc_src/tutorial.rst @@ -597,7 +597,7 @@ To remove /usr/local/bin from ``$PATH``, you can write:: >_ set PATH (string match -v /usr/local/bin $PATH) -You can do so directly in ``config.fish``, like you might do in other shells with ``.profile``. See [this example](#path_example). +You can do so directly in ``config.fish``, like you might do in other shells with ``.profile``. See :ref:`this example `. A faster way is to modify the ``$fish_user_paths`` [universal variable](#tut_universal), which is automatically prepended to ``$PATH``. For example, to permanently add ``/usr/local/bin`` to your ``$PATH``, you could write:: @@ -613,8 +613,7 @@ Startup (Where's .bashrc?) It is possible to directly create functions and variables in ``config.fish`` file, using the commands shown above. For example: - - +.. _path_example: :: From 6c234a7385ea338d4fbccea4204e2153c05b26aa Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 31 Mar 2019 11:56:12 +0200 Subject: [PATCH 0220/1732] docs: Remove a table This was html, and I don't think it helped all that much, so let's remove it instead of translating to rst. [ci skip] --- sphinx_doc_src/index.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index 4df9dd268..f6b72f568 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -101,11 +101,6 @@ Arguments → Program → Return Values - the arguments become options or switches paired with data: the switches influence the behaviour of the command - the return value shrinks to an **exit code**: this exit code is 0 when the command executes normally and between 1 and 255 otherwise. - -
Input Stream ⇒|Shell Command|⇒ Output Stream -
switch and data as arguments →→ exit code -
- This leads to another way of programming and especially of combining commands: There are two ways to combine shell commands: From 95ab71c456510f4195753c24cc20b5a6cd11e637 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 31 Mar 2019 12:00:19 +0200 Subject: [PATCH 0221/1732] docs: Another bit of dehtml-izing [ci skip] --- sphinx_doc_src/cmds/type.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_doc_src/cmds/type.rst b/sphinx_doc_src/cmds/type.rst index 31e5ccf70..18ddcefe0 100644 --- a/sphinx_doc_src/cmds/type.rst +++ b/sphinx_doc_src/cmds/type.rst @@ -22,7 +22,7 @@ The following options are available: - ``-t`` or ``--type`` prints ``function``, ``builtin``, or ``file`` if ``NAME`` is a shell function, builtin, or disk file, respectively. -- ``-p`` or ``--path`` prints the path to ``NAME`` if ``NAME`` resolves to an executable file in $PATH, the path to the script containing the definition of the function ``NAME`` if ``NAME`` resolves to a function loaded from a file on disk (i.e. not interactively defined at the prompt), or nothing otherwise. +- ``-p`` or ``--path`` prints the path to ``NAME`` if ``NAME`` resolves to an executable file in :ref:`$PATH `, the path to the script containing the definition of the function ``NAME`` if ``NAME`` resolves to a function loaded from a file on disk (i.e. not interactively defined at the prompt), or nothing otherwise. - ``-P`` or ``--force-path`` returns the path to the executable file ``NAME``, presuming ``NAME`` is found in ``$PATH``, or nothing otherwise. ``--force-path`` explicitly resolves only the path to executable files in ``$PATH``, regardless of whether ``$NAME`` is shadowed by a function or builtin with the same name. From aafd706a34e3d2756aa887d114c37e60de24ddee Mon Sep 17 00:00:00 2001 From: Lily Ballard Date: Sat, 30 Mar 2019 13:48:17 -0700 Subject: [PATCH 0222/1732] Replace Doxygen reference in README with Sphinx Also update a comment in the `make_tarball.sh` script. --- README.md | 2 +- build_tools/make_tarball.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 28c60704c..5ae048545 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ Compiling fish requires: * PCRE2 (headers and libraries) - a copy is included with fish * gettext (headers and libraries) - optional, for translation support -Doxygen (1.8.7 or later) is also optionally required to build the documentation from a cloned git repository. +Sphinx is also optionally required to build the documentation from a cloned git repository. ### Building from source (all platforms) - Makefile generator diff --git a/build_tools/make_tarball.sh b/build_tools/make_tarball.sh index 89789a348..d0578e006 100755 --- a/build_tools/make_tarball.sh +++ b/build_tools/make_tarball.sh @@ -2,7 +2,7 @@ # Script to generate a tarball # We use git to output a tree. But we also want to build the user documentation -# and put that in the tarball, so that nobody needs to have doxygen installed +# and put that in the tarball, so that nobody needs to have sphinx installed # to build it. # Outputs to $FISH_ARTEFACT_PATH or ~/fish_built by default From 3c537bfa656bbb119028f14b7ab770d34ca8fbaa Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Sun, 31 Mar 2019 13:20:49 -0500 Subject: [PATCH 0223/1732] Optimize get_deferred_process() traversal --- src/exec.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/exec.cpp b/src/exec.cpp index ddf612d9d..7fc37af5e 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -993,21 +993,20 @@ static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr< // This should show the output as it comes, not buffer until the end. // Any such process (only one per job) will be called the "deferred" process. static process_t *get_deferred_process(const shared_ptr &j) { - process_t *last_internal = nullptr; - for (const auto &p : j->processes) { + // By enumerating in reverse order, we can avoid walking the entire list + for (auto i = j->processes.rbegin(); i != j->processes.rend(); ++i) { + const auto &p = *i; if (p->type == process_type_t::exec) { // No tail reordering for execs. return nullptr; } else if (p->type != process_type_t::external) { - last_internal = p.get(); + if (p->is_last_in_job) { + return nullptr; + } + return p.get(); } } - if (last_internal && !last_internal->is_last_in_job) { - // This is the last internal process, and it pipes to an external process. - return last_internal; - } else { - return nullptr; - } + return nullptr; } bool exec_job(parser_t &parser, shared_ptr j) { From b5b9406711fde15162a0bc3f52b4d656c2e18aa4 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Sun, 31 Mar 2019 18:09:59 -0500 Subject: [PATCH 0224/1732] Use explicit atomic/CAS to prevent race conditions They are probably equivalent on x86/64 being single-byte reads/writes, but it never hurts to be safe. --- src/proc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/proc.cpp b/src/proc.cpp index 24b266920..4d224b8f9 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -463,7 +463,7 @@ static bool process_clean_after_marking(bool allow_interactive) { // This function may fire an event handler, we do not want to call ourselves recursively (to // avoid infinite recursion). - static bool locked = false; + static std::atomic locked { false }; if (locked) { return false; } From eb2d829bc5bb3ecd2004d3e6308a3af9d32b4222 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Sun, 31 Mar 2019 18:17:33 -0500 Subject: [PATCH 0225/1732] Use explicit lock.exchange() There's really no point in using std::atomic if we're not going to actually guarantee the entire read & write process is atomic. --- src/proc.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/proc.cpp b/src/proc.cpp index 4d224b8f9..169116abd 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -464,10 +464,9 @@ static bool process_clean_after_marking(bool allow_interactive) { // This function may fire an event handler, we do not want to call ourselves recursively (to // avoid infinite recursion). static std::atomic locked { false }; - if (locked) { + if (locked.exchange(true, std::memory_order::memory_order_relaxed)) { return false; } - locked = true; // This may be invoked in an exit handler, after the TERM has been torn down // Don't try to print in that case (#3222) From 469a8880aa20ea6c13ffa96f36f2b7b664892c7d Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sun, 31 Mar 2019 21:38:23 -0700 Subject: [PATCH 0226/1732] correct 'bind' completions --new-mode isn't even an option `bind` takes, and it -m for -M. --- share/completions/bind.fish | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/share/completions/bind.fish b/share/completions/bind.fish index c6153cf8a..05375a1d8 100644 --- a/share/completions/bind.fish +++ b/share/completions/bind.fish @@ -43,14 +43,16 @@ function __fish_bind_test2 end +complete -c bind -f complete -c bind -s a -l all -d 'Show unavailable key bindings/erase all bindings' complete -c bind -s e -l erase -d 'Erase mode' complete -c bind -s f -l function-names -d 'Print names of available functions' complete -c bind -s h -l help -d "Display help and exit" complete -c bind -s k -l key -d 'Specify key name, not sequence' complete -c bind -s K -l key-names -d 'Print names of available keys' -complete -c bind -s m -l mode -d 'Add to named bind mode' -complete -c bind -s M -l new-mode -d 'Change current bind mode to named mode' +complete -c bind -s M -l mode -d 'Specify the bind mode that the bind is used in' +complete -c bind -s m -l sets-mode -d 'Change current mode after bind is executed' +complete -c bind -s L -l list-modes -d 'Display a list of defined bind modes' complete -c bind -n __fish_bind_test1 -a '(bind --key-names)' -d 'Key name' -x complete -c bind -n __fish_bind_test2 -a '(bind --function-names)' -d 'Function name' -x From 0d729126419e566c7be004c38c53896081ae27c9 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 1 Apr 2019 15:59:15 +0200 Subject: [PATCH 0227/1732] Expand abbr explicitly (#5762) * Add "expand-abbr" bind function This can be used to explictly allow expanding abbreviations. * Make expanding abbr explicit NOTE: This accepts them for space only, we currently also do it for \n and \r. * Remove now dead code We no longer trigger an abbr implicitly, so we can remove the code that does it. * Fix comment [ci skip] --- .../functions/fish_default_key_bindings.fish | 3 + share/functions/fish_vi_key_bindings.fish | 3 + sphinx_doc_src/cmds/bind.rst | 2 + src/input.cpp | 1 + src/input_common.h | 1 + src/reader.cpp | 55 +++++++------------ 6 files changed, 31 insertions(+), 34 deletions(-) diff --git a/share/functions/fish_default_key_bindings.fish b/share/functions/fish_default_key_bindings.fish index f3ac78349..5bf00b216 100644 --- a/share/functions/fish_default_key_bindings.fish +++ b/share/functions/fish_default_key_bindings.fish @@ -31,6 +31,9 @@ function fish_default_key_bindings -d "Default (Emacs-like) key bindings for fis bind --preset $argv "" self-insert or exit # protect against invalid $argv + # Space expands abbrs _and_ inserts itself. + bind --preset $argv " " 'commandline -i " "; commandline -f expand-abbr' + bind --preset $argv \n execute bind --preset $argv \r execute diff --git a/share/functions/fish_vi_key_bindings.fish b/share/functions/fish_vi_key_bindings.fish index 5d39be4c9..40ed9432f 100644 --- a/share/functions/fish_vi_key_bindings.fish +++ b/share/functions/fish_vi_key_bindings.fish @@ -54,6 +54,9 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset -M insert \n execute bind -s --preset -M insert "" self-insert + # Space expands abbrs _and_ inserts itself. + bind -s --preset -M insert " " 'commandline -i " "; commandline -f expand-abbr' + # Add way to kill current command line while in insert mode. bind -s --preset -M insert \cc __fish_cancel_commandline diff --git a/sphinx_doc_src/cmds/bind.rst b/sphinx_doc_src/cmds/bind.rst index 8347040c6..eca0e4425 100644 --- a/sphinx_doc_src/cmds/bind.rst +++ b/sphinx_doc_src/cmds/bind.rst @@ -112,6 +112,8 @@ The following special input functions are available: - ``end-selection``, end selecting text +- ``expand-abbr`` expands any abbreviation currently under the cursor + - ``forward-bigword``, move one whitespace-delimited word to the right - ``forward-char``, move one character to the right diff --git a/src/input.cpp b/src/input.cpp index 256e0f62c..ba55f709d 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -129,6 +129,7 @@ static const input_function_metadata_t input_function_metadata[] = { {readline_cmd_t::repeat_jump, L"repeat-jump"}, {readline_cmd_t::reverse_repeat_jump, L"repeat-jump-reverse"}, {readline_cmd_t::func_and, L"and"}, + {readline_cmd_t::expand_abbr, L"expand-abbr"}, {readline_cmd_t::cancel, L"cancel"}}; static_assert(sizeof(input_function_metadata) / sizeof(input_function_metadata[0]) == diff --git a/src/input_common.h b/src/input_common.h index 7489f0e96..3b2ffb6e1 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -65,6 +65,7 @@ enum class readline_cmd_t { forward_jump_till, backward_jump_till, func_and, + expand_abbr, cancel, repeat_jump, reverse_repeat_jump, diff --git a/src/reader.cpp b/src/reader.cpp index 87d31f0ed..53a4a2d33 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -430,13 +430,12 @@ class reader_data_t : public std::enable_shared_from_this { void update_buff_pos(editable_line_t *el, size_t buff_pos); void repaint(); void kill(editable_line_t *el, size_t begin_idx, size_t length, int mode, int newv); - bool insert_string(editable_line_t *el, const wcstring &str, - bool allow_expand_abbreviations = false); + bool insert_string(editable_line_t *el, const wcstring &str); /// Insert the character into the command line buffer and print it to the screen using syntax /// highlighting, etc. - bool insert_char(editable_line_t *el, wchar_t c, bool allow_expand_abbreviations = false) { - return insert_string(el, wcstring{c}, allow_expand_abbreviations); + bool insert_char(editable_line_t *el, wchar_t c) { + return insert_string(el, wcstring{c}); } void move_word(editable_line_t *el, bool move_right, bool erase, enum move_word_style_t style, @@ -1134,43 +1133,21 @@ void reader_data_t::remove_backward() { } /// Insert the characters of the string into the command line buffer and print them to the screen -/// using syntax highlighting, etc. Optionally also expand abbreviations, after space characters. +/// using syntax highlighting, etc. /// Returns true if the string changed. -bool reader_data_t::insert_string(editable_line_t *el, const wcstring &str, - bool allow_expand_abbreviations) { +bool reader_data_t::insert_string(editable_line_t *el, const wcstring &str) { size_t len = str.size(); if (len == 0) return false; - // Start inserting. If we are expanding abbreviations, we have to do this after every space (see - // #1434), so look for spaces. We try to do this efficiently (rather than the simpler character - // at a time) to avoid expensive work in command_line_changed(). + // Start inserting. size_t cursor = 0; while (cursor < len) { - // Determine the position of the next expansion-triggering char (possibly none), and the end - // of the range we wish to insert. - const wchar_t *expansion_triggering_chars = L" ;|&^><"; - size_t char_triggering_expansion_pos = - allow_expand_abbreviations ? str.find_first_of(expansion_triggering_chars, cursor) - : wcstring::npos; - bool has_expansion_triggering_char = (char_triggering_expansion_pos != wcstring::npos); - size_t range_end = - (has_expansion_triggering_char ? char_triggering_expansion_pos + 1 : len); - // Insert from the cursor up to but not including the range end. - assert(range_end > cursor); - el->insert_string(str, cursor, range_end - cursor); + el->insert_string(str, cursor, len - cursor); update_buff_pos(el, el->position); command_line_changed(el); - - // If we got an expansion trigger, then the last character we inserted was it (i.e. was a - // space). Expand abbreviations. - if (has_expansion_triggering_char && allow_expand_abbreviations) { - assert(range_end > 0); - assert(std::wcschr(expansion_triggering_chars, str.at(range_end - 1))); - expand_abbreviation_as_necessary(1); - } - cursor = range_end; + cursor = len; } if (el == &command_line) { @@ -2471,7 +2448,7 @@ maybe_t reader_data_t::read_normal_chars(readline_loop_state_t &rl } editable_line_t *el = active_edit_line(); - insert_string(el, arr, true); + insert_string(el, arr); // End paging upon inserting into the normal command line. if (el == &command_line) { @@ -3193,6 +3170,17 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat break; } + case rl::expand_abbr: { + editable_line_t *el = active_edit_line(); + if (expand_abbreviation_as_necessary(1)) { + super_highlight_me_plenty(); + mark_repaint_needed(); + input_function_set_status(true); + } else { + input_function_set_status(false); + } + break; + } // Some commands should have been handled internally by input_readch(). case rl::self_insert: { DIE("self-insert should have been handled by input_readch"); @@ -3317,8 +3305,7 @@ maybe_t reader_data_t::readline(int nchars_or_0) { c != 0x7F) { // Regular character. editable_line_t *el = active_edit_line(); - bool allow_expand_abbreviations = (el == &command_line); - insert_char(active_edit_line(), c, allow_expand_abbreviations); + insert_char(active_edit_line(), c); // End paging upon inserting into the normal command line. if (el == &command_line) { From da1b32f0adb42a52a1ccef157532fd986f6238bb Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 1 Apr 2019 15:59:33 +0200 Subject: [PATCH 0228/1732] Remove option to use system wcwidth (#5777) As it turns out it didn't work much better, and it fell behind in support when it comes to things that wcwidth traditionally can't express like variation selectors and hangul combining characters, but also simply $fish_*_width. I've had to tell a few people now to rebuild with widecharwidth after sending them on a fool's errand to set X variable. So keeping this option is doing our users a disservice. --- CMakeLists.txt | 7 ------- src/fallback.cpp | 11 ----------- 2 files changed, 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b0b518aa5..443a6640b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,13 +127,6 @@ SET_SOURCE_FILES_PROPERTIES(src/fish_version.cpp PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${FBVF}) -OPTION(INTERNAL_WCWIDTH "use fallback wcwidth" ON) -IF(INTERNAL_WCWIDTH) - ADD_DEFINITIONS(-DHAVE_BROKEN_WCWIDTH=1) -ELSE() - ADD_DEFINITIONS(-DHAVE_BROKEN_WCWIDTH=0) -ENDIF() - # Enable thread-safe errno on Solaris (#5611) ADD_DEFINITIONS(-D_REENTRANT) diff --git a/src/fallback.cpp b/src/fallback.cpp index 870f81787..fc9b478a9 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -267,15 +267,6 @@ int fish_get_emoji_width(wchar_t c) { // Big hack to use our versions of wcswidth where we know them to be broken, which is // EVERYWHERE (https://github.com/fish-shell/fish-shell/issues/2199) -#ifndef HAVE_BROKEN_WCWIDTH -#define HAVE_BROKEN_WCWIDTH 1 -#endif - -#if !HAVE_BROKEN_WCWIDTH -int fish_wcwidth(wchar_t wc) { return wcwidth(wc); } -int fish_wcswidth(const wchar_t *str, size_t n) { return wcswidth(str, n); } -#else - #include "widecharwidth/widechar_width.h" int fish_wcwidth(wchar_t wc) { @@ -332,8 +323,6 @@ int fish_wcswidth(const wchar_t *str, size_t n) { return result; } -#endif // HAVE_BROKEN_WCWIDTH - #ifndef HAVE_FLOCK /* $NetBSD: flock.c,v 1.6 2008/04/28 20:24:12 martin Exp $ */ From 8ff866b26b2f42bb8deeb2c2ec2b308c79daff75 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 1 Apr 2019 15:52:21 +0200 Subject: [PATCH 0229/1732] Add repaint-mode bind function If we switch the bind mode, we add a "force-repaint" there just to redraw the mode indicator. That's quite wasteful and annoying, considering that sometimes the prompt can take half a second. So we add a "repaint-mode" function that just reexecutes the mode-prompt and uses the cached values for the others. Fixes #5783. --- share/functions/fish_vi_key_bindings.fish | 76 +++++++++++------------ sphinx_doc_src/cmds/bind.rst | 4 ++ src/input.cpp | 1 + src/input_common.h | 1 + src/reader.cpp | 41 ++++++++---- 5 files changed, 73 insertions(+), 50 deletions(-) diff --git a/share/functions/fish_vi_key_bindings.fish b/share/functions/fish_vi_key_bindings.fish index 40ed9432f..5ff75e4b9 100644 --- a/share/functions/fish_vi_key_bindings.fish +++ b/share/functions/fish_vi_key_bindings.fish @@ -63,7 +63,7 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' # Add a way to switch from insert to normal (command) mode. # Note if we are paging, we want to stay in insert mode # See #2871 - bind -s --preset -M insert \e "if commandline -P; commandline -f cancel; else; set fish_bind_mode default; commandline -f backward-char force-repaint; end" + bind -s --preset -M insert \e "if commandline -P; commandline -f cancel; else; set fish_bind_mode default; commandline -f backward-char repaint-mode; end" # Default (command) mode bind -s --preset :q exit @@ -72,14 +72,14 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset -M default l forward-char bind -s --preset -m insert \n execute bind -s --preset -m insert \r execute - bind -s --preset -m insert i force-repaint - bind -s --preset -m insert I beginning-of-line force-repaint - bind -s --preset -m insert a forward-char force-repaint - bind -s --preset -m insert A end-of-line force-repaint - bind -s --preset -m visual v begin-selection force-repaint + bind -s --preset -m insert i repaint-mode + bind -s --preset -m insert I beginning-of-line repaint-mode + bind -s --preset -m insert a forward-char repaint-mode + bind -s --preset -m insert A end-of-line repaint-mode + bind -s --preset -m visual v begin-selection repaint-mode - #bind -s --preset -m insert o "commandline -a \n" down-line force-repaint - #bind -s --preset -m insert O beginning-of-line "commandline -i \n" up-line force-repaint # doesn't work + #bind -s --preset -m insert o "commandline -a \n" down-line repaint-mode + #bind -s --preset -m insert O beginning-of-line "commandline -i \n" up-line repaint-mode # doesn't work bind -s --preset gg beginning-of-buffer bind -s --preset G end-of-buffer @@ -154,24 +154,24 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset dF begin-selection backward-jump kill-selection end-selection bind -s --preset dT begin-selection backward-jump forward-char kill-selection end-selection - bind -s --preset -m insert s delete-char force-repaint - bind -s --preset -m insert S kill-whole-line force-repaint - bind -s --preset -m insert cc kill-whole-line force-repaint - bind -s --preset -m insert C kill-line force-repaint - bind -s --preset -m insert c\$ kill-line force-repaint - bind -s --preset -m insert c\^ backward-kill-line force-repaint - bind -s --preset -m insert cw kill-word force-repaint - bind -s --preset -m insert cW kill-bigword force-repaint - bind -s --preset -m insert ciw forward-char forward-char backward-word kill-word force-repaint - bind -s --preset -m insert ciW forward-char forward-char backward-bigword kill-bigword force-repaint - bind -s --preset -m insert caw forward-char forward-char backward-word kill-word force-repaint - bind -s --preset -m insert caW forward-char forward-char backward-bigword kill-bigword force-repaint - bind -s --preset -m insert ce kill-word force-repaint - bind -s --preset -m insert cE kill-bigword force-repaint - bind -s --preset -m insert cb backward-kill-word force-repaint - bind -s --preset -m insert cB backward-kill-bigword force-repaint - bind -s --preset -m insert cge backward-kill-word force-repaint - bind -s --preset -m insert cgE backward-kill-bigword force-repaint + bind -s --preset -m insert s delete-char repaint-mode + bind -s --preset -m insert S kill-whole-line repaint-mode + bind -s --preset -m insert cc kill-whole-line repaint-mode + bind -s --preset -m insert C kill-line repaint-mode + bind -s --preset -m insert c\$ kill-line repaint-mode + bind -s --preset -m insert c\^ backward-kill-line repaint-mode + bind -s --preset -m insert cw kill-word repaint-mode + bind -s --preset -m insert cW kill-bigword repaint-mode + bind -s --preset -m insert ciw forward-char forward-char backward-word kill-word repaint-mode + bind -s --preset -m insert ciW forward-char forward-char backward-bigword kill-bigword repaint-mode + bind -s --preset -m insert caw forward-char forward-char backward-word kill-word repaint-mode + bind -s --preset -m insert caW forward-char forward-char backward-bigword kill-bigword repaint-mode + bind -s --preset -m insert ce kill-word repaint-mode + bind -s --preset -m insert cE kill-bigword repaint-mode + bind -s --preset -m insert cb backward-kill-word repaint-mode + bind -s --preset -m insert cB backward-kill-bigword repaint-mode + bind -s --preset -m insert cge backward-kill-word repaint-mode + bind -s --preset -m insert cgE backward-kill-bigword repaint-mode bind -s --preset '~' capitalize-word bind -s --preset gu downcase-word @@ -215,9 +215,9 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' # # Lowercase r, enters replace_one mode # - bind -s --preset -m replace_one r force-repaint - bind -s --preset -M replace_one -m default '' delete-char self-insert backward-char force-repaint - bind -s --preset -M replace_one -m default \e cancel force-repaint + bind -s --preset -m replace_one r repaint-mode + bind -s --preset -M replace_one -m default '' delete-char self-insert backward-char repaint-mode + bind -s --preset -M replace_one -m default \e cancel repaint-mode # # visual mode @@ -236,7 +236,7 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset -M visual W forward-bigword bind -s --preset -M visual e forward-word bind -s --preset -M visual E forward-bigword - bind -s --preset -M visual o swap-selection-start-stop force-repaint + bind -s --preset -M visual o swap-selection-start-stop repaint-mode bind -s --preset -M visual f forward-jump bind -s --preset -M visual t forward-jump-till @@ -250,15 +250,15 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset -M visual $key beginning-of-line end - bind -s --preset -M visual -m insert c kill-selection end-selection force-repaint - bind -s --preset -M visual -m default d kill-selection end-selection force-repaint - bind -s --preset -M visual -m default x kill-selection end-selection force-repaint - bind -s --preset -M visual -m default X kill-whole-line end-selection force-repaint - bind -s --preset -M visual -m default y kill-selection yank end-selection force-repaint - bind -s --preset -M visual -m default '"*y' "commandline -s | xsel -p; commandline -f end-selection force-repaint" + bind -s --preset -M visual -m insert c kill-selection end-selection repaint-mode + bind -s --preset -M visual -m default d kill-selection end-selection repaint-mode + bind -s --preset -M visual -m default x kill-selection end-selection repaint-mode + bind -s --preset -M visual -m default X kill-whole-line end-selection repaint-mode + bind -s --preset -M visual -m default y kill-selection yank end-selection repaint-mode + bind -s --preset -M visual -m default '"*y' "commandline -s | xsel -p; commandline -f end-selection repaint-mode" - bind -s --preset -M visual -m default \cc end-selection force-repaint - bind -s --preset -M visual -m default \e end-selection force-repaint + bind -s --preset -M visual -m default \cc end-selection repaint-mode + bind -s --preset -M visual -m default \e end-selection repaint-mode # Make it easy to turn an unexecuted command into a comment in the shell history. Also, remove # the commenting chars so the command can be further edited then executed. diff --git a/sphinx_doc_src/cmds/bind.rst b/sphinx_doc_src/cmds/bind.rst index eca0e4425..3455053d2 100644 --- a/sphinx_doc_src/cmds/bind.rst +++ b/sphinx_doc_src/cmds/bind.rst @@ -136,6 +136,10 @@ The following special input functions are available: - ``pager-toggle-search``, toggles the search field if the completions pager is visible. +- ``repaint`` reexecutes the prompt functions and redraws the prompt. Multiple successive repaints are coalesced. + +- ``repaint-mode`` reexecutes the fish_mode_prompt function and redraws the prompt. This is useful for vi-mode. + - ``suppress-autosuggestion``, remove the current autosuggestion - ``swap-selection-start-stop``, go to the other end of the highlighted text without changing the selection diff --git a/src/input.cpp b/src/input.cpp index ba55f709d..421782dc5 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -112,6 +112,7 @@ static const input_function_metadata_t input_function_metadata[] = { {readline_cmd_t::execute, L"execute"}, {readline_cmd_t::beginning_of_buffer, L"beginning-of-buffer"}, {readline_cmd_t::end_of_buffer, L"end-of-buffer"}, + {readline_cmd_t::repaint_mode, L"repaint-mode"}, {readline_cmd_t::repaint, L"repaint"}, {readline_cmd_t::force_repaint, L"force-repaint"}, {readline_cmd_t::up_line, L"up-line"}, diff --git a/src/input_common.h b/src/input_common.h index 3b2ffb6e1..d7b061fa4 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -50,6 +50,7 @@ enum class readline_cmd_t { execute, beginning_of_buffer, end_of_buffer, + repaint_mode, repaint, force_repaint, up_line, diff --git a/src/reader.cpp b/src/reader.cpp index 53a4a2d33..04f4c8668 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -357,6 +357,7 @@ class reader_data_t : public std::enable_shared_from_this { wcstring right_prompt; /// The output of the last evaluation of the prompt command. wcstring left_prompt_buff; + wcstring mode_prompt_buff; /// The output of the last evaluation of the right prompt command. wcstring right_prompt_buff; /// Completion support. @@ -461,6 +462,7 @@ class reader_data_t : public std::enable_shared_from_this { void highlight_search(); void highlight_complete(highlight_result_t result); + void exec_mode_prompt(); void exec_prompt(); bool jump(jump_direction_t dir, jump_precision_t precision, editable_line_t *el, @@ -641,7 +643,8 @@ void reader_data_t::repaint() { bool focused_on_pager = active_edit_line() == &pager.search_field_line; size_t cursor_position = focused_on_pager ? pager.cursor_position() : cmd_line->position; - s_write(&screen, left_prompt_buff, right_prompt_buff, full_line, cmd_line->size(), colors, + // Prepend the mode prompt to the left prompt. + s_write(&screen, mode_prompt_buff + left_prompt_buff, right_prompt_buff, full_line, cmd_line->size(), colors, indents, cursor_position, current_page_rendering, focused_on_pager); repaint_needed = false; @@ -904,6 +907,20 @@ void reader_write_title(const wcstring &cmd, bool reset_cursor_position) { } } +void reader_data_t::exec_mode_prompt() { + mode_prompt_buff.clear(); + if (function_exists(MODE_PROMPT_FUNCTION_NAME)) { + wcstring_list_t mode_indicator_list; + exec_subshell(MODE_PROMPT_FUNCTION_NAME, parser(), mode_indicator_list, + false); + // We do not support multiple lines in the mode indicator, so just concatenate all of + // them. + for (size_t i = 0; i < mode_indicator_list.size(); i++) { + mode_prompt_buff += mode_indicator_list.at(i); + } + } +} + /// Reexecute the prompt command. The output is inserted into prompt_buff. void reader_data_t::exec_prompt() { // Clear existing prompts. @@ -921,17 +938,7 @@ void reader_data_t::exec_prompt() { if (left_prompt.size() || right_prompt.size()) { proc_push_interactive(0); - // Prepend any mode indicator to the left prompt (issue #1988). - if (function_exists(MODE_PROMPT_FUNCTION_NAME)) { - wcstring_list_t mode_indicator_list; - exec_subshell(MODE_PROMPT_FUNCTION_NAME, parser(), mode_indicator_list, - apply_exit_status); - // We do not support multiple lines in the mode indicator, so just concatenate all of - // them. - for (size_t i = 0; i < mode_indicator_list.size(); i++) { - left_prompt_buff += mode_indicator_list.at(i); - } - } + exec_mode_prompt(); if (!left_prompt.empty()) { wcstring_list_t prompt_list; @@ -2503,6 +2510,16 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // The only thing we can cancel right now is paging, which we handled up above. break; } + case rl::repaint_mode: { + // Repaint the mode-prompt only if it exists. + // This is an optimization basically exclusively for vi-mode, since the prompt + // may sometimes take a while but when switching the mode all we care about is the mode-prompt. + exec_mode_prompt(); + s_reset(&screen, screen_reset_current_line_and_prompt); + screen_reset_needed = false; + repaint(); + break; + } case rl::force_repaint: case rl::repaint: { if (!rls.coalescing_repaints) { From bc958712e40f7a1a72787c17e3671eee321db423 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 1 Apr 2019 16:02:09 +0200 Subject: [PATCH 0230/1732] CHANGELOG INTERNAL_WCWIDTH [ci skip] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a2a7f789..2824e1d67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ ### For distributors and developers - The autotools-based build system and legacy Xcode build systems have been removed, leaving only the CMake build system. All distributors and developers must migrate to the CMake build. - The doxygen-based documentation system has been removed and replaced with one based on sphinx. All distributors and developers must migrate to that. +- The INTERNAL_WCWIDTH build option to use the system wcwidth has been removed. We believe our wcwidth is a better choice, as it has a number of configuration options that the other path never gained (#5777). --- From 99dd6d7394576d1e6e9600efef8a8375d50ba6e1 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 1 Apr 2019 16:04:14 +0200 Subject: [PATCH 0231/1732] Let repaint-mode act like a repaint if no fish_mode_prompt exists Otherwise I'm pretty sure we'd get complaints from people who use a mode-indicator elsewhere in their prompts. --- sphinx_doc_src/cmds/bind.rst | 2 +- src/reader.cpp | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/sphinx_doc_src/cmds/bind.rst b/sphinx_doc_src/cmds/bind.rst index 3455053d2..394bb42f1 100644 --- a/sphinx_doc_src/cmds/bind.rst +++ b/sphinx_doc_src/cmds/bind.rst @@ -138,7 +138,7 @@ The following special input functions are available: - ``repaint`` reexecutes the prompt functions and redraws the prompt. Multiple successive repaints are coalesced. -- ``repaint-mode`` reexecutes the fish_mode_prompt function and redraws the prompt. This is useful for vi-mode. +- ``repaint-mode`` reexecutes the fish_mode_prompt function and redraws the prompt. This is useful for vi-mode. If no fish_mode_prompt exists, it acts like a normal repaint. - ``suppress-autosuggestion``, remove the current autosuggestion diff --git a/src/reader.cpp b/src/reader.cpp index 04f4c8668..acdd9ad3f 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2514,11 +2514,15 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // Repaint the mode-prompt only if it exists. // This is an optimization basically exclusively for vi-mode, since the prompt // may sometimes take a while but when switching the mode all we care about is the mode-prompt. - exec_mode_prompt(); - s_reset(&screen, screen_reset_current_line_and_prompt); - screen_reset_needed = false; - repaint(); - break; + if (function_exists(MODE_PROMPT_FUNCTION_NAME)) { + exec_mode_prompt(); + s_reset(&screen, screen_reset_current_line_and_prompt); + screen_reset_needed = false; + repaint(); + break; + } + // If it doesn't exist, we repaint as normal. + /* fallthrough */ } case rl::force_repaint: case rl::repaint: { From ab92baf671cba7e4ac207725505b0c916b8ff198 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 1 Apr 2019 16:14:00 +0200 Subject: [PATCH 0232/1732] CHANGELOG repaint-mode [ci skip] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2824e1d67..2b68a2692 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ - `vagrant` - The git prompt in informative mode now shows the number of stashes if enabled. - The nextd and prevd functions no longer print "Hit end of history", instead using a BEL. +- If fish_mode_prompt exists, vi-mode will only execute it on mode-switch instead of the entire prompt. This should make it much more responsive with slow prompts (#5783). ### For distributors and developers - The autotools-based build system and legacy Xcode build systems have been removed, leaving only the CMake build system. All distributors and developers must migrate to the CMake build. From dd007c29f4b9b94155b194fba3a140f5bd7a2e62 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Mon, 1 Apr 2019 20:19:28 -0700 Subject: [PATCH 0233/1732] Revert "parser: try to avoid some strings being copied" This reverts commit 7a74198aa3cf88585eee879bd608df36fca12ced. Believe it or not this commit actually increased copying. When accepting a value you know you're going to take ownership of, just accept it by value; then temporaries can invoke the move ctor and blah blah blah. We really need a lightweight refcounted pass-by-value string to make this less error prone. --- src/parse_tree.cpp | 2 +- src/parse_tree.h | 2 +- src/parser.cpp | 2 +- src/parser.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/parse_tree.cpp b/src/parse_tree.cpp index d2e3774af..cd7b35568 100644 --- a/src/parse_tree.cpp +++ b/src/parse_tree.cpp @@ -1135,7 +1135,7 @@ const parse_node_t *parse_node_tree_t::get_child(const parse_node_t &parent, nod return result; } -parsed_source_ref_t parse_source(const wcstring &src, parse_tree_flags_t flags, parse_error_list_t *errors, +parsed_source_ref_t parse_source(wcstring src, parse_tree_flags_t flags, parse_error_list_t *errors, parse_token_type_t goal) { parse_node_tree_t tree; if (!parse_tree_from_string(src, flags, &tree, errors, goal)) return {}; diff --git a/src/parse_tree.h b/src/parse_tree.h index 8fc536131..9e032f11d 100644 --- a/src/parse_tree.h +++ b/src/parse_tree.h @@ -233,7 +233,7 @@ struct parsed_source_t { }; /// Return a shared pointer to parsed_source_t, or null on failure. using parsed_source_ref_t = std::shared_ptr; -parsed_source_ref_t parse_source(const wcstring &src, parse_tree_flags_t flags, parse_error_list_t *errors, +parsed_source_ref_t parse_source(wcstring src, parse_tree_flags_t flags, parse_error_list_t *errors, parse_token_type_t goal = symbol_job_list); #endif diff --git a/src/parser.cpp b/src/parser.cpp index 4b0a75082..a36faa4f4 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -618,7 +618,7 @@ profile_item_t *parser_t::create_profile_item() { return result; } -int parser_t::eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type) { +int parser_t::eval(wcstring cmd, const io_chain_t &io, enum block_type_t block_type) { // Parse the source into a tree, if we can. parse_error_list_t error_list; parsed_source_ref_t ps = parse_source(cmd, parse_flag_none, &error_list); diff --git a/src/parser.h b/src/parser.h index e6409c283..6648b069b 100644 --- a/src/parser.h +++ b/src/parser.h @@ -222,7 +222,7 @@ class parser_t : public std::enable_shared_from_this { /// \param block_type The type of block to push on the block stack /// /// \return 0 on success, 1 on a parse error. - int eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type); + int eval(wcstring cmd, const io_chain_t &io, enum block_type_t block_type); /// Evaluate the parsed source ps. void eval(parsed_source_ref_t ps, const io_chain_t &io, enum block_type_t block_type); From aa3dff098c511492a958cb05013c37309477de84 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 2 Apr 2019 12:46:23 +0200 Subject: [PATCH 0234/1732] docs/string: Add paragraph on comparison with unix tools [ci skip] --- sphinx_doc_src/cmds/string.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sphinx_doc_src/cmds/string.rst b/sphinx_doc_src/cmds/string.rst index b7fa6752c..13e3608b6 100644 --- a/sphinx_doc_src/cmds/string.rst +++ b/sphinx_doc_src/cmds/string.rst @@ -226,6 +226,21 @@ And some other things: - ``^`` is the start of the string or line, ``$`` the end. - ``|`` is "alternation", i.e. the "or". +Comparison to other tools +------------------------- + +Most operations ``string`` supports can also be done by external tools. Some of these include ``grep``, ``sed`` and ``cut``. + +If you are familiar with these, it is useful to know how ``string`` differs from them. + +In contrast to these classics, ``string`` reads input either from stdin or as arguments. ``string`` also does not deal with files, so it requires redirections to be used with them. + +In contrast to ``grep``, ``string``\ s `match` and `replace` default to glob-mode. If set to regex-mode, they use PCRE regular expressions, which is comparable to ``grep``\ s `-P` option. `match` defaults to printing just the match, which is like ``grep`` with `-o` (use `--entire` to enable grep-like behavior). + +Like ``sed``\ s `s/` command, ``string replace`` still prints strings that don't match. ``sed``\ s `-n` in combination with a `/p` modifier or command is like ``string replace -f``. + +``string split somedelimiter`` is a replacement for ``tr somedeliminter \n`. + Examples -------- From 318fe3c04655756c55ec7268f87664cc568e4677 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 3 Apr 2019 19:49:38 +0200 Subject: [PATCH 0235/1732] docs/string: Replace doesn't do globs As a bit of weirdness in string's design, replace does literal matching (`*` aren't expanded) by default, not globs. [ci skip] --- sphinx_doc_src/cmds/string.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_doc_src/cmds/string.rst b/sphinx_doc_src/cmds/string.rst index 13e3608b6..220247026 100644 --- a/sphinx_doc_src/cmds/string.rst +++ b/sphinx_doc_src/cmds/string.rst @@ -235,7 +235,7 @@ If you are familiar with these, it is useful to know how ``string`` differs from In contrast to these classics, ``string`` reads input either from stdin or as arguments. ``string`` also does not deal with files, so it requires redirections to be used with them. -In contrast to ``grep``, ``string``\ s `match` and `replace` default to glob-mode. If set to regex-mode, they use PCRE regular expressions, which is comparable to ``grep``\ s `-P` option. `match` defaults to printing just the match, which is like ``grep`` with `-o` (use `--entire` to enable grep-like behavior). +In contrast to ``grep``, ``string``\ s `match` defaults to glob-mode, whie `replace` defaults to literal matching. If set to regex-mode, they use PCRE regular expressions, which is comparable to ``grep``\ s `-P` option. `match` defaults to printing just the match, which is like ``grep`` with `-o` (use `--entire` to enable grep-like behavior). Like ``sed``\ s `s/` command, ``string replace`` still prints strings that don't match. ``sed``\ s `-n` in combination with a `/p` modifier or command is like ``string replace -f``. From e2ed6baf43c89ab4fe54dd8ea245c20b4fdb207f Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Wed, 3 Apr 2019 16:47:05 -0700 Subject: [PATCH 0236/1732] Make the output/errput test more robust by sorting output --- tests/test1.in | 2 +- tests/test1.out | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test1.in b/tests/test1.in index 41fc71caa..51302c2a3 100644 --- a/tests/test1.in +++ b/tests/test1.in @@ -110,7 +110,7 @@ echo Test 5 $sta logmsg Verify that we can turn stderr into stdout and then pipe it # Note that the order here has historically been unspecified - 'errput' could conceivably appear before 'output'. -begin ; echo output ; echo errput 1>&2 ; end 2>&1 | tee ../test/temp/tee_test.txt ; cat ../test/temp/tee_test.txt +begin ; echo output ; echo errput 1>&2 ; end 2>&1 | sort | tee ../test/temp/tee_test.txt ; cat ../test/temp/tee_test.txt logmsg "Test that trailing ^ doesn't trigger redirection, see #1873" echo caret_no_redirect 12345^ diff --git a/tests/test1.out b/tests/test1.out index 8ac15efc6..6c141412d 100644 --- a/tests/test1.out +++ b/tests/test1.out @@ -44,10 +44,10 @@ Test 5 pass #################### # Verify that we can turn stderr into stdout and then pipe it -output errput output errput +output #################### # Test that trailing ^ doesn't trigger redirection, see #1873 From bc66921ac9c10bf6a36e2b9b9f9dd83347b1d3e6 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 3 Apr 2019 20:38:29 -0500 Subject: [PATCH 0237/1732] Optimize keyword detection The data stored in these containers is small enough that it is worth creating distinct sets for each lookup. In a microbenchmark of these changes, the single-lookup version of the function with lookups gated on the length of input (bypassed entirely if the input is longer than the longest key in the container) provided a 1.5x-3.5x speedup over the previous implementation. Additionally, as the collections are static and their contents are never modified after startup, it makes no sense to continously calculate the location of and allocate an iterator for the `!= foo.end()` comparison; the end iterator is now statically cached. I'm not expecting massive speed gains out of this change, but the parser does perform enough of these to make it worth optimizing in this way. --- src/parser_keywords.cpp | 84 ++++++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 14 deletions(-) diff --git a/src/parser_keywords.cpp b/src/parser_keywords.cpp index 4711d178d..7f1bdecc7 100644 --- a/src/parser_keywords.cpp +++ b/src/parser_keywords.cpp @@ -8,26 +8,82 @@ #include "fallback.h" // IWYU pragma: keep #include "parser_keywords.h" +typedef std::unordered_set string_set_t; + +static const wcstring skip_keywords[] { + L"else", + L"begin", +}; + +static const wcstring subcommand_keywords[] { + L"command", L"builtin", L"while", L"exec", + L"if", L"and", L"or", L"not" +}; + +static const string_set_t block_keywords = { + L"for", L"while", L"if", + L"function", L"switch", L"begin" +}; + +static const wcstring reserved_keywords[] = { + L"end", L"case", L"else", L"return", + L"continue", L"break", L"argparse", L"read", + L"set", L"status", L"test", L"[" +}; + +// The lists above are purposely implemented separately from the logic below, so that future +// maintainers may assume the contents of the list based off their names, and not off what the +// functions below require them to contain. + +static size_t list_max_length(const string_set_t &list) { + size_t result = 0; + for (const auto &w: list) { + if (w.length() > result) { + result = w.length(); + } + } + return result; +} + bool parser_keywords_skip_arguments(const wcstring &cmd) { - static const wcstring el = L"else"; - static const wcstring beg = L"begin"; - return cmd == el || cmd == beg; + return cmd == skip_keywords[0] || cmd == skip_keywords[1]; } -static const std::unordered_set subcommand_keywords = {L"command", L"builtin", L"while", L"exec", - L"if", L"and", L"or", L"not"}; bool parser_keywords_is_subcommand(const wcstring &cmd) { - return parser_keywords_skip_arguments(cmd) || contains(subcommand_keywords, cmd); + const static string_set_t search_list = ([](){ + string_set_t results; + results.insert(std::begin(subcommand_keywords), std::end(subcommand_keywords)); + results.insert(std::begin(skip_keywords), std::end(skip_keywords)); + return results; + })(); + + const static auto max_len = list_max_length(search_list); + const static auto not_found = search_list.end(); + + // Everything above is executed only at startup, this is the actual optimized search routine: + return cmd.length() <= max_len && search_list.find(cmd) != not_found; } -static const std::unordered_set block_keywords = {L"for", L"while", L"if", - L"function", L"switch", L"begin"}; -bool parser_keywords_is_block(const wcstring &word) { return contains(block_keywords, word); } +bool parser_keywords_is_block(const wcstring &word) { + const static auto max_len = list_max_length(block_keywords); + const static auto not_found = block_keywords.end(); + + // Everything above is executed only at startup, this is the actual optimized search routine: + return word.length() <= max_len && block_keywords.find(word) != not_found; +} -static const std::unordered_set reserved_keywords = {L"end", L"case", L"else", L"return", - L"continue", L"break", L"argparse", L"read", - L"set", L"status", L"test", L"["}; bool parser_keywords_is_reserved(const wcstring &word) { - return parser_keywords_is_block(word) || parser_keywords_is_subcommand(word) || - contains(reserved_keywords, word); + const static string_set_t search_list = ([](){ + string_set_t results; + results.insert(std::begin(subcommand_keywords), std::end(subcommand_keywords)); + results.insert(std::begin(skip_keywords), std::end(skip_keywords)); + results.insert(std::begin(block_keywords), std::end(block_keywords)); + results.insert(std::begin(reserved_keywords), std::end(reserved_keywords)); + return results; + })(); + const static auto max_len = list_max_length(search_list); + const static auto not_found = search_list.end(); + + // Everything above is executed only at startup, this is the actual optimized search routine: + return word.length() <= max_len && search_list.find(word) != not_found; } From 09e8f0fd7cef9fa59c7d9776577529b535569f57 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 4 Apr 2019 13:40:20 -0700 Subject: [PATCH 0238/1732] rearrange structure fields Putting larger members before smaller ones will reduce structure sizes. bools are 1 byte. on 64bit systems I think they reduced: wgetopt.h:46: 64 to 56 bytes builtin_history.cpp:30: 48 to 32 bytes builtin_status.cpp:91: 32 to 24 bytes tinyexpr.cpp:69: 40 to 32 bytes --- src/builtin_history.cpp | 6 +++--- src/builtin_status.cpp | 2 +- src/tinyexpr.cpp | 3 +-- src/wgetopt.h | 19 +++++++++---------- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/builtin_history.cpp b/src/builtin_history.cpp index 583657ae9..09610b3c7 100644 --- a/src/builtin_history.cpp +++ b/src/builtin_history.cpp @@ -28,12 +28,12 @@ static const enum_map hist_enum_map[] = { {HIST_SAVE, L"save"}, {HIST_SEARCH, L"search"}, {HIST_UNDEF, NULL}}; struct history_cmd_opts_t { - bool print_help = false; hist_cmd_t hist_cmd = HIST_UNDEF; history_search_type_t search_type = (history_search_type_t)-1; - size_t max_items = SIZE_MAX; - bool history_search_type_defined = false; const wchar_t *show_time_format = NULL; + size_t max_items = SIZE_MAX; + bool print_help = false; + bool history_search_type_defined = false; bool case_sensitive = false; bool null_terminate = false; bool reverse = false; diff --git a/src/builtin_status.cpp b/src/builtin_status.cpp index c11aa4a5d..fe253ecfd 100644 --- a/src/builtin_status.cpp +++ b/src/builtin_status.cpp @@ -90,11 +90,11 @@ static maybe_t job_control_str_to_mode(const wchar_t *mode, wchar } struct status_cmd_opts_t { - bool print_help{false}; int level{1}; maybe_t new_job_control_mode{}; const wchar_t *feature_name{}; status_cmd_t status_cmd{STATUS_UNDEF}; + bool print_help{false}; }; /// Note: Do not add new flags that represent subcommands. We're encouraging people to switch to diff --git a/src/tinyexpr.cpp b/src/tinyexpr.cpp index e4ae70a34..e4afe469b 100644 --- a/src/tinyexpr.cpp +++ b/src/tinyexpr.cpp @@ -67,11 +67,10 @@ typedef struct te_builtin { } te_builtin; typedef struct state { + union {double value; const void *function;}; const char *start; const char *next; int type; - union {double value; const void *function;}; - te_error_type_t error; } state; diff --git a/src/wgetopt.h b/src/wgetopt.h index f5de1a57a..ae5ed0b21 100644 --- a/src/wgetopt.h +++ b/src/wgetopt.h @@ -45,9 +45,6 @@ Cambridge, MA 02139, USA. */ class wgetopter_t { private: - bool initialized = false; - bool missing_arg_return_colon = false; - void exchange(wchar_t **argv); void _wgetopt_initialize(const wchar_t *optstring); int _wgetopt_internal(int argc, wchar_t **argv, const wchar_t *optstring, @@ -60,6 +57,8 @@ class wgetopter_t { int *exact, int *ambig, int *indfound); void _update_long_opt(int argc, wchar_t **argv, const struct woption *pfound, wchar_t *nameend, int *longind, int option_index, int *retval); + bool initialized = false; + bool missing_arg_return_colon = false; public: // For communication from `getopt' to the caller. When `getopt' finds an option that takes an @@ -69,6 +68,13 @@ class wgetopter_t { const wchar_t *shortopts = nullptr; + // The next char to be scanned in the option-element in which the last option character we + // returned was found. This allows us to pick up the scan where we left off. + // + // If this is zero, or a null string, it means resume the scan by advancing to the next + // ARGV-element. + wchar_t *nextchar = nullptr; + // Index in ARGV of the next element to be scanned. This is used for communication to and from // the caller and for communication between successive calls to `getopt'. // @@ -83,13 +89,6 @@ class wgetopter_t { // XXX 1003.2 says this must be 1 before any call. int woptind = 0; - // The next char to be scanned in the option-element in which the last option character we - // returned was found. This allows us to pick up the scan where we left off. - // - // If this is zero, or a null string, it means resume the scan by advancing to the next - // ARGV-element. - wchar_t *nextchar = nullptr; - // Callers store zero here to inhibit the error message for unrecognized options. int wopterr = 0; From b064eaa571d9ba9e7610f59ca93e78cff1a694fc Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 4 Apr 2019 14:16:34 -0700 Subject: [PATCH 0239/1732] use std::move in a couple spots where things were unsed after copy --- src/env.cpp | 8 ++++---- src/path.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/env.cpp b/src/env.cpp index 1a4080d7d..268234221 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -195,7 +195,7 @@ struct var_stack_t { } node->next = this->top; - this->top = node; + this->top = std::move(node); if (new_scope && local_scope_exports(this->top)) { this->mark_changed_exported(); } @@ -1160,7 +1160,7 @@ int env_stack_t::set_internal(const wcstring &key, env_mode_flags_t input_var_mo bool has_changed_new = false; env_node_ref_t preexisting_node = get_node(key); maybe_t preexisting_flags{}; - if (preexisting_node != NULL) { + if (preexisting_node != nullptr) { var_table_t::const_iterator result = preexisting_node->env.find(key); assert(result != preexisting_node->env.end()); preexisting_flags = result->second.get_flags(); @@ -1174,8 +1174,8 @@ int env_stack_t::set_internal(const wcstring &key, env_mode_flags_t input_var_mo node = vars_stack().global_env; } else if (var_mode & ENV_LOCAL) { node = vars_stack().top; - } else if (preexisting_node != NULL) { - node = preexisting_node; + } else if (preexisting_node != nullptr) { + node = std::move(preexisting_node); if ((var_mode & (ENV_EXPORT | ENV_UNEXPORT)) == 0) { // Use existing entry's exportv status. if (preexisting_flags && (*preexisting_flags & env_var_t::flag_export)) { diff --git a/src/path.cpp b/src/path.cpp index 937738664..0a47f11ee 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -185,7 +185,7 @@ maybe_t path_get_cdpath(const wcstring &dir, const wcstring &wd, expand_tilde(next_path, env_vars); if (next_path.empty()) continue; - wcstring whole_path = next_path; + wcstring whole_path = std::move(next_path); append_path_component(whole_path, dir); paths.push_back(whole_path); } From b4ddd797e31bdf120dc6a2a08974d8ed8fb905e7 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 4 Apr 2019 14:24:36 -0700 Subject: [PATCH 0240/1732] remove unused wcstring --- src/complete.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/complete.cpp b/src/complete.cpp index 481cff7d5..d4091855d 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -1124,7 +1124,6 @@ bool completer_t::complete_variable(const wcstring &str, size_t start_offset) { size_t varlen = str.length() - start_offset; bool res = false; - const wcstring_list_t names = vars.get_names(0); for (const wcstring &env_name : vars.get_names(0)) { string_fuzzy_match_t match = string_fuzzy_match_string(var, env_name, this->max_fuzzy_match_type()); From be80a56ad4a9bc834cd388e9d04a302e246bade4 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 4 Apr 2019 17:31:54 -0700 Subject: [PATCH 0241/1732] expand.cpp: use wcspbrk for is_quotable --- src/expand.cpp | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/expand.cpp b/src/expand.cpp index 408176166..7d73ff3ca 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -124,24 +124,11 @@ static void append_cmdsub_error(parse_error_list_t *errors, size_t source_start, /// Test if the specified string does not contain character which can not be used inside a quoted /// string. -static int is_quotable(const wchar_t *str) { - switch (*str) { - case 0: { - return 1; - } - case L'\n': - case L'\t': - case L'\r': - case L'\b': - case L'\x1B': { - return 0; - } - default: { return is_quotable(str + 1); } - } - return 0; +static bool is_quotable(const wchar_t *str) { + return !std::wcspbrk(str, L"\n\t\r\b\x1B"); } -static int is_quotable(const wcstring &str) { return is_quotable(str.c_str()); } +static bool is_quotable(const wcstring &str) { return is_quotable(str.c_str()); } wcstring expand_escape_variable(const env_var_t &var) { wcstring buff; @@ -1115,6 +1102,7 @@ expand_error_t expand_to_command_and_args(const wcstring &instr, const environme parse_error_list_t *errors) { // Fast path. if (expand_is_clean(instr)) { + *out_cmd = instr; return EXPAND_OK; } From 2e6264558c1d548b95c2cb6eb1491d139af3a9e2 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Thu, 4 Apr 2019 22:25:45 -0500 Subject: [PATCH 0242/1732] Fix remaining realpath test issue with symlinks Pursuant to 0be79038590d3473b75252bf50ade2f62ea9c207, there still remained one issue with the test when run from within a symlinked directory after fish gained support for cding into symlinks. This change should make the test function OK both when the tests are run out of a PWD containing a symlink in its hierarchy and when run otherwise. --- tests/realpath.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/realpath.in b/tests/realpath.in index abaccf4cd..89397dd64 100644 --- a/tests/realpath.in +++ b/tests/realpath.in @@ -11,7 +11,7 @@ end # A non-existent file relative to $PWD succeeds. set -l real_path (builtin realpath nonexistent-file) -if test "$real_path" = "$PWD/nonexistent-file" +if test "$real_path" = (realpath $PWD)"/nonexistent-file" echo nonexistent-file in PWD correctly converted end From 2a3677b38659835858c9d557e7d920630bfbcbb8 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 5 Apr 2019 12:29:57 +0200 Subject: [PATCH 0243/1732] Stop setting term-modes early This set the term modes to the shell-modes, including disabling ICRNL (translating \cm to \cj) and echo. The rationale given was that `reader_interactive_init()` would only be called >= 250ms later, which I _highly_ doubt considering fish's total startup time is 8ms for me. The main idea was that this would stop programs like tmuxinator that send shortcuts early from failing _iff_ the shortcut was \cj, which also seems quite unusual. This works both with `rm -i` and `read` in config.fish, because `read` explicitly calls `reader_push`, which then initializes the shell modes. The real fix would involve reordering our init so we set up the modesetting first, but that's quite involved and the remaining issue should barely happen, while it's fairly common to have issues with a prompt in config.fish, and the workaround for the former is simpler, so let's leave it for now. Partially reverts #2578. Fixes #2980. --- src/fish_key_reader.cpp | 3 +++ src/reader.cpp | 12 ------------ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/fish_key_reader.cpp b/src/fish_key_reader.cpp index ba688b4e7..36fdd0fa8 100644 --- a/src/fish_key_reader.cpp +++ b/src/fish_key_reader.cpp @@ -286,6 +286,9 @@ static void setup_and_process_keys(bool continuous_mode) { proc_push_interactive(1); env_init(); reader_init(); + // We need to set the shell-modes for ICRNL, + // in fish-proper this is done once a command is run. + tcsetattr(STDIN_FILENO, TCSANOW, &shell_modes); install_our_signal_handlers(); if (continuous_mode) { diff --git a/src/reader.cpp b/src/reader.cpp index acdd9ad3f..aa800efe1 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -1001,18 +1001,6 @@ void reader_init() { shell_modes.c_cc[VMIN] = 1; shell_modes.c_cc[VTIME] = 0; - // We don't use term_steal because this can fail if fd 0 isn't associated with a tty and this - // function is run regardless of whether stdin is tied to a tty. This is harmless in that case. - // We do it unconditionally because disabling ICRNL mode (see above) needs to be done at the - // earliest possible moment. Doing it here means it will be done within approximately 1 ms of - // the start of the shell rather than 250 ms (or more) when reader_interactive_init is - // eventually called. - // - // TODO: Remove this condition when issue #2315 and #1041 are addressed. - if (is_interactive_session) { - tcsetattr(STDIN_FILENO, TCSANOW, &shell_modes); - } - // We do this not because we actually need the window size but for its side-effect of correctly // setting the COLUMNS and LINES env vars. get_current_winsize(); From 357a572b43bcd908afcf294518a7587fa75a1223 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 5 Apr 2019 14:08:58 +0200 Subject: [PATCH 0244/1732] docs/index: Document repaint-mode This was only mentioned in passing in the bind docs. [ci skip] --- sphinx_doc_src/index.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sphinx_doc_src/index.rst b/sphinx_doc_src/index.rst index f6b72f568..3f27ebef0 100644 --- a/sphinx_doc_src/index.rst +++ b/sphinx_doc_src/index.rst @@ -1483,6 +1483,8 @@ It is also possible to add all emacs-mode bindings to vi-mode by using something When in vi-mode, the `fish_mode_prompt `_ function will display a mode indicator to the left of the prompt. The ``fish_vi_cursor`` function will be used to change the cursor's shape depending on the mode in supported terminals. To disable this feature, override it with an empty function. To display the mode elsewhere (like in your right prompt), use the output of the ``fish_default_mode_prompt`` function. +When a binding switches the mode, it will repaint the mode-prompt if it exists, and the rest of the prompt only if it doesn't. So if you want a mode-indicator in your ``fish_prompt``, you need to erase ``fish_mode_prompt`` e.g. by adding an empty file at `~/.config/fish/functions/fish_mode_prompt.fish`. (Bindings that change the mode are supposed to call the `repaint-mode` bind function, see :ref:`bind `) + .. _vi-mode-command: Command mode From 21ef9f5150624c159e964161ad59b65192236084 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 5 Apr 2019 14:09:41 +0200 Subject: [PATCH 0245/1732] docs: Remove fish_vi_mode documentation This has been deprecated for quite a while, no need to keep the docs around. [ci skip] --- sphinx_doc_src/cmds/fish_vi_mode.rst | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 sphinx_doc_src/cmds/fish_vi_mode.rst diff --git a/sphinx_doc_src/cmds/fish_vi_mode.rst b/sphinx_doc_src/cmds/fish_vi_mode.rst deleted file mode 100644 index 61d8bb713..000000000 --- a/sphinx_doc_src/cmds/fish_vi_mode.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. _cmd-fish_vi_mode: - -fish_vi_mode - Enable vi mode -============================= - -Synopsis --------- - -fish_vi_mode - - -Description ------------ - -This function is deprecated. Please call ``fish_vi_key_bindings directly`` - -``fish_vi_mode`` enters a vi-like command editing mode. To always start in vi mode, add ``fish_vi_mode`` to your ``config.fish`` file. From 4e555aebec474412d0ce10ba6692cb5a2172c0c6 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 6 Apr 2019 02:06:13 -0700 Subject: [PATCH 0246/1732] Remove is_whitespace and whitespace character string declarations I don't doubt such functions and character arrays could be useful, to keep things consistent, but they are not actually being used. --- src/common.cpp | 19 ------------------- src/common.h | 8 -------- 2 files changed, 27 deletions(-) diff --git a/src/common.cpp b/src/common.cpp index d097f5844..73e2f43ae 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -78,7 +78,6 @@ const wchar_t *program_name; int debug_level = 1; // default maximum debug output level (errors and warnings) int debug_stack_frames = 0; // default number of stack frames to show on debug() calls - /// Be able to restore the term's foreground process group. /// This is set during startup and not modified after. static pid_t initial_fg_process_group = -1; @@ -93,24 +92,6 @@ static volatile bool termsize_valid = false; static char *wcs2str_internal(const wchar_t *in, char *out); static void debug_shared(const wchar_t msg_level, const wcstring &msg); -bool is_whitespace(wchar_t c) { - switch (c) { - case ' ': - case '\t': - case '\r': - case '\n': - case '\v': - return true; - default: - return false; - } -} - -bool is_whitespace(const wcstring &input) { - bool (*pred)(wchar_t c) = is_whitespace; - return std::all_of(input.begin(), input.end(), pred); -} - #if defined(OS_IS_CYGWIN) || defined(WSL) // MS Windows tty devices do not currently have either a read or write timestamp. Those // respective fields of `struct stat` are always the current time. Which means we can't diff --git a/src/common.h b/src/common.h index cf6963349..98785ab24 100644 --- a/src/common.h +++ b/src/common.h @@ -217,14 +217,6 @@ extern const wchar_t *program_name; /// Set to false if it's been determined we can't trust the last modified timestamp on the tty. extern const bool has_working_tty_timestamps; -/// A list of all whitespace characters -extern const wcstring whitespace; -extern const char *whitespace_narrow; - -bool is_whitespace(const wchar_t input); -bool is_whitespace(const wcstring &input); -inline bool is_whitespace(const wchar_t *input) { return is_whitespace(wcstring(input)); } - /// This macro is used to check that an argument is true. It is a bit like a non-fatal form of /// assert. Instead of exiting on failure, the current function is ended at once. The second /// parameter is the return value of the current function on failure. From f1614a995ab187df6de4025ae288f27fa4cd7768 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 6 Apr 2019 20:37:14 +0200 Subject: [PATCH 0247/1732] docs: Reword `commandline -f` We don't refer to "readline functions" anywhere else, and "injecting" them "into the reader" is an overly jargony way of expressing it that only makes sense to someone familiar with the internals. And even then the term "readline" is already taken by the "readline" library, used by bash et al, but not by us. So we pick the term "input functions", like we did in bind. See https://stackoverflow.com/questions/55542839/what-does-commandline-f-repaint-in-fish-shell/55543411#55543411. [ci skip] --- sphinx_doc_src/cmds/commandline.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_doc_src/cmds/commandline.rst b/sphinx_doc_src/cmds/commandline.rst index 67e35cb7d..ee012beff 100644 --- a/sphinx_doc_src/cmds/commandline.rst +++ b/sphinx_doc_src/cmds/commandline.rst @@ -22,7 +22,7 @@ The following options are available: - ``-C`` or ``--cursor`` set or get the current cursor position, not the contents of the buffer. If no argument is given, the current cursor position is printed, otherwise the argument is interpreted as the new cursor position. -- ``-f`` or ``--function`` inject readline functions into the reader. This option cannot be combined with any other option. It will cause any additional arguments to be interpreted as readline functions, and these functions will be injected into the reader, so that they will be returned to the reader before any additional actual key presses are read. +- ``-f`` or ``--function`` causes any additional arguments to be interpreted as input functions, and puts them into the queue, so that they will be read before any additional actual key presses are. This option cannot be combined with any other option. See :ref:`bind ` for a list of input functions. The following options change the way ``commandline`` updates the command line buffer: From 6e3c87f4c3c4bbe3b3f8f4b26ed05564d3e27d3c Mon Sep 17 00:00:00 2001 From: Collin Styles Date: Sat, 6 Apr 2019 10:04:45 -0700 Subject: [PATCH 0248/1732] Add completions for git-merge-base --- share/completions/git.fish | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/share/completions/git.fish b/share/completions/git.fish index 6293142e7..8c66fdfaf 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -1169,6 +1169,15 @@ complete -f -c git -n '__fish_git_using_command merge' -s no-rerere-autoupdate - complete -f -c git -n '__fish_git_using_command merge' -l abort -d 'Abort the current conflict resolution process' complete -f -c git -n '__fish_git_using_command merge' -l continue -d 'Conclude current conflict resolution process' +### merge-base +complete -f -c git -n '__fish_git_needs_command' -a merge-base -d 'Find as good common ancestors as possible for a merge' +complete -f -c git -n '__fish_git_using_command merge-base' -a '(__fish_git_branches)' +complete -f -c git -n '__fish_git_using_command merge-base' -s a -l all -d 'Output all merge bases for the commits, instead of just one' +complete -f -c git -n '__fish_git_using_command merge-base' -l octopus -d 'Compute the best common ancestors of all supplied commits' +complete -f -c git -n '__fish_git_using_command merge-base' -l independent -d 'Print a minimal subset of the supplied commits with the same ancestors.' +complete -f -c git -n '__fish_git_using_command merge-base' -l is-ancestor -d 'Check if the first commit is an ancestor of the second commit' +complete -f -c git -n '__fish_git_using_command merge-base' -l fork-point -d 'Find the point at which a branch forked from another branch ref' + ### mergetool complete -f -c git -n '__fish_git_needs_command' -a mergetool -d 'Run merge conflict resolution tools to resolve merge conflicts' From 0bd8c61e7eb1778ccb70d758dc42ba3c3bb662ce Mon Sep 17 00:00:00 2001 From: Collin Styles Date: Sat, 6 Apr 2019 10:38:52 -0700 Subject: [PATCH 0249/1732] Add completions for git-ls-files --- share/completions/git.fish | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/share/completions/git.fish b/share/completions/git.fish index 8c66fdfaf..9392b79c7 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -1135,6 +1135,35 @@ complete -c git -n '__fish_git_using_command log' -l no-prefix complete -x -c git -n '__fish_git_using_command log' -l line-prefix complete -c git -n '__fish_git_using_command log' -l ita-invisible-in-index +### ls-files +complete -c git -n '__fish_git_needs_command' -a ls-files -d 'Show information about files in the index and the working tree' +complete -c git -n '__fish_git_using_command ls-files' +complete -c git -n '__fish_git_using_command ls-files' -s c -l cached -d 'Show cached files in the output' +complete -c git -n '__fish_git_using_command ls-files' -s d -l deleted -d 'Show deleted files in the output' +complete -c git -n '__fish_git_using_command ls-files' -s m -l modified -d 'Show modified files in the output' +complete -c git -n '__fish_git_using_command ls-files' -s o -l others -d 'Show other (i.e. untracked) files in the output' +complete -c git -n '__fish_git_using_command ls-files' -s i -l ignored -d 'Show only ignored files in the output' +complete -c git -n '__fish_git_using_command ls-files' -s s -l staged -d "Show staged contents' mode bits, object name and stage number in the output" +complete -c git -n '__fish_git_using_command ls-files' -l directory -d 'If a whole directory is classified as "other", show just its name' +complete -c git -n '__fish_git_using_command ls-files' -l no-empty-directory -d 'Do not list empty directories' +complete -c git -n '__fish_git_using_command ls-files' -s u -l unmerged -d 'Show unmerged files in the output' +complete -c git -n '__fish_git_using_command ls-files' -s k -l killed -d 'Show files on the filesystem that need to be removed for checkout-index to succeed' +complete -c git -n '__fish_git_using_command ls-files' -s z -d '\0 line termination on output and do not quote filenames' +complete -c git -n '__fish_git_using_command ls-files' -s x -l exclude -d 'Skip untracked files matching pattern' +complete -c git -n '__fish_git_using_command ls-files' -s X -l exclude-from -d 'Read exclude patterns from ; 1 per line' +complete -c git -n '__fish_git_using_command ls-files' -l exclude-per-directory -d 'Read additional exclude patterns that apply only to the directory and its subdirectories in ' +complete -c git -n '__fish_git_using_command ls-files' -l exclude-standard -d 'Add the standard Git exclusions' +complete -c git -n '__fish_git_using_command ls-files' -l error-unmatch -d 'If any does not appear in the index, treat this as an error' +complete -c git -n '__fish_git_using_command ls-files' -l with-tree +complete -c git -n '__fish_git_using_command ls-files' -s t -d 'Identifies the file status' +complete -c git -n '__fish_git_using_command ls-files' -s v -d 'Similar to -t but use lowercase letters for files that are marked as assume unchanged' +complete -c git -n '__fish_git_using_command ls-files' -s f -d 'Similar to -t but use lowercase letters for files that are marked as fsmonitor valid' +complete -c git -n '__fish_git_using_command ls-files' -l full-name -d 'Force paths to be output relative to the project top directory' +complete -c git -n '__fish_git_using_command ls-files' -l recurse-submodules -d 'Recursively calls ls-files on each submodule in the repository' +complete -c git -n '__fish_git_using_command ls-files' -l abbrev -d 'Show only a partial prefix' +complete -c git -n '__fish_git_using_command ls-files' -l debug -d 'After each line that describes a file, add more data about its cache entry' +complete -c git -n '__fish_git_using_command ls-files' -l eol -d 'Show and of files' + ### merge complete -f -c git -n '__fish_git_needs_command' -a merge -d 'Join two or more development histories together' complete -f -c git -n '__fish_git_using_command merge' -a '(__fish_git_branches)' From 82596465b25eec7258cad6c350ca851043097a87 Mon Sep 17 00:00:00 2001 From: Collin Styles Date: Sat, 6 Apr 2019 11:00:37 -0700 Subject: [PATCH 0250/1732] Add completions for git-describe --- share/completions/git.fish | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/share/completions/git.fish b/share/completions/git.fish index 9392b79c7..dd20fe9f2 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -900,6 +900,27 @@ complete -f -c git -n '__fish_git_using_command commit' -l fixup -d 'Fixup commi complete -f -c git -n '__fish_git_using_command commit; and __fish_contains_opt fixup' -k -a '(__fish_git_recent_commits)' # TODO options +### describe +complete -c git -n '__fish_git_needs_command' -a describe -d 'Give an object a human readable name based on an available ref' +complete -k -f -c git -n '__fish_git_using_command describe' -a '(__fish_git_branches)' +complete -k -f -c git -n '__fish_git_using_command describe' -a '(__fish_git_heads)' -d 'Head' +complete -k -f -c git -n '__fish_git_using_command describe' -a '(__fish_git_tags)' -d 'Tag' +complete -k -f -c git -n '__fish_git_using_command describe' -a '(__fish_git_unique_remote_branches)' -d 'Unique Remote Branch' +complete -f -c git -n '__fish_git_using_command describe' -l dirty -d 'Describe the state of the working tree' +complete -f -c git -n '__fish_git_using_command describe' -l broken -d 'Describe the state of the working tree' +complete -f -c git -n '__fish_git_using_command describe' -l all -d 'Use any ref found in refs/ namespace' +complete -f -c git -n '__fish_git_using_command describe' -l tags -d 'Use any tag found in refs/tags namespace' +complete -f -c git -n '__fish_git_using_command describe' -l contains -d 'Find the tag that comes after the commit' +complete -f -c git -n '__fish_git_using_command describe' -l abbrev -d 'Use digits, or as many digits as needed to form a unique object name' +complete -f -c git -n '__fish_git_using_command describe' -l candidates -d 'Consider up to candidates' +complete -f -c git -n '__fish_git_using_command describe' -l exact-match -d 'Only output exact matches' +complete -f -c git -n '__fish_git_using_command describe' -l debug -d 'Verbosely display information about the searching strategy' +complete -f -c git -n '__fish_git_using_command describe' -l long -d 'Always output the long format' +complete -f -c git -n '__fish_git_using_command describe' -l match -d 'Only consider tags matching the given glob pattern' +complete -f -c git -n '__fish_git_using_command describe' -l exclude -d 'Do not consider tags matching the given glob pattern' +complete -f -c git -n '__fish_git_using_command describe' -l always -d 'Show uniquely abbreviated commit object as fallback' +complete -f -c git -n '__fish_git_using_command describe' -l first-parent -d 'Follow only the first parent commit upon seeing a merge commit' + ### diff complete -c git -n '__fish_git_needs_command' -a diff -d 'Show changes between commits, commit and working tree, etc' complete -c git -n '__fish_git_using_command diff' -a '(__fish_git_ranges)' From 2226a87b595a73ae07f94aabbf500fc905ad2b81 Mon Sep 17 00:00:00 2001 From: Collin Styles Date: Sat, 6 Apr 2019 12:18:45 -0700 Subject: [PATCH 0251/1732] Add completions for git-worktree --- share/completions/git.fish | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/share/completions/git.fish b/share/completions/git.fish index dd20fe9f2..e1372e288 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -512,6 +512,10 @@ function __fish_git_stash_not_using_subcommand return 0 end +function __fish_git_complete_worktrees + command git worktree list --porcelain | string match -er '^worktree' | string replace -r '^worktree\s*' '' +end + function __fish_git_complete_stashes command git stash list --format=%gd:%gs 2>/dev/null | string replace ":" \t end @@ -1393,6 +1397,46 @@ complete -f -c git -n '__fish_git_using_command tag' -l contains -xka '(__fish_g complete -f -c git -n '__fish_git_using_command tag; and __fish_contains_opt -s d delete -s v verify' -a '(__fish_git_tags)' -d 'Tag' # TODO options +### worktree +set -l git_worktree_commands add list lock move prune remove unlock +complete -c git -n '__fish_git_needs_command' -a worktree -d 'Manage multiple working trees' +complete -f -c git -n "__fish_git_using_command worktree; and not __fish_seen_subcommand_from $git_worktree_commands" -a add -d 'Create a working tree' +complete -f -c git -n "__fish_git_using_command worktree; and not __fish_seen_subcommand_from $git_worktree_commands" -a list -d 'List details of each worktree' +complete -f -c git -n "__fish_git_using_command worktree; and not __fish_seen_subcommand_from $git_worktree_commands" -a lock -d 'Unlock a working tree' +complete -f -c git -n "__fish_git_using_command worktree; and not __fish_seen_subcommand_from $git_worktree_commands" -a move -d 'Move a working tree to a new location' +complete -f -c git -n "__fish_git_using_command worktree; and not __fish_seen_subcommand_from $git_worktree_commands" -a prune -d 'Prune working tree information in $GIT_DIR/worktrees' +complete -f -c git -n "__fish_git_using_command worktree; and not __fish_seen_subcommand_from $git_worktree_commands" -a remove -d 'Remove a working tree' +complete -f -c git -n "__fish_git_using_command worktree; and not __fish_seen_subcommand_from $git_worktree_commands" -a unlock -d 'Unlock a working tree' + +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add move remove' -s f -l force -d 'Override safeguards' + +complete -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' +complete -k -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -a '(__fish_git_branches)' +complete -k -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -a '(__fish_git_heads)' -d 'Head' +complete -k -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -a '(__fish_git_tags)' -d 'Tag' +complete -k -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -a '(__fish_git_unique_remote_branches)' -d 'Unique Remote Branch' +complete -x -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -s b -d 'Create a new branch' +complete -x -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -s B -d 'Create a new branch even if it already exists' +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -l detach -d 'Detach HEAD in the new working tree' +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -l checkout -d 'Checkout after creating working tree' +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -l no-checkout -d 'Suppress checkout' +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -l guess-remote +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -l no-guess-remote +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -l track -d 'Mark as "upstream" from the new branch' +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -l no-track -d 'Don\'t mark as "upstream" from the new branch' +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -l lock -d 'Lock working tree after creation' +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from add' -s q -l quiet -d 'Suppress feedback messages' +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from list' -l porcelain -d 'Output in an easy-to-parse format for scripts' +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from lock' -a '(__fish_git_complete_worktrees)' +complete -x -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from lock' -l reason -d 'An explanation why the working tree is locked' +complete -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from move' -a '(__fish_git_complete_worktrees)' +complete -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from move' +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from prune' -s n -l dry-run -d 'Do not remove anything' +complete -f -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from prune' -s v -l verbose -d 'Report all removals' +complete -x -c git -n '__fish_git_using_command worktree; and __fish_seen_subcommand_from prune' -l expire -d 'Only expire unused working trees older than