mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 04:43:10 +00:00
Reformat all files
This runs build_tools/style.fish, which runs clang-format on C++, fish_indent on fish and (new) black on python. If anything is wrong with the formatting, we should fix the tools, but automated formatting is worth it.
This commit is contained in:
parent
90d64194c5
commit
c2970f9618
137 changed files with 2885 additions and 2350 deletions
|
@ -8,7 +8,8 @@ function __fish_describe_command -d "Command used to find descriptions for comma
|
||||||
# TODO: stop interpolating argv into regex, and remove this hack.
|
# TODO: stop interpolating argv into regex, and remove this hack.
|
||||||
string match --quiet --regex '^[a-zA-Z0-9_ ]+$' -- "$argv"
|
string match --quiet --regex '^[a-zA-Z0-9_ ]+$' -- "$argv"
|
||||||
or return
|
or return
|
||||||
type -q apropos; or return
|
type -q apropos
|
||||||
|
or return
|
||||||
apropos $argv 2>/dev/null | awk -v FS=" +- +" '{
|
apropos $argv 2>/dev/null | awk -v FS=" +- +" '{
|
||||||
split($1, names, ", ");
|
split($1, names, ", ");
|
||||||
for (name in names)
|
for (name in names)
|
||||||
|
|
|
@ -73,18 +73,23 @@ function __fish_print_help --description "Print help message for the specified f
|
||||||
# Remove man's bolding
|
# Remove man's bolding
|
||||||
set -l name (string replace -ra '(.)'\b'.' '$1' -- $line)
|
set -l name (string replace -ra '(.)'\b'.' '$1' -- $line)
|
||||||
# We start after we have the name
|
# We start after we have the name
|
||||||
contains -- $name NAME; and set have_name 1; and continue
|
contains -- $name NAME
|
||||||
|
and set have_name 1
|
||||||
|
and continue
|
||||||
# We ignore the SYNOPSIS header
|
# We ignore the SYNOPSIS header
|
||||||
contains -- $name SYNOPSIS; and continue
|
contains -- $name SYNOPSIS
|
||||||
|
and continue
|
||||||
# Everything after COPYRIGHT is useless
|
# Everything after COPYRIGHT is useless
|
||||||
contains -- $name COPYRIGHT; and break
|
contains -- $name COPYRIGHT
|
||||||
|
and break
|
||||||
|
|
||||||
# not leading space, and not empty, so must contain a non-space
|
# not leading space, and not empty, so must contain a non-space
|
||||||
# in the first column. That makes it a header/footer.
|
# in the first column. That makes it a header/footer.
|
||||||
set line_type meta
|
set line_type meta
|
||||||
end
|
end
|
||||||
|
|
||||||
set -q have_name[1]; or continue
|
set -q have_name[1]
|
||||||
|
or continue
|
||||||
switch $state
|
switch $state
|
||||||
case normal
|
case normal
|
||||||
switch $line_type
|
switch $line_type
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
# Use --installed to limit to installed packages only
|
# Use --installed to limit to installed packages only
|
||||||
function __fish_print_packages
|
function __fish_print_packages
|
||||||
argparse --name=__fish_print_packages 'i/installed' -- $argv
|
argparse --name=__fish_print_packages 'i/installed' -- $argv
|
||||||
or return;
|
or return
|
||||||
|
|
||||||
|
|
||||||
set -l only_installed 1
|
set -l only_installed 1
|
||||||
if not set -q _flag_installed
|
if not set -q _flag_installed
|
||||||
|
|
|
@ -16,7 +16,7 @@ set -g fish_prompt_git_status_renamed '➜'
|
||||||
set -g fish_prompt_git_status_copied '⇒'
|
set -g fish_prompt_git_status_copied '⇒'
|
||||||
set -g fish_prompt_git_status_deleted '✖'
|
set -g fish_prompt_git_status_deleted '✖'
|
||||||
set -g fish_prompt_git_status_untracked '?'
|
set -g fish_prompt_git_status_untracked '?'
|
||||||
set -g fish_prompt_git_status_unmerged '!'
|
set -g fish_prompt_git_status_unmerged !
|
||||||
|
|
||||||
set -g fish_prompt_git_status_order added modified renamed copied deleted untracked unmerged
|
set -g fish_prompt_git_status_order added modified renamed copied deleted untracked unmerged
|
||||||
|
|
||||||
|
|
|
@ -33,23 +33,30 @@ function _fish_systemctl --description 'Call systemctl with some options from th
|
||||||
help reset-failed list-dependencies list-units revert add-{wants,requires} edit
|
help reset-failed list-dependencies list-units revert add-{wants,requires} edit
|
||||||
case enable
|
case enable
|
||||||
# This will only work for "list-unit-files", but won't print an error for "list-units".
|
# This will only work for "list-unit-files", but won't print an error for "list-units".
|
||||||
set -q _flag_state; or set _flag_state disabled
|
set -q _flag_state
|
||||||
|
or set _flag_state disabled
|
||||||
case disable
|
case disable
|
||||||
set -q _flag_state; or set _flag_state enabled
|
set -q _flag_state
|
||||||
|
or set _flag_state enabled
|
||||||
case start
|
case start
|
||||||
# Running `start` on an already started unit isn't an _error_, but useless.
|
# Running `start` on an already started unit isn't an _error_, but useless.
|
||||||
set -q _flag_state; or set _flag_state dead,failed
|
set -q _flag_state
|
||||||
|
or set _flag_state dead,failed
|
||||||
case mask
|
case mask
|
||||||
set -q _flag_state; or set _flag_state loaded
|
set -q _flag_state
|
||||||
|
or set _flag_state loaded
|
||||||
case unmask
|
case unmask
|
||||||
set -q _flag_state; or set _flag_state masked
|
set -q _flag_state
|
||||||
|
or set _flag_state masked
|
||||||
case stop kill
|
case stop kill
|
||||||
# TODO: Is "kill" useful on other unit types?
|
# TODO: Is "kill" useful on other unit types?
|
||||||
# Running as the catch-all, "mounted" for .mount units, "active" for .target.
|
# Running as the catch-all, "mounted" for .mount units, "active" for .target.
|
||||||
set -q _flag_state; or set _flag_state running,mounted,active
|
set -q _flag_state
|
||||||
|
or set _flag_state running,mounted,active
|
||||||
case isolate set-default
|
case isolate set-default
|
||||||
# These only take one unit.
|
# These only take one unit.
|
||||||
set -q argv[1]; and return
|
set -q argv[1]
|
||||||
|
and return
|
||||||
case list-sockets
|
case list-sockets
|
||||||
set _flag_type socket
|
set _flag_type socket
|
||||||
case list-timers
|
case list-timers
|
||||||
|
@ -65,11 +72,16 @@ function _fish_systemctl --description 'Call systemctl with some options from th
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add the flags back so we can pass them to our systemctl invocations.
|
# Add the flags back so we can pass them to our systemctl invocations.
|
||||||
set -q _flag_type; and set passflags $passflags --type=$_flag_type
|
set -q _flag_type
|
||||||
set -q _flag_state; and set passflags $passflags --state=$_flag_state
|
and set passflags $passflags --type=$_flag_type
|
||||||
set -q _flag_property; and set passflags $passflags --property=$_flag_property
|
set -q _flag_state
|
||||||
set -q _flag_machine; and set passflags $passflags --machine=$_flag_machine
|
and set passflags $passflags --state=$_flag_state
|
||||||
set -q _flag_host; and set passflags $passflags --host=$_flag_host
|
set -q _flag_property
|
||||||
|
and set passflags $passflags --property=$_flag_property
|
||||||
|
set -q _flag_machine
|
||||||
|
and set passflags $passflags --machine=$_flag_machine
|
||||||
|
set -q _flag_host
|
||||||
|
and set passflags $passflags --host=$_flag_host
|
||||||
|
|
||||||
# Output looks like
|
# Output looks like
|
||||||
# systemd-tmpfiles-clean.timer [more whitespace] loaded active waiting Daily Cleanup[...]
|
# systemd-tmpfiles-clean.timer [more whitespace] loaded active waiting Daily Cleanup[...]
|
||||||
|
|
|
@ -53,12 +53,14 @@ function abbr --description "Manage abbreviations"
|
||||||
else if set -q _flag_query[1]
|
else if set -q _flag_query[1]
|
||||||
# "--query": Check if abbrs exist.
|
# "--query": Check if abbrs exist.
|
||||||
# If we don't have an argument, it's an automatic failure.
|
# If we don't have an argument, it's an automatic failure.
|
||||||
set -q argv[1]; or return 1
|
set -q argv[1]
|
||||||
|
or return 1
|
||||||
set -l escaped _fish_abbr_(string escape --style=var -- $argv)
|
set -l escaped _fish_abbr_(string escape --style=var -- $argv)
|
||||||
# We return 0 if any arg exists, whereas `set -q` returns the number of undefined arguments.
|
# We return 0 if any arg exists, whereas `set -q` returns the number of undefined arguments.
|
||||||
# But we should be consistent with `type -q` and `command -q`.
|
# But we should be consistent with `type -q` and `command -q`.
|
||||||
for var in $escaped
|
for var in $escaped
|
||||||
set -q $escaped; and return 0
|
set -q $escaped
|
||||||
|
and return 0
|
||||||
end
|
end
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
function fish_clipboard_copy
|
function fish_clipboard_copy
|
||||||
# Copy the current selection, or the entire commandline if that is empty.
|
# Copy the current selection, or the entire commandline if that is empty.
|
||||||
set -l cmdline (commandline --current-selection)
|
set -l cmdline (commandline --current-selection)
|
||||||
test -n "$cmdline"; or set cmdline (commandline)
|
test -n "$cmdline"
|
||||||
|
or set cmdline (commandline)
|
||||||
if type -q pbcopy
|
if type -q pbcopy
|
||||||
printf '%s\n' $cmdline | pbcopy
|
printf '%s\n' $cmdline | pbcopy
|
||||||
else if type -q xsel
|
else if type -q xsel
|
||||||
|
|
|
@ -454,7 +454,8 @@ function fish_git_prompt --description "Prompt function for Git"
|
||||||
set b (string replace refs/heads/ '' -- $b)
|
set b (string replace refs/heads/ '' -- $b)
|
||||||
set -q __fish_git_prompt_shorten_branch_char_suffix
|
set -q __fish_git_prompt_shorten_branch_char_suffix
|
||||||
or set -l __fish_git_prompt_shorten_branch_char_suffix "…"
|
or set -l __fish_git_prompt_shorten_branch_char_suffix "…"
|
||||||
if string match -qr '^\d+$' "$__fish_git_prompt_shorten_branch_len"; and test (string length "$b") -gt $__fish_git_prompt_shorten_branch_len
|
if string match -qr '^\d+$' "$__fish_git_prompt_shorten_branch_len"
|
||||||
|
and test (string length "$b") -gt $__fish_git_prompt_shorten_branch_len
|
||||||
set b (string sub -l "$__fish_git_prompt_shorten_branch_len" "$b")"$__fish_git_prompt_shorten_branch_char_suffix"
|
set b (string sub -l "$__fish_git_prompt_shorten_branch_len" "$b")"$__fish_git_prompt_shorten_branch_char_suffix"
|
||||||
end
|
end
|
||||||
if test -n "$b"
|
if test -n "$b"
|
||||||
|
@ -548,7 +549,8 @@ function __fish_git_prompt_informative_status
|
||||||
set -l untrackedfiles (command git ls-files --others --exclude-standard | count)
|
set -l untrackedfiles (command git ls-files --others --exclude-standard | count)
|
||||||
set -l stashstate 0
|
set -l stashstate 0
|
||||||
set -l stashfile "$argv[1]/logs/refs/stash"
|
set -l stashfile "$argv[1]/logs/refs/stash"
|
||||||
if set -q __fish_git_prompt_showstashstate; and test -e "$stashfile"
|
if set -q __fish_git_prompt_showstashstate
|
||||||
|
and test -e "$stashfile"
|
||||||
set stashstate (count < $stashfile)
|
set stashstate (count < $stashfile)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ set -g fish_prompt_hg_status_modified '*'
|
||||||
set -g fish_prompt_hg_status_copied '⇒'
|
set -g fish_prompt_hg_status_copied '⇒'
|
||||||
set -g fish_prompt_hg_status_deleted '✖'
|
set -g fish_prompt_hg_status_deleted '✖'
|
||||||
set -g fish_prompt_hg_status_untracked '?'
|
set -g fish_prompt_hg_status_untracked '?'
|
||||||
set -g fish_prompt_hg_status_unmerged '!'
|
set -g fish_prompt_hg_status_unmerged !
|
||||||
|
|
||||||
set -g fish_prompt_hg_status_order added modified copied deleted untracked unmerged
|
set -g fish_prompt_hg_status_order added modified copied deleted untracked unmerged
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ function __yarn_installed_packages
|
||||||
|
|
||||||
if set -l python (__fish_anypython)
|
if set -l python (__fish_anypython)
|
||||||
$python -c 'import json, sys; data = json.load(sys.stdin);
|
$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
|
print("\n".join(data["dependencies"])); print("\n".join(data["devDependencies"]))' <$package_json 2>/dev/null
|
||||||
else if type -q jq
|
else if type -q jq
|
||||||
jq -r '.dependencies as $a1 | .devDependencies as $a2 | ($a1 + $a2) | to_entries[] | .key' $package_json
|
jq -r '.dependencies as $a1 | .devDependencies as $a2 | ($a1 + $a2) | to_entries[] | .key' $package_json
|
||||||
else
|
else
|
||||||
|
|
|
@ -37,7 +37,7 @@ set -g __fish_svn_prompt_char_unversioned_external_color --underline cyan
|
||||||
set -g __fish_svn_prompt_char_unversioned_display '?'
|
set -g __fish_svn_prompt_char_unversioned_display '?'
|
||||||
set -g __fish_svn_prompt_char_unversioned_color purple
|
set -g __fish_svn_prompt_char_unversioned_color purple
|
||||||
|
|
||||||
set -g __fish_svn_prompt_char_missing_display '!'
|
set -g __fish_svn_prompt_char_missing_display !
|
||||||
set -g __fish_svn_prompt_char_missing_color yellow
|
set -g __fish_svn_prompt_char_missing_color yellow
|
||||||
|
|
||||||
set -g __fish_svn_prompt_char_versioned_obstructed_display '~'
|
set -g __fish_svn_prompt_char_versioned_obstructed_display '~'
|
||||||
|
|
|
@ -69,7 +69,8 @@ function help --description 'Show help for the fish shell'
|
||||||
set fish_browser cygstart
|
set fish_browser cygstart
|
||||||
# If xdg-open is available, just use that
|
# If xdg-open is available, just use that
|
||||||
# but only if an X session is running
|
# but only if an X session is running
|
||||||
else if type -q xdg-open; and set -q -x DISPLAY
|
else if type -q xdg-open
|
||||||
|
and set -q -x DISPLAY
|
||||||
set fish_browser xdg-open
|
set fish_browser xdg-open
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -158,7 +159,7 @@ function help --description 'Show help for the fish shell'
|
||||||
or set -l TMPDIR /tmp
|
or set -l TMPDIR /tmp
|
||||||
set -l tmpdir (mktemp -d $TMPDIR/help.XXXXXX)
|
set -l tmpdir (mktemp -d $TMPDIR/help.XXXXXX)
|
||||||
set -l tmpname $tmpdir/help.html
|
set -l tmpname $tmpdir/help.html
|
||||||
echo '<meta http-equiv="refresh" content="0;URL=\''$clean_url'\'" />' > $tmpname
|
echo '<meta http-equiv="refresh" content="0;URL=\''$clean_url'\'" />' >$tmpname
|
||||||
set page_url file://$tmpname
|
set page_url file://$tmpname
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,7 +16,7 @@ for opt in --color=auto -G --color -F
|
||||||
command ls $opt $argv
|
command ls $opt $argv
|
||||||
end
|
end
|
||||||
|
|
||||||
if [ $opt = --color=auto ] &&! set -qx LS_COLORS && set -l cmd (command -s {g,}dircolors)[1]
|
if [ $opt = --color=auto ] && ! set -qx LS_COLORS && set -l cmd (command -s {g,}dircolors)[1]
|
||||||
set -l colorfile
|
set -l colorfile
|
||||||
for file in ~/.dir_colors ~/.dircolors /etc/DIR_COLORS
|
for file in ~/.dir_colors ~/.dircolors /etc/DIR_COLORS
|
||||||
if test -f $file
|
if test -f $file
|
||||||
|
|
|
@ -61,7 +61,8 @@ function type --description 'Print the type of a command'
|
||||||
switch $func_path
|
switch $func_path
|
||||||
case "n/a"
|
case "n/a"
|
||||||
case "stdin"
|
case "stdin"
|
||||||
break;
|
break
|
||||||
|
|
||||||
case "*"
|
case "*"
|
||||||
echo $func_path
|
echo $func_path
|
||||||
end
|
end
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -13,21 +13,25 @@ from sphinx.errors import SphinxError, SphinxWarning
|
||||||
|
|
||||||
# -- Helper functions --------------------------------------------------------
|
# -- Helper functions --------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def strip_ext(path):
|
def strip_ext(path):
|
||||||
""" Remove the extension from a path. """
|
""" Remove the extension from a path. """
|
||||||
return os.path.splitext(path)[0]
|
return os.path.splitext(path)[0]
|
||||||
|
|
||||||
|
|
||||||
# -- Load our Pygments lexer -------------------------------------------------
|
# -- Load our Pygments lexer -------------------------------------------------
|
||||||
def setup(app):
|
def setup(app):
|
||||||
from sphinx.highlighting import lexers
|
from sphinx.highlighting import lexers
|
||||||
|
|
||||||
this_dir = os.path.dirname(os.path.realpath(__file__))
|
this_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
fish_indent_lexer = pygments.lexers.load_lexer_from_file(
|
fish_indent_lexer = pygments.lexers.load_lexer_from_file(
|
||||||
os.path.join(this_dir, 'fish_indent_lexer.py'),
|
os.path.join(this_dir, "fish_indent_lexer.py"), lexername="FishIndentLexer"
|
||||||
lexername='FishIndentLexer')
|
)
|
||||||
lexers['fish-docs-samples'] = fish_indent_lexer
|
lexers["fish-docs-samples"] = fish_indent_lexer
|
||||||
|
|
||||||
|
|
||||||
# The default language to assume
|
# The default language to assume
|
||||||
highlight_language = 'fish-docs-samples'
|
highlight_language = "fish-docs-samples"
|
||||||
|
|
||||||
# -- Path setup --------------------------------------------------------------
|
# -- Path setup --------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -42,14 +46,14 @@ highlight_language = 'fish-docs-samples'
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
project = 'fish-shell'
|
project = "fish-shell"
|
||||||
copyright = '2019, fish-shell developers'
|
copyright = "2019, fish-shell developers"
|
||||||
author = 'fish-shell developers'
|
author = "fish-shell developers"
|
||||||
|
|
||||||
# The short X.Y version
|
# The short X.Y version
|
||||||
version = '3.1'
|
version = "3.1"
|
||||||
# The full version, including alpha/beta/rc tags
|
# The full version, including alpha/beta/rc tags
|
||||||
release = '3.1.0'
|
release = "3.1.0"
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
|
@ -61,20 +65,19 @@ release = '3.1.0'
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = [
|
extensions = []
|
||||||
]
|
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
# The suffix(es) of source filenames.
|
# The suffix(es) of source filenames.
|
||||||
# You can specify multiple suffix as a list of string:
|
# You can specify multiple suffix as a list of string:
|
||||||
#
|
#
|
||||||
# source_suffix = ['.rst', '.md']
|
# source_suffix = ['.rst', '.md']
|
||||||
source_suffix = '.rst'
|
source_suffix = ".rst"
|
||||||
|
|
||||||
# The master toctree document.
|
# The master toctree document.
|
||||||
master_doc = 'index'
|
master_doc = "index"
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@ -98,7 +101,7 @@ pygments_style = None
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
# !!! If you change this you also need to update the @import at the top
|
# !!! If you change this you also need to update the @import at the top
|
||||||
# of _static/fish-syntax-style.css
|
# of _static/fish-syntax-style.css
|
||||||
html_theme = 'nature'
|
html_theme = "nature"
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
|
@ -109,7 +112,7 @@ html_theme = 'nature'
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = ['_static']
|
html_static_path = ["_static"]
|
||||||
|
|
||||||
# Custom sidebar templates, must be a dictionary that maps document names
|
# Custom sidebar templates, must be a dictionary that maps document names
|
||||||
# to template names.
|
# to template names.
|
||||||
|
@ -119,13 +122,13 @@ html_static_path = ['_static']
|
||||||
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
||||||
# 'searchbox.html']``.
|
# 'searchbox.html']``.
|
||||||
#
|
#
|
||||||
html_sidebars = { '**': ['globaltoc.html', 'localtoc.html', 'searchbox.html'] }
|
html_sidebars = {"**": ["globaltoc.html", "localtoc.html", "searchbox.html"]}
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTMLHelp output ---------------------------------------------
|
# -- Options for HTMLHelp output ---------------------------------------------
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = 'fish-shelldoc'
|
htmlhelp_basename = "fish-shelldoc"
|
||||||
|
|
||||||
|
|
||||||
# -- Options for LaTeX output ------------------------------------------------
|
# -- Options for LaTeX output ------------------------------------------------
|
||||||
|
@ -134,15 +137,12 @@ latex_elements = {
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
#
|
#
|
||||||
# 'papersize': 'letterpaper',
|
# 'papersize': 'letterpaper',
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
#
|
#
|
||||||
# 'pointsize': '10pt',
|
# 'pointsize': '10pt',
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
# Additional stuff for the LaTeX preamble.
|
||||||
#
|
#
|
||||||
# 'preamble': '',
|
# 'preamble': '',
|
||||||
|
|
||||||
# Latex figure (float) alignment
|
# Latex figure (float) alignment
|
||||||
#
|
#
|
||||||
# 'figure_align': 'htbp',
|
# 'figure_align': 'htbp',
|
||||||
|
@ -152,34 +152,36 @@ latex_elements = {
|
||||||
# (source start file, target name, title,
|
# (source start file, target name, title,
|
||||||
# author, documentclass [howto, manual, or own class]).
|
# author, documentclass [howto, manual, or own class]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
(master_doc, 'fish-shell.tex', 'fish-shell Documentation',
|
(
|
||||||
'fish-shell developers', 'manual'),
|
master_doc,
|
||||||
|
"fish-shell.tex",
|
||||||
|
"fish-shell Documentation",
|
||||||
|
"fish-shell developers",
|
||||||
|
"manual",
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output ------------------------------------------
|
# -- Options for manual page output ------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def get_command_description(path, name):
|
def get_command_description(path, name):
|
||||||
""" Return the description for a command, by parsing its synopsis line """
|
""" Return the description for a command, by parsing its synopsis line """
|
||||||
with open(path) as fd:
|
with open(path) as fd:
|
||||||
for line in fd:
|
for line in fd:
|
||||||
if line.startswith(name + " - "):
|
if line.startswith(name + " - "):
|
||||||
_, desc = line.split(' - ', 1)
|
_, desc = line.split(" - ", 1)
|
||||||
return desc.strip()
|
return desc.strip()
|
||||||
raise SphinxWarning('No description in file %s' % os.path.basename(path))
|
raise SphinxWarning("No description in file %s" % os.path.basename(path))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [(master_doc, "fish", "fish-shell Documentation", [author], 1)]
|
||||||
(master_doc, 'fish', 'fish-shell Documentation',
|
for path in sorted(glob.glob("cmds/*")):
|
||||||
[author], 1)
|
|
||||||
]
|
|
||||||
for path in sorted(glob.glob('cmds/*')):
|
|
||||||
docname = strip_ext(path)
|
docname = strip_ext(path)
|
||||||
cmd = os.path.basename(docname)
|
cmd = os.path.basename(docname)
|
||||||
man_pages.append((docname, cmd, get_command_description(path, cmd), '', 1))
|
man_pages.append((docname, cmd, get_command_description(path, cmd), "", 1))
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Texinfo output ----------------------------------------------
|
# -- Options for Texinfo output ----------------------------------------------
|
||||||
|
@ -188,9 +190,15 @@ for path in sorted(glob.glob('cmds/*')):
|
||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
(master_doc, 'fish-shell', 'fish-shell Documentation',
|
(
|
||||||
author, 'fish-shell', 'One line description of project.',
|
master_doc,
|
||||||
'Miscellaneous'),
|
"fish-shell",
|
||||||
|
"fish-shell Documentation",
|
||||||
|
author,
|
||||||
|
"fish-shell",
|
||||||
|
"One line description of project.",
|
||||||
|
"Miscellaneous",
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -209,7 +217,7 @@ epub_title = project
|
||||||
# epub_uid = ''
|
# epub_uid = ''
|
||||||
|
|
||||||
# A list of files that should not be packed into the epub file.
|
# A list of files that should not be packed into the epub file.
|
||||||
epub_exclude_files = ['search.html']
|
epub_exclude_files = ["search.html"]
|
||||||
|
|
||||||
# Disable smart-quotes to prevent double dashes from becoming emdashes.
|
# Disable smart-quotes to prevent double dashes from becoming emdashes.
|
||||||
smartquotes = False
|
smartquotes = False
|
||||||
|
|
|
@ -91,9 +91,9 @@ def tokenize_fish_command(code, offset):
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
universal_newlines=False,
|
universal_newlines=False,
|
||||||
)
|
)
|
||||||
stdout, _ = proc.communicate(code.encode('utf-8'))
|
stdout, _ = proc.communicate(code.encode("utf-8"))
|
||||||
result = []
|
result = []
|
||||||
for line in stdout.decode('utf-8').splitlines():
|
for line in stdout.decode("utf-8").splitlines():
|
||||||
start, end, role = line.split(",")
|
start, end, role = line.split(",")
|
||||||
start, end = int(start), int(end)
|
start, end = int(start), int(end)
|
||||||
value = code[start:end]
|
value = code[start:end]
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
|
@ -59,14 +59,11 @@ struct argparse_cmd_opts_t {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const wchar_t *const short_options = L"+:hn:six:N:X:";
|
static const wchar_t *const short_options = L"+:hn:six:N:X:";
|
||||||
static const struct woption long_options[] = {{L"stop-nonopt", no_argument, NULL, 's'},
|
static const struct woption long_options[] = {
|
||||||
{L"ignore-unknown", no_argument, NULL, 'i'},
|
{L"stop-nonopt", no_argument, NULL, 's'}, {L"ignore-unknown", no_argument, NULL, 'i'},
|
||||||
{L"name", required_argument, NULL, 'n'},
|
{L"name", required_argument, NULL, 'n'}, {L"exclusive", required_argument, NULL, 'x'},
|
||||||
{L"exclusive", required_argument, NULL, 'x'},
|
{L"help", no_argument, NULL, 'h'}, {L"min-args", required_argument, NULL, 'N'},
|
||||||
{L"help", no_argument, NULL, 'h'},
|
{L"max-args", required_argument, NULL, 'X'}, {NULL, 0, NULL, 0}};
|
||||||
{L"min-args", required_argument, NULL, 'N'},
|
|
||||||
{L"max-args", required_argument, NULL, 'X'},
|
|
||||||
{NULL, 0, NULL, 0}};
|
|
||||||
|
|
||||||
// Check if any pair of mutually exclusive options was seen. Note that since every option must have
|
// Check if any pair of mutually exclusive options was seen. Note that since every option must have
|
||||||
// a short name we only need to check those.
|
// a short name we only need to check those.
|
||||||
|
@ -584,12 +581,12 @@ static int argparse_parse_flags(parser_t &parser, argparse_cmd_opts_t &opts,
|
||||||
// A non-option argument.
|
// A non-option argument.
|
||||||
// We use `-` as the first option-string-char to disable GNU getopt's reordering,
|
// We use `-` as the first option-string-char to disable GNU getopt's reordering,
|
||||||
// otherwise we'd get ignored options first and normal arguments later.
|
// otherwise we'd get ignored options first and normal arguments later.
|
||||||
// E.g. `argparse -i -- -t tango -w` needs to keep `-t tango -w` in $argv, not `-t -w tango`.
|
// E.g. `argparse -i -- -t tango -w` needs to keep `-t tango -w` in $argv, not `-t -w
|
||||||
|
// tango`.
|
||||||
opts.argv.push_back(argv[w.woptind - 1]);
|
opts.argv.push_back(argv[w.woptind - 1]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// It's a recognized flag.
|
// It's a recognized flag.
|
||||||
auto found = opts.options.find(opt);
|
auto found = opts.options.find(opt);
|
||||||
assert(found != opts.options.end());
|
assert(found != opts.options.end());
|
||||||
|
@ -610,7 +607,8 @@ static int argparse_parse_args(argparse_cmd_opts_t &opts, const wcstring_list_t
|
||||||
parser_t &parser, io_streams_t &streams) {
|
parser_t &parser, io_streams_t &streams) {
|
||||||
if (args.empty()) return STATUS_CMD_OK;
|
if (args.empty()) return STATUS_CMD_OK;
|
||||||
|
|
||||||
// "+" means stop at nonopt, "-" means give nonoptions the option character code `1`, and don't reorder.
|
// "+" means stop at nonopt, "-" means give nonoptions the option character code `1`, and don't
|
||||||
|
// reorder.
|
||||||
wcstring short_options = opts.stop_nonopt ? L"+:" : L"-";
|
wcstring short_options = opts.stop_nonopt ? L"+:" : L"-";
|
||||||
std::vector<woption> long_options;
|
std::vector<woption> long_options;
|
||||||
populate_option_strings(opts, &short_options, &long_options);
|
populate_option_strings(opts, &short_options, &long_options);
|
||||||
|
|
|
@ -102,8 +102,8 @@ bool builtin_bind_t::list_one(const wcstring &seq, const wcstring &bind_mode, bo
|
||||||
|
|
||||||
// Overload with both kinds of bindings.
|
// Overload with both kinds of bindings.
|
||||||
// Returns false only if neither exists.
|
// Returns false only if neither exists.
|
||||||
bool builtin_bind_t::list_one(const wcstring &seq, const wcstring &bind_mode, bool user, bool preset,
|
bool builtin_bind_t::list_one(const wcstring &seq, const wcstring &bind_mode, bool user,
|
||||||
io_streams_t &streams) {
|
bool preset, io_streams_t &streams) {
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
if (preset) {
|
if (preset) {
|
||||||
retval |= list_one(seq, bind_mode, false, streams);
|
retval |= list_one(seq, bind_mode, false, streams);
|
||||||
|
@ -151,7 +151,8 @@ void builtin_bind_t::function_names(io_streams_t &streams) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps input_terminfo_get_sequence(), appending the correct error messages as needed.
|
/// Wraps input_terminfo_get_sequence(), appending the correct error messages as needed.
|
||||||
bool builtin_bind_t::get_terminfo_sequence(const wchar_t *seq, wcstring *out_seq, io_streams_t &streams) {
|
bool builtin_bind_t::get_terminfo_sequence(const wchar_t *seq, wcstring *out_seq,
|
||||||
|
io_streams_t &streams) {
|
||||||
if (input_terminfo_get_sequence(seq, out_seq)) {
|
if (input_terminfo_get_sequence(seq, out_seq)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -159,7 +160,8 @@ bool builtin_bind_t::get_terminfo_sequence(const wchar_t *seq, wcstring *out_seq
|
||||||
wcstring eseq = escape_string(seq, 0);
|
wcstring eseq = escape_string(seq, 0);
|
||||||
if (!opts->silent) {
|
if (!opts->silent) {
|
||||||
if (errno == ENOENT) {
|
if (errno == ENOENT) {
|
||||||
streams.err.append_format(_(L"%ls: No key with name '%ls' found\n"), L"bind", eseq.c_str());
|
streams.err.append_format(_(L"%ls: No key with name '%ls' found\n"), L"bind",
|
||||||
|
eseq.c_str());
|
||||||
} else if (errno == EILSEQ) {
|
} else if (errno == EILSEQ) {
|
||||||
streams.err.append_format(_(L"%ls: Key with name '%ls' does not have any mapping\n"),
|
streams.err.append_format(_(L"%ls: Key with name '%ls' does not have any mapping\n"),
|
||||||
L"bind", eseq.c_str());
|
L"bind", eseq.c_str());
|
||||||
|
@ -202,8 +204,8 @@ bool builtin_bind_t::add(const wchar_t *seq, const wchar_t *const *cmds, size_t
|
||||||
/// @param use_terminfo
|
/// @param use_terminfo
|
||||||
/// Whether to look use terminfo -k name
|
/// Whether to look use terminfo -k name
|
||||||
///
|
///
|
||||||
bool builtin_bind_t::erase(wchar_t **seq, bool all, const wchar_t *mode, bool use_terminfo, bool user,
|
bool builtin_bind_t::erase(wchar_t **seq, bool all, const wchar_t *mode, bool use_terminfo,
|
||||||
io_streams_t &streams) {
|
bool user, io_streams_t &streams) {
|
||||||
if (all) {
|
if (all) {
|
||||||
input_mapping_clear(mode, user);
|
input_mapping_clear(mode, user);
|
||||||
return false;
|
return false;
|
||||||
|
@ -228,8 +230,7 @@ bool builtin_bind_t::erase(wchar_t **seq, bool all, const wchar_t *mode, bool us
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool builtin_bind_t::insert(int optind, int argc, wchar_t **argv,
|
bool builtin_bind_t::insert(int optind, int argc, wchar_t **argv, io_streams_t &streams) {
|
||||||
io_streams_t &streams) {
|
|
||||||
wchar_t *cmd = argv[0];
|
wchar_t *cmd = argv[0];
|
||||||
int arg_count = argc - optind;
|
int arg_count = argc - optind;
|
||||||
|
|
||||||
|
@ -242,7 +243,8 @@ bool builtin_bind_t::insert(int optind, int argc, wchar_t **argv,
|
||||||
} else {
|
} else {
|
||||||
// Inserting both on the other hand makes no sense.
|
// Inserting both on the other hand makes no sense.
|
||||||
if (opts->have_preset && opts->have_user) {
|
if (opts->have_preset && opts->have_user) {
|
||||||
streams.err.append_format(BUILTIN_ERR_COMBO2, cmd,
|
streams.err.append_format(
|
||||||
|
BUILTIN_ERR_COMBO2, cmd,
|
||||||
L"--preset and --user can not be used together when inserting bindings.");
|
L"--preset and --user can not be used together when inserting bindings.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,25 +11,25 @@ struct io_streams_t;
|
||||||
struct bind_cmd_opts_t;
|
struct bind_cmd_opts_t;
|
||||||
|
|
||||||
class builtin_bind_t {
|
class builtin_bind_t {
|
||||||
public:
|
public:
|
||||||
int builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv);
|
int builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv);
|
||||||
private:
|
|
||||||
|
private:
|
||||||
bind_cmd_opts_t *opts;
|
bind_cmd_opts_t *opts;
|
||||||
|
|
||||||
void list(const wchar_t *bind_mode, bool user, io_streams_t &streams);
|
void list(const wchar_t *bind_mode, bool user, io_streams_t &streams);
|
||||||
void key_names(bool all, io_streams_t &streams);
|
void key_names(bool all, io_streams_t &streams);
|
||||||
void function_names(io_streams_t &streams);
|
void function_names(io_streams_t &streams);
|
||||||
bool add(const wchar_t *seq, const wchar_t *const *cmds, size_t cmds_len,
|
bool add(const wchar_t *seq, const wchar_t *const *cmds, size_t cmds_len, const wchar_t *mode,
|
||||||
const wchar_t *mode, const wchar_t *sets_mode, bool terminfo, bool user,
|
const wchar_t *sets_mode, bool terminfo, bool user, io_streams_t &streams);
|
||||||
io_streams_t &streams);
|
|
||||||
bool erase(wchar_t **seq, bool all, const wchar_t *mode, bool use_terminfo, bool user,
|
bool erase(wchar_t **seq, bool all, const wchar_t *mode, bool use_terminfo, bool user,
|
||||||
io_streams_t &streams);
|
io_streams_t &streams);
|
||||||
bool get_terminfo_sequence(const wchar_t *seq, wcstring *out_seq, io_streams_t &streams);
|
bool get_terminfo_sequence(const wchar_t *seq, wcstring *out_seq, io_streams_t &streams);
|
||||||
bool insert(int optind, int argc, wchar_t **argv,
|
bool insert(int optind, int argc, wchar_t **argv, io_streams_t &streams);
|
||||||
io_streams_t &streams);
|
|
||||||
void list_modes(io_streams_t &streams);
|
void list_modes(io_streams_t &streams);
|
||||||
bool list_one(const wcstring &seq, const wcstring &bind_mode, bool user, io_streams_t &streams);
|
bool list_one(const wcstring &seq, const wcstring &bind_mode, bool user, io_streams_t &streams);
|
||||||
bool list_one(const wcstring &seq, const wcstring &bind_mode, bool user, bool preset, io_streams_t &streams);
|
bool list_one(const wcstring &seq, const wcstring &bind_mode, bool user, bool preset,
|
||||||
|
io_streams_t &streams);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline int builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
inline int builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
|
|
|
@ -20,8 +20,8 @@ struct builtin_cmd_opts_t {
|
||||||
bool query = false;
|
bool query = false;
|
||||||
};
|
};
|
||||||
static const wchar_t *const short_options = L":hnq";
|
static const wchar_t *const short_options = L":hnq";
|
||||||
static const struct woption long_options[] = {
|
static const struct woption long_options[] = {{L"help", no_argument, NULL, 'h'},
|
||||||
{L"help", no_argument, NULL, 'h'}, {L"names", no_argument, NULL, 'n'},
|
{L"names", no_argument, NULL, 'n'},
|
||||||
{L"query", no_argument, NULL, 'q'},
|
{L"query", no_argument, NULL, 'q'},
|
||||||
{NULL, 0, NULL, 0}};
|
{NULL, 0, NULL, 0}};
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
#ifndef FISH_BUILTIN_COMMANDLINE_H
|
#ifndef FISH_BUILTIN_COMMANDLINE_H
|
||||||
#define FISH_BUILTIN_COMMANDLINE_H
|
#define FISH_BUILTIN_COMMANDLINE_H
|
||||||
|
|
||||||
#include <cwchar>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
class parser_t;
|
class parser_t;
|
||||||
|
|
||||||
|
|
|
@ -263,7 +263,6 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
// Use one left-over arg as the do-complete argument
|
// Use one left-over arg as the do-complete argument
|
||||||
// to enable `complete -C "git check"`.
|
// to enable `complete -C "git check"`.
|
||||||
if (do_complete && !have_do_complete_param && argc == w.woptind + 1) {
|
if (do_complete && !have_do_complete_param && argc == w.woptind + 1) {
|
||||||
|
|
||||||
do_complete_param = argv[argc - 1];
|
do_complete_param = argv[argc - 1];
|
||||||
have_do_complete_param = true;
|
have_do_complete_param = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -306,7 +305,7 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
if (do_complete) {
|
if (do_complete) {
|
||||||
if (!have_do_complete_param) {
|
if (!have_do_complete_param) {
|
||||||
// No argument given, try to use the current commandline.
|
// No argument given, try to use the current commandline.
|
||||||
const wchar_t* cmd = reader_get_buffer();
|
const wchar_t *cmd = reader_get_buffer();
|
||||||
if (cmd == NULL) {
|
if (cmd == NULL) {
|
||||||
// This corresponds to using 'complete -C' in non-interactive mode.
|
// This corresponds to using 'complete -C' in non-interactive mode.
|
||||||
// See #2361 .
|
// See #2361 .
|
||||||
|
|
|
@ -18,7 +18,7 @@ struct echo_cmd_opts_t {
|
||||||
bool interpret_special_chars = false;
|
bool interpret_special_chars = false;
|
||||||
};
|
};
|
||||||
static const wchar_t *const short_options = L"+:Eens";
|
static const wchar_t *const short_options = L"+:Eens";
|
||||||
static const struct woption * const long_options = NULL;
|
static const struct woption *const long_options = NULL;
|
||||||
|
|
||||||
static int parse_cmd_opts(echo_cmd_opts_t &opts, int *optind, int argc, wchar_t **argv,
|
static int parse_cmd_opts(echo_cmd_opts_t &opts, int *optind, int argc, wchar_t **argv,
|
||||||
parser_t &parser, io_streams_t &streams) {
|
parser_t &parser, io_streams_t &streams) {
|
||||||
|
@ -89,7 +89,9 @@ static unsigned int builtin_echo_digit(wchar_t wc, unsigned int base) {
|
||||||
return 6;
|
return 6;
|
||||||
case L'7':
|
case L'7':
|
||||||
return 7;
|
return 7;
|
||||||
default: { break; }
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base != 16) return UINT_MAX;
|
if (base != 16) return UINT_MAX;
|
||||||
|
@ -117,7 +119,9 @@ static unsigned int builtin_echo_digit(wchar_t wc, unsigned int base) {
|
||||||
case L'f':
|
case L'f':
|
||||||
case L'F':
|
case L'F':
|
||||||
return 15;
|
return 15;
|
||||||
default: { break; }
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return UINT_MAX;
|
return UINT_MAX;
|
||||||
|
|
|
@ -99,7 +99,7 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const wcstring ft = tok_first(job->command());
|
const wcstring ft = tok_first(job->command());
|
||||||
//For compatibility with fish 2.0's $_, now replaced with `status current-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);
|
if (!ft.empty()) parser.vars().set_one(L"_", ENV_EXPORT, ft);
|
||||||
reader_write_title(job->command(), parser);
|
reader_write_title(job->command(), parser);
|
||||||
|
|
||||||
|
|
|
@ -40,13 +40,18 @@ struct functions_cmd_opts_t {
|
||||||
wchar_t *description = NULL;
|
wchar_t *description = NULL;
|
||||||
};
|
};
|
||||||
static const wchar_t *const short_options = L":HDacd:ehnqv";
|
static const wchar_t *const short_options = L":HDacd:ehnqv";
|
||||||
static const struct woption long_options[] = {
|
static const struct woption long_options[] = {{L"erase", no_argument, NULL, 'e'},
|
||||||
{L"erase", no_argument, NULL, 'e'}, {L"description", required_argument, NULL, 'd'},
|
{L"description", required_argument, NULL, 'd'},
|
||||||
{L"names", no_argument, NULL, 'n'}, {L"all", no_argument, NULL, 'a'},
|
{L"names", no_argument, NULL, 'n'},
|
||||||
{L"help", no_argument, NULL, 'h'}, {L"query", no_argument, NULL, 'q'},
|
{L"all", no_argument, NULL, 'a'},
|
||||||
{L"copy", no_argument, NULL, 'c'}, {L"details", no_argument, NULL, 'D'},
|
{L"help", no_argument, NULL, 'h'},
|
||||||
{L"verbose", no_argument, NULL, 'v'}, {L"handlers", no_argument, NULL, 'H'},
|
{L"query", no_argument, NULL, 'q'},
|
||||||
{L"handlers-type", required_argument, NULL, 't'}, {NULL, 0, NULL, 0}};
|
{L"copy", no_argument, NULL, 'c'},
|
||||||
|
{L"details", no_argument, NULL, 'D'},
|
||||||
|
{L"verbose", no_argument, NULL, 'v'},
|
||||||
|
{L"handlers", no_argument, NULL, 'H'},
|
||||||
|
{L"handlers-type", required_argument, NULL, 't'},
|
||||||
|
{NULL, 0, NULL, 0}};
|
||||||
|
|
||||||
static int parse_cmd_opts(functions_cmd_opts_t &opts, int *optind, //!OCLINT(high ncss method)
|
static int parse_cmd_opts(functions_cmd_opts_t &opts, int *optind, //!OCLINT(high ncss method)
|
||||||
int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) {
|
int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) {
|
||||||
|
@ -327,8 +332,9 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
maybe_t<event_type_t> type_filter;
|
maybe_t<event_type_t> type_filter;
|
||||||
if (opts.handlers_type) {
|
if (opts.handlers_type) {
|
||||||
type_filter = event_type_for_name(opts.handlers_type);
|
type_filter = event_type_for_name(opts.handlers_type);
|
||||||
if (! type_filter) {
|
if (!type_filter) {
|
||||||
streams.err.append_format(_(L"%ls: Expected generic | variable | signal | exit | job-id for --handlers-type\n"),
|
streams.err.append_format(_(L"%ls: Expected generic | variable | signal | exit | "
|
||||||
|
L"job-id for --handlers-type\n"),
|
||||||
cmd);
|
cmd);
|
||||||
return STATUS_INVALID_ARGS;
|
return STATUS_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,8 +117,7 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
int print_last = 0;
|
int print_last = 0;
|
||||||
|
|
||||||
static const wchar_t *const short_options = L":cghlpq";
|
static const wchar_t *const short_options = L":cghlpq";
|
||||||
static const struct woption long_options[] = {
|
static const struct woption long_options[] = {{L"command", no_argument, NULL, 'c'},
|
||||||
{L"command", no_argument, NULL, 'c'},
|
|
||||||
{L"group", no_argument, NULL, 'g'},
|
{L"group", no_argument, NULL, 'g'},
|
||||||
{L"help", no_argument, NULL, 'h'},
|
{L"help", no_argument, NULL, 'h'},
|
||||||
{L"last", no_argument, NULL, 'l'},
|
{L"last", no_argument, NULL, 'l'},
|
||||||
|
@ -189,15 +188,16 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
int jobId = -1;
|
int jobId = -1;
|
||||||
jobId = fish_wcstoi(argv[i] + 1);
|
jobId = fish_wcstoi(argv[i] + 1);
|
||||||
if (errno || jobId < -1) {
|
if (errno || jobId < -1) {
|
||||||
streams.err.append_format(_(L"%ls: '%ls' is not a valid job id"), cmd, argv[i]);
|
streams.err.append_format(_(L"%ls: '%ls' is not a valid job id"), cmd,
|
||||||
|
argv[i]);
|
||||||
return STATUS_INVALID_ARGS;
|
return STATUS_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
j = job_t::from_job_id(jobId);
|
j = job_t::from_job_id(jobId);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
int pid = fish_wcstoi(argv[i]);
|
int pid = fish_wcstoi(argv[i]);
|
||||||
if (errno || pid < 0) {
|
if (errno || pid < 0) {
|
||||||
streams.err.append_format(_(L"%ls: '%ls' is not a valid process id\n"), cmd, argv[i]);
|
streams.err.append_format(_(L"%ls: '%ls' is not a valid process id\n"), cmd,
|
||||||
|
argv[i]);
|
||||||
return STATUS_INVALID_ARGS;
|
return STATUS_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
j = job_t::from_pid(pid);
|
j = job_t::from_pid(pid);
|
||||||
|
@ -215,7 +215,8 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
for (const auto &j : jobs()) {
|
for (const auto &j : jobs()) {
|
||||||
// Ignore unconstructed jobs, i.e. ourself.
|
// Ignore unconstructed jobs, i.e. ourself.
|
||||||
if (j->is_visible()) {
|
if (j->is_visible()) {
|
||||||
builtin_jobs_print(j.get(), mode, !found && !streams.out_is_redirected, streams);
|
builtin_jobs_print(j.get(), mode, !found && !streams.out_is_redirected,
|
||||||
|
streams);
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,8 @@ static int parse_cmd_opts(math_cmd_opts_t &opts, int *optind, //!OCLINT(high nc
|
||||||
} else {
|
} else {
|
||||||
opts.scale = fish_wcstoi(w.woptarg);
|
opts.scale = fish_wcstoi(w.woptarg);
|
||||||
if (errno || opts.scale < 0 || opts.scale > 15) {
|
if (errno || opts.scale < 0 || opts.scale > 15) {
|
||||||
streams.err.append_format(_(L"%ls: '%ls' is not a valid scale value\n"), cmd,
|
streams.err.append_format(_(L"%ls: '%ls' is not a valid scale value\n"),
|
||||||
w.woptarg);
|
cmd, w.woptarg);
|
||||||
return STATUS_INVALID_ARGS;
|
return STATUS_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,19 +129,28 @@ static const wchar_t *math_get_arg(int *argidx, wchar_t **argv, wcstring *storag
|
||||||
return math_get_arg_argv(argidx, argv);
|
return math_get_arg_argv(argidx, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const wchar_t *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?!?";
|
if (error.position == 0) return L"NO ERROR?!?";
|
||||||
|
|
||||||
switch(error.type) {
|
switch (error.type) {
|
||||||
case TE_ERROR_NONE: DIE("Error has no position");
|
case TE_ERROR_NONE:
|
||||||
case TE_ERROR_UNKNOWN_VARIABLE: return _(L"Unknown variable");
|
DIE("Error has no position");
|
||||||
case TE_ERROR_MISSING_CLOSING_PAREN: return _(L"Missing closing parenthesis");
|
case TE_ERROR_UNKNOWN_VARIABLE:
|
||||||
case TE_ERROR_MISSING_OPENING_PAREN: return _(L"Missing opening parenthesis");
|
return _(L"Unknown variable");
|
||||||
case TE_ERROR_TOO_FEW_ARGS: return _(L"Too few arguments");
|
case TE_ERROR_MISSING_CLOSING_PAREN:
|
||||||
case TE_ERROR_TOO_MANY_ARGS: return _(L"Too many arguments");
|
return _(L"Missing closing parenthesis");
|
||||||
case TE_ERROR_MISSING_OPERATOR: return _(L"Missing operator");
|
case TE_ERROR_MISSING_OPENING_PAREN:
|
||||||
case TE_ERROR_UNKNOWN: return _(L"Expression is bogus");
|
return _(L"Missing opening parenthesis");
|
||||||
default: return L"Unknown error";
|
case TE_ERROR_TOO_FEW_ARGS:
|
||||||
|
return _(L"Too few arguments");
|
||||||
|
case TE_ERROR_TOO_MANY_ARGS:
|
||||||
|
return _(L"Too many arguments");
|
||||||
|
case TE_ERROR_MISSING_OPERATOR:
|
||||||
|
return _(L"Missing operator");
|
||||||
|
case TE_ERROR_UNKNOWN:
|
||||||
|
return _(L"Expression is bogus");
|
||||||
|
default:
|
||||||
|
return L"Unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +221,7 @@ static int evaluate_expression(const wchar_t *cmd, parser_t &parser, io_streams_
|
||||||
} else {
|
} else {
|
||||||
streams.err.append_format(L"%ls: Error: %ls\n", cmd, math_describe_error(error));
|
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'\n", expression.c_str());
|
||||||
streams.err.append_format(L"%*ls%ls\n", error.position - 1, L" ",L"^");
|
streams.err.append_format(L"%*ls%ls\n", error.position - 1, L" ", L"^");
|
||||||
retval = STATUS_CMD_ERROR;
|
retval = STATUS_CMD_ERROR;
|
||||||
}
|
}
|
||||||
setlocale(LC_NUMERIC, saved_locale);
|
setlocale(LC_NUMERIC, saved_locale);
|
||||||
|
|
|
@ -57,10 +57,10 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
@ -93,7 +93,6 @@ struct builtin_printf_state_t {
|
||||||
void nonfatal_error(const wchar_t *fmt, ...);
|
void nonfatal_error(const wchar_t *fmt, ...);
|
||||||
void fatal_error(const wchar_t *format, ...);
|
void fatal_error(const wchar_t *format, ...);
|
||||||
|
|
||||||
|
|
||||||
long print_esc(const wchar_t *escstart, bool octal_0);
|
long print_esc(const wchar_t *escstart, bool octal_0);
|
||||||
void print_esc_string(const wchar_t *str);
|
void print_esc_string(const wchar_t *str);
|
||||||
void print_esc_char(wchar_t c);
|
void print_esc_char(wchar_t c);
|
||||||
|
@ -161,7 +160,9 @@ static int hex_to_bin(const wchar_t &c) {
|
||||||
case L'F': {
|
case L'F': {
|
||||||
return 15;
|
return 15;
|
||||||
}
|
}
|
||||||
default: { return -1; }
|
default: {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +192,9 @@ static int octal_to_bin(wchar_t c) {
|
||||||
case L'7': {
|
case L'7': {
|
||||||
return 7;
|
return 7;
|
||||||
}
|
}
|
||||||
default: { return -1; }
|
default: {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,7 +475,9 @@ void builtin_printf_state_t::print_direc(const wchar_t *start, size_t length, wc
|
||||||
fmt.append(L"l");
|
fmt.append(L"l");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: { break; }
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the conversion itself.
|
// Append the conversion itself.
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "wutil.h" // IWYU pragma: keep
|
#include "wutil.h" // IWYU pragma: keep
|
||||||
|
|
||||||
/// The pwd builtin. Respect -P to resolve symbolic links. Respect -L to not do that (the default).
|
/// The pwd builtin. Respect -P to resolve symbolic links. Respect -L to not do that (the default).
|
||||||
static const wchar_t * const short_options = L"LPh";
|
static const wchar_t *const short_options = L"LPh";
|
||||||
static const struct woption long_options[] = {{L"help", no_argument, NULL, 'h'},
|
static const struct woption long_options[] = {{L"help", no_argument, NULL, 'h'},
|
||||||
{NULL, 0, NULL, 0}};
|
{NULL, 0, NULL, 0}};
|
||||||
int builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
int builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -55,8 +55,7 @@ struct read_cmd_opts_t {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const wchar_t *const short_options = L":ac:d:ghiLlm:n:p:sSuxzP:UR:LB";
|
static const wchar_t *const short_options = L":ac:d:ghiLlm:n:p:sSuxzP:UR:LB";
|
||||||
static const struct woption long_options[] = {
|
static const struct woption long_options[] = {{L"array", no_argument, NULL, 'a'},
|
||||||
{L"array", no_argument, NULL, 'a'},
|
|
||||||
{L"command", required_argument, NULL, 'c'},
|
{L"command", required_argument, NULL, 'c'},
|
||||||
{L"delimiter", required_argument, NULL, 'd'},
|
{L"delimiter", required_argument, NULL, 'd'},
|
||||||
{L"export", no_argument, NULL, 'x'},
|
{L"export", no_argument, NULL, 'x'},
|
||||||
|
@ -74,8 +73,7 @@ static const struct woption long_options[] = {
|
||||||
{L"silent", no_argument, NULL, 's'},
|
{L"silent", no_argument, NULL, 's'},
|
||||||
{L"unexport", no_argument, NULL, 'u'},
|
{L"unexport", no_argument, NULL, 'u'},
|
||||||
{L"universal", no_argument, NULL, 'U'},
|
{L"universal", no_argument, NULL, 'U'},
|
||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}};
|
||||||
};
|
|
||||||
|
|
||||||
static int parse_cmd_opts(read_cmd_opts_t &opts, int *optind, //!OCLINT(high ncss method)
|
static int parse_cmd_opts(read_cmd_opts_t &opts, int *optind, //!OCLINT(high ncss method)
|
||||||
int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) {
|
int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) {
|
||||||
|
@ -98,7 +96,8 @@ static int parse_cmd_opts(read_cmd_opts_t &opts, int *optind, //!OCLINT(high nc
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'i': {
|
case 'i': {
|
||||||
streams.err.append_format(_(L"%ls: usage of -i for --silent is deprecated. Please use -s or --silent instead.\n"),
|
streams.err.append_format(_(L"%ls: usage of -i for --silent is deprecated. Please "
|
||||||
|
L"use -s or --silent instead.\n"),
|
||||||
cmd);
|
cmd);
|
||||||
return STATUS_INVALID_ARGS;
|
return STATUS_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
@ -350,17 +349,20 @@ static int read_one_char_at_a_time(int fd, wcstring &buff, int nchars, bool spli
|
||||||
static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int argc,
|
static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int argc,
|
||||||
const wchar_t *const *argv, parser_t &parser, io_streams_t &streams) {
|
const wchar_t *const *argv, parser_t &parser, io_streams_t &streams) {
|
||||||
if (opts.prompt && opts.prompt_str) {
|
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");
|
streams.err.append_format(_(L"%ls: Options %ls and %ls cannot be used together\n"), cmd,
|
||||||
|
L"-p", L"-P");
|
||||||
builtin_print_error_trailer(parser, streams.err, cmd);
|
builtin_print_error_trailer(parser, streams.err, cmd);
|
||||||
return STATUS_INVALID_ARGS;
|
return STATUS_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.have_delimiter && opts.one_line) {
|
if (opts.have_delimiter && opts.one_line) {
|
||||||
streams.err.append_format(_(L"%ls: Options %ls and %ls cannot be used together\n"), cmd, L"--delimiter", L"--line");
|
streams.err.append_format(_(L"%ls: Options %ls and %ls cannot be used together\n"), cmd,
|
||||||
|
L"--delimiter", L"--line");
|
||||||
return STATUS_INVALID_ARGS;
|
return STATUS_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
if (opts.one_line && opts.split_null) {
|
if (opts.one_line && opts.split_null) {
|
||||||
streams.err.append_format(_(L"%ls: Options %ls and %ls cannot be used together\n"), cmd, L"-z", L"--line");
|
streams.err.append_format(_(L"%ls: Options %ls and %ls cannot be used together\n"), cmd,
|
||||||
|
L"-z", L"--line");
|
||||||
return STATUS_INVALID_ARGS;
|
return STATUS_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,22 +451,23 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
opts.shell = false;
|
opts.shell = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t * const *var_ptr = argv;
|
wchar_t *const *var_ptr = argv;
|
||||||
auto vars_left = [&] () { return argv + argc - var_ptr; };
|
auto vars_left = [&]() { return argv + argc - var_ptr; };
|
||||||
auto clear_remaining_vars = [&] () {
|
auto clear_remaining_vars = [&]() {
|
||||||
while (vars_left()) {
|
while (vars_left()) {
|
||||||
parser.vars().set_empty(*var_ptr, opts.place);
|
parser.vars().set_empty(*var_ptr, opts.place);
|
||||||
++var_ptr;
|
++var_ptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Normally, we either consume a line of input or all available input. But if we are reading a line at
|
// Normally, we either consume a line of input or all available input. But if we are reading a
|
||||||
// a time, we need a middle ground where we only consume as many lines as we need to fill the given vars.
|
// line at a time, we need a middle ground where we only consume as many lines as we need to
|
||||||
|
// fill the given vars.
|
||||||
do {
|
do {
|
||||||
buff.clear();
|
buff.clear();
|
||||||
|
|
||||||
// TODO: Determine if the original set of conditions for interactive reads should be reinstated:
|
// TODO: Determine if the original set of conditions for interactive reads should be
|
||||||
// if (isatty(0) && streams.stdin_fd == STDIN_FILENO && !split_null) {
|
// reinstated: if (isatty(0) && streams.stdin_fd == STDIN_FILENO && !split_null) {
|
||||||
int stream_stdin_is_a_tty = isatty(streams.stdin_fd);
|
int stream_stdin_is_a_tty = isatty(streams.stdin_fd);
|
||||||
if (stream_stdin_is_a_tty && !opts.split_null) {
|
if (stream_stdin_is_a_tty && !opts.split_null) {
|
||||||
// Read interactively using reader_readline(). This does not support splitting on null.
|
// Read interactively using reader_readline(). This does not support splitting on null.
|
||||||
|
@ -474,7 +477,8 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
lseek(streams.stdin_fd, 0, SEEK_CUR) != -1) {
|
lseek(streams.stdin_fd, 0, SEEK_CUR) != -1) {
|
||||||
exit_res = read_in_chunks(streams.stdin_fd, buff, opts.split_null);
|
exit_res = read_in_chunks(streams.stdin_fd, buff, opts.split_null);
|
||||||
} else {
|
} else {
|
||||||
exit_res = read_one_char_at_a_time(streams.stdin_fd, buff, opts.nchars, opts.split_null);
|
exit_res =
|
||||||
|
read_one_char_at_a_time(streams.stdin_fd, buff, opts.nchars, opts.split_null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exit_res != STATUS_CMD_OK) {
|
if (exit_res != STATUS_CMD_OK) {
|
||||||
|
@ -496,7 +500,8 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
// Every character is a separate token with one wrinkle involving non-array mode where
|
// Every character is a separate token with one wrinkle involving non-array mode where
|
||||||
// the final var gets the remaining characters as a single string.
|
// the final var gets the remaining characters as a single string.
|
||||||
size_t x = std::max(static_cast<size_t>(1), buff.size());
|
size_t x = std::max(static_cast<size_t>(1), buff.size());
|
||||||
size_t n_splits = (opts.array || static_cast<size_t>(vars_left()) > x) ? x : vars_left();
|
size_t n_splits =
|
||||||
|
(opts.array || static_cast<size_t>(vars_left()) > x) ? x : vars_left();
|
||||||
wcstring_list_t chars;
|
wcstring_list_t chars;
|
||||||
chars.reserve(n_splits);
|
chars.reserve(n_splits);
|
||||||
|
|
||||||
|
@ -563,7 +568,7 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
// is set to the remaining string.
|
// is set to the remaining string.
|
||||||
split_about(buff.begin(), buff.end(), opts.delimiter.begin(), opts.delimiter.end(),
|
split_about(buff.begin(), buff.end(), opts.delimiter.begin(), opts.delimiter.end(),
|
||||||
&splits, argc - 1);
|
&splits, argc - 1);
|
||||||
assert(splits.size() <= (size_t) vars_left());
|
assert(splits.size() <= (size_t)vars_left());
|
||||||
for (const auto &split : splits) {
|
for (const auto &split : splits) {
|
||||||
vars.set_one(*var_ptr++, opts.place, split);
|
vars.set_one(*var_ptr++, opts.place, split);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -305,7 +305,6 @@ static bool validate_path_warning_on_colons(const wchar_t *cmd,
|
||||||
|
|
||||||
static void handle_env_return(int retval, const wchar_t *cmd, const wchar_t *key,
|
static void handle_env_return(int retval, const wchar_t *cmd, const wchar_t *key,
|
||||||
io_streams_t &streams) {
|
io_streams_t &streams) {
|
||||||
|
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
case ENV_OK: {
|
case ENV_OK: {
|
||||||
break;
|
break;
|
||||||
|
@ -317,19 +316,18 @@ static void handle_env_return(int retval, const wchar_t *cmd, const wchar_t *key
|
||||||
}
|
}
|
||||||
case ENV_SCOPE: {
|
case ENV_SCOPE: {
|
||||||
streams.err.append_format(
|
streams.err.append_format(
|
||||||
_(L"%ls: Tried to modify the special variable '%ls' with the wrong scope\n"),
|
_(L"%ls: Tried to modify the special variable '%ls' with the wrong scope\n"), cmd,
|
||||||
cmd, key);
|
key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ENV_INVALID: {
|
case ENV_INVALID: {
|
||||||
streams.err.append_format(
|
streams.err.append_format(
|
||||||
_(L"%ls: Tried to modify the special variable '%ls' to an invalid value\n"),
|
_(L"%ls: Tried to modify the special variable '%ls' to an invalid value\n"), cmd,
|
||||||
cmd, key);
|
key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ENV_NOT_FOUND: {
|
case ENV_NOT_FOUND: {
|
||||||
streams.err.append_format(
|
streams.err.append_format(_(L"%ls: The variable '%ls' does not exist\n"), cmd, key);
|
||||||
_(L"%ls: The variable '%ls' does not exist\n"), cmd, key);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -579,8 +577,7 @@ static void show_scope(const wchar_t *var_name, int scope, io_streams_t &streams
|
||||||
if (i >= 50 && i < vals.size() - 50) continue;
|
if (i >= 50 && i < vals.size() - 50) continue;
|
||||||
}
|
}
|
||||||
const wcstring value = vals[i];
|
const wcstring value = vals[i];
|
||||||
const wcstring escaped_val =
|
const wcstring escaped_val = escape_string(value, ESCAPE_NO_QUOTED, STRING_STYLE_SCRIPT);
|
||||||
escape_string(value, ESCAPE_NO_QUOTED, STRING_STYLE_SCRIPT);
|
|
||||||
streams.out.append_format(_(L"$%ls[%d]: length=%d value=|%ls|\n"), var_name, i + 1,
|
streams.out.append_format(_(L"$%ls[%d]: length=%d value=|%ls|\n"), var_name, i + 1,
|
||||||
value.size(), escaped_val.c_str());
|
value.size(), escaped_val.c_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,12 +65,12 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
// By the time this is called we should have initialized the curses subsystem.
|
// By the time this is called we should have initialized the curses subsystem.
|
||||||
assert(curses_initialized);
|
assert(curses_initialized);
|
||||||
|
|
||||||
// Hack in missing italics and dim capabilities omitted from MacOS xterm-256color terminfo
|
// Hack in missing italics and dim capabilities omitted from MacOS xterm-256color terminfo
|
||||||
// Helps Terminal.app/iTerm
|
// Helps Terminal.app/iTerm
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
const auto term_prog = parser.vars().get(L"TERM_PROGRAM");
|
const auto term_prog = parser.vars().get(L"TERM_PROGRAM");
|
||||||
if (!term_prog.missing_or_empty() && (term_prog->as_string() == L"Apple_Terminal"
|
if (!term_prog.missing_or_empty() &&
|
||||||
|| term_prog->as_string() == L"iTerm.app")) {
|
(term_prog->as_string() == L"Apple_Terminal" || term_prog->as_string() == L"iTerm.app")) {
|
||||||
const auto term = parser.vars().get(L"TERM");
|
const auto term = parser.vars().get(L"TERM");
|
||||||
if (!term.missing_or_empty() && (term->as_string() == L"xterm-256color")) {
|
if (!term.missing_or_empty() && (term->as_string() == L"xterm-256color")) {
|
||||||
enter_italics_mode = sitm_esc;
|
enter_italics_mode = sitm_esc;
|
||||||
|
@ -78,7 +78,7 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
enter_dim_mode = dim_esc;
|
enter_dim_mode = dim_esc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Variables used for parsing the argument list.
|
// Variables used for parsing the argument list.
|
||||||
wchar_t *cmd = argv[0];
|
wchar_t *cmd = argv[0];
|
||||||
|
|
|
@ -102,7 +102,8 @@ struct status_cmd_opts_t {
|
||||||
/// least until fish 3.0 and possibly longer to avoid breaking everyones config.fish and other
|
/// least until fish 3.0 and possibly longer to avoid breaking everyones config.fish and other
|
||||||
/// scripts.
|
/// scripts.
|
||||||
static const wchar_t *const short_options = L":L:cbilfnhj:t";
|
static const wchar_t *const short_options = L":L:cbilfnhj:t";
|
||||||
static const struct woption long_options[] = {{L"help", no_argument, NULL, 'h'},
|
static const struct woption long_options[] = {
|
||||||
|
{L"help", no_argument, NULL, 'h'},
|
||||||
{L"current-filename", no_argument, NULL, 'f'},
|
{L"current-filename", no_argument, NULL, 'f'},
|
||||||
{L"current-line-number", no_argument, NULL, 'n'},
|
{L"current-line-number", no_argument, NULL, 'n'},
|
||||||
{L"filename", no_argument, NULL, 'f'},
|
{L"filename", no_argument, NULL, 'f'},
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cwctype>
|
#include <cwctype>
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <cstring>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -24,8 +24,8 @@
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "wutil.h" // IWYU pragma: keep
|
#include "wutil.h" // IWYU pragma: keep
|
||||||
|
|
||||||
using std::unique_ptr;
|
|
||||||
using std::move;
|
using std::move;
|
||||||
|
using std::unique_ptr;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
namespace test_expressions {
|
namespace test_expressions {
|
||||||
|
@ -530,7 +530,9 @@ unique_ptr<expression> test_parser::parse_expression(unsigned int start, unsigne
|
||||||
case 4: {
|
case 4: {
|
||||||
return parse_4_arg_expression(start, end);
|
return parse_4_arg_expression(start, end);
|
||||||
}
|
}
|
||||||
default: { return parse_combining_expression(start, end); }
|
default: {
|
||||||
|
return parse_combining_expression(start, end);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,8 +675,8 @@ static bool parse_number(const wcstring &arg, number_t *number, wcstring_list_t
|
||||||
// We could not parse a float or an int.
|
// We could not parse a float or an int.
|
||||||
// Check for special fish_wcsto* value or show standard EINVAL/ERANGE error.
|
// Check for special fish_wcsto* value or show standard EINVAL/ERANGE error.
|
||||||
if (errno == -1) {
|
if (errno == -1) {
|
||||||
errors.push_back(format_string(_(L"Integer %lld in '%ls' followed by non-digit"),
|
errors.push_back(
|
||||||
integral, argcs));
|
format_string(_(L"Integer %lld in '%ls' followed by non-digit"), integral, argcs));
|
||||||
} else {
|
} else {
|
||||||
errors.push_back(format_string(L"%s: '%ls'", std::strerror(errno), argcs));
|
errors.push_back(format_string(L"%s: '%ls'", std::strerror(errno), argcs));
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,9 @@ static int parse_hex_digit(wchar_t x) {
|
||||||
case L'F': {
|
case L'F': {
|
||||||
return 0xF;
|
return 0xF;
|
||||||
}
|
}
|
||||||
default: { return -1; }
|
default: {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +331,9 @@ wcstring rgb_color_t::description() const {
|
||||||
case type_normal: {
|
case type_normal: {
|
||||||
return L"normal";
|
return L"normal";
|
||||||
}
|
}
|
||||||
default: { break; }
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DIE("unknown color type");
|
DIE("unknown color type");
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,13 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cwchar>
|
||||||
#ifdef HAVE_EXECINFO_H
|
#ifdef HAVE_EXECINFO_H
|
||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -63,7 +63,7 @@ constexpr wint_t NOT_A_WCHAR = static_cast<wint_t>(WEOF);
|
||||||
struct termios shell_modes;
|
struct termios shell_modes;
|
||||||
|
|
||||||
/// This allows us to determine if we're running on the main thread
|
/// This allows us to determine if we're running on the main thread
|
||||||
static std::atomic<size_t> thread_id { 0 };
|
static std::atomic<size_t> thread_id{0};
|
||||||
/// This allows us to notice when we've forked.
|
/// This allows us to notice when we've forked.
|
||||||
static relaxed_atomic_bool_t is_forked_proc{false};
|
static relaxed_atomic_bool_t is_forked_proc{false};
|
||||||
/// This allows us to bypass the main thread checks
|
/// This allows us to bypass the main thread checks
|
||||||
|
@ -168,7 +168,9 @@ bool is_windows_subsystem_for_linux() {
|
||||||
if (std::strstr(info.release, "Microsoft") != nullptr) {
|
if (std::strstr(info.release, "Microsoft") != nullptr) {
|
||||||
const char *dash = std::strchr(info.release, '-');
|
const char *dash = std::strchr(info.release, '-');
|
||||||
if (dash == nullptr || strtod(dash + 1, nullptr) < 17763) {
|
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"
|
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!");
|
"Please upgrade to Windows 10 1809 (17763) or higher to use fish!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,8 +189,8 @@ bool is_windows_subsystem_for_linux() {
|
||||||
#ifdef HAVE_BACKTRACE_SYMBOLS
|
#ifdef HAVE_BACKTRACE_SYMBOLS
|
||||||
// This function produces a stack backtrace with demangled function & method names. It is based on
|
// This function produces a stack backtrace with demangled function & method names. It is based on
|
||||||
// https://gist.github.com/fmela/591333 but adapted to the style of the fish project.
|
// https://gist.github.com/fmela/591333 but adapted to the style of the fish project.
|
||||||
[[gnu::noinline]] static const wcstring_list_t
|
[[gnu::noinline]] static const wcstring_list_t demangled_backtrace(int max_frames,
|
||||||
demangled_backtrace(int max_frames, int skip_levels) {
|
int skip_levels) {
|
||||||
void *callstack[128];
|
void *callstack[128];
|
||||||
const int n_max_frames = sizeof(callstack) / sizeof(callstack[0]);
|
const int n_max_frames = sizeof(callstack) / sizeof(callstack[0]);
|
||||||
int n_frames = backtrace(callstack, n_max_frames);
|
int n_frames = backtrace(callstack, n_max_frames);
|
||||||
|
@ -653,8 +655,8 @@ static void debug_shared(const wchar_t level, const wcstring &msg) {
|
||||||
std::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 {
|
} else {
|
||||||
current_pid = getpid();
|
current_pid = getpid();
|
||||||
std::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,
|
||||||
msg.c_str());
|
current_pid, msg.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1156,8 +1158,9 @@ static wcstring escape_string_pcre2(const wcstring &in) {
|
||||||
case L'}':
|
case L'}':
|
||||||
case L'\\':
|
case L'\\':
|
||||||
case L'|':
|
case L'|':
|
||||||
// these two only *need* to be escaped within a character class, and technically it makes
|
// these two only *need* to be escaped within a character class, and technically it
|
||||||
// no sense to ever use process substitution output to compose a character class, but...
|
// makes no sense to ever use process substitution output to compose a character class,
|
||||||
|
// but...
|
||||||
case L'-':
|
case L'-':
|
||||||
case L']':
|
case L']':
|
||||||
out.push_back('\\');
|
out.push_back('\\');
|
||||||
|
@ -1652,7 +1655,9 @@ static bool unescape_string_internal(const wchar_t *const input, const size_t in
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: { break; }
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2232,9 +2237,7 @@ void set_main_thread() {
|
||||||
|
|
||||||
void configure_thread_assertions_for_testing() { thread_asserts_cfg_for_testing = true; }
|
void configure_thread_assertions_for_testing() { thread_asserts_cfg_for_testing = true; }
|
||||||
|
|
||||||
bool is_forked_child() {
|
bool is_forked_child() { return is_forked_proc; }
|
||||||
return is_forked_proc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup_fork_guards() {
|
void setup_fork_guards() {
|
||||||
is_forked_proc = false;
|
is_forked_proc = false;
|
||||||
|
@ -2426,12 +2429,11 @@ std::string get_executable_path(const char *argv0) {
|
||||||
// Linux compatibility layer. Per sysctl(3), passing in a process ID of -1 returns
|
// Linux compatibility layer. Per sysctl(3), passing in a process ID of -1 returns
|
||||||
// the value for the current process.
|
// the value for the current process.
|
||||||
size_t buff_size = sizeof buff;
|
size_t buff_size = sizeof buff;
|
||||||
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
|
int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
|
||||||
int result = sysctl(name, sizeof(name) / sizeof(int), buff, &buff_size, nullptr, 0);
|
int result = sysctl(name, sizeof(name) / sizeof(int), buff, &buff_size, nullptr, 0);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
wperror(L"sysctl KERN_PROC_PATHNAME");
|
wperror(L"sysctl KERN_PROC_PATHNAME");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return std::string(buff);
|
return std::string(buff);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -2494,9 +2496,10 @@ bool is_console_session() {
|
||||||
const char *TERM = getenv("TERM");
|
const char *TERM = getenv("TERM");
|
||||||
return
|
return
|
||||||
// Test that the tty matches /dev/(console|dcons|tty[uv\d])
|
// Test that the tty matches /dev/(console|dcons|tty[uv\d])
|
||||||
tty_name && ((strncmp(tty_name, "/dev/tty", len) == 0 &&
|
tty_name &&
|
||||||
(tty_name[len] == 'u' || tty_name[len] == 'v' || isdigit(tty_name[len])))
|
((strncmp(tty_name, "/dev/tty", len) == 0 &&
|
||||||
|| strcmp(tty_name, "/dev/dcons") == 0 || strcmp(tty_name, "/dev/console") == 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`
|
// and that $TERM is simple, e.g. `xterm` or `vt100`, not `xterm-something`
|
||||||
&& (!TERM || !strchr(TERM, '-') || !strcmp(TERM, "sun-color"));
|
&& (!TERM || !strchr(TERM, '-') || !strcmp(TERM, "sun-color"));
|
||||||
}();
|
}();
|
||||||
|
|
31
src/common.h
31
src/common.h
|
@ -248,7 +248,8 @@ extern const bool has_working_tty_timestamps;
|
||||||
|
|
||||||
[[noreturn]] void __fish_assert(const char *msg, const char *file, size_t line, int error);
|
[[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., std::fwprintf()).
|
/// Shorthand for wgettext call in situations where a C-style string is needed (e.g.,
|
||||||
|
/// std::fwprintf()).
|
||||||
#define _(wstr) wgettext(wstr).c_str()
|
#define _(wstr) wgettext(wstr).c_str()
|
||||||
|
|
||||||
/// Noop, used to tell xgettext that a string should be translated. Use this when a string cannot be
|
/// Noop, used to tell xgettext that a string should be translated. Use this when a string cannot be
|
||||||
|
@ -348,26 +349,22 @@ class line_iterator_t {
|
||||||
// The current location in the iteration.
|
// The current location in the iteration.
|
||||||
typename Collection::const_iterator current;
|
typename Collection::const_iterator current;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Construct from a collection (presumably std::string or std::wcstring).
|
/// Construct from a collection (presumably std::string or std::wcstring).
|
||||||
line_iterator_t(const Collection &coll) : coll(coll), current(coll.cbegin()) {}
|
line_iterator_t(const Collection &coll) : coll(coll), current(coll.cbegin()) {}
|
||||||
|
|
||||||
/// Access the storage in which the last line was stored.
|
/// Access the storage in which the last line was stored.
|
||||||
const Collection &line() const {
|
const Collection &line() const { return storage; }
|
||||||
return storage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Advances to the next line. \return true on success, false if we have exhausted the string.
|
/// Advances to the next line. \return true on success, false if we have exhausted the string.
|
||||||
bool next() {
|
bool next() {
|
||||||
if (current == coll.end())
|
if (current == coll.end()) return false;
|
||||||
return false;
|
|
||||||
auto newline_or_end = std::find(current, coll.cend(), '\n');
|
auto newline_or_end = std::find(current, coll.cend(), '\n');
|
||||||
storage.assign(current, newline_or_end);
|
storage.assign(current, newline_or_end);
|
||||||
current = newline_or_end;
|
current = newline_or_end;
|
||||||
|
|
||||||
// Skip the newline.
|
// Skip the newline.
|
||||||
if (current != coll.cend())
|
if (current != coll.cend()) ++current;
|
||||||
++current;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -531,7 +528,9 @@ inline bool bool_from_string(const std::string &x) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool bool_from_string(const wcstring &x) { return !x.empty() && std::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);
|
wchar_t **make_null_terminated_array(const wcstring_list_t &lst);
|
||||||
char **make_null_terminated_array(const std::vector<std::string> &lst);
|
char **make_null_terminated_array(const std::vector<std::string> &lst);
|
||||||
|
@ -1014,14 +1013,12 @@ std::string get_executable_path(const char *fallback);
|
||||||
/// A RAII wrapper for resources that don't recur, so we don't have to create a separate RAII
|
/// A RAII wrapper for resources that don't recur, so we don't have to create a separate RAII
|
||||||
/// wrapper for each function. Avoids needing to call "return cleanup()" or similar / everywhere.
|
/// wrapper for each function. Avoids needing to call "return cleanup()" or similar / everywhere.
|
||||||
struct cleanup_t {
|
struct cleanup_t {
|
||||||
private:
|
private:
|
||||||
const std::function<void()> cleanup;
|
const std::function<void()> cleanup;
|
||||||
public:
|
|
||||||
cleanup_t(std::function<void()> exit_actions)
|
public:
|
||||||
: cleanup{std::move(exit_actions)} {}
|
cleanup_t(std::function<void()> exit_actions) : cleanup{std::move(exit_actions)} {}
|
||||||
~cleanup_t() {
|
~cleanup_t() { cleanup(); }
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_console_session();
|
bool is_console_session();
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
@ -180,13 +180,9 @@ static bool compare_completions_by_order(const completion_entry_t &p1,
|
||||||
return p1.order < p2.order;
|
return p1.order < p2.order;
|
||||||
}
|
}
|
||||||
|
|
||||||
void completion_entry_t::add_option(const complete_entry_opt_t &opt) {
|
void completion_entry_t::add_option(const complete_entry_opt_t &opt) { options.push_front(opt); }
|
||||||
options.push_front(opt);
|
|
||||||
}
|
|
||||||
|
|
||||||
const option_list_t &completion_entry_t::get_options() const {
|
const option_list_t &completion_entry_t::get_options() const { return options; }
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
description_func_t const_desc(const wcstring &s) {
|
description_func_t const_desc(const wcstring &s) {
|
||||||
return [=](const wcstring &ignored) {
|
return [=](const wcstring &ignored) {
|
||||||
|
@ -202,7 +198,8 @@ static complete_flags_t resolve_auto_space(const wcstring &comp, complete_flags_
|
||||||
if (flags & COMPLETE_AUTO_SPACE) {
|
if (flags & COMPLETE_AUTO_SPACE) {
|
||||||
new_flags &= ~COMPLETE_AUTO_SPACE;
|
new_flags &= ~COMPLETE_AUTO_SPACE;
|
||||||
size_t len = comp.size();
|
size_t len = comp.size();
|
||||||
if (len > 0 && (std::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;
|
return new_flags;
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,7 +195,6 @@ void append_completion(std::vector<completion_t> *completions, wcstring comp,
|
||||||
wcstring desc = wcstring(), int flags = 0,
|
wcstring desc = wcstring(), int flags = 0,
|
||||||
string_fuzzy_match_t match = string_fuzzy_match_t(fuzzy_match_exact));
|
string_fuzzy_match_t match = string_fuzzy_match_t(fuzzy_match_exact));
|
||||||
|
|
||||||
|
|
||||||
/// Support for "wrap targets." A wrap target is a command that completes like another command.
|
/// Support for "wrap targets." A wrap target is a command that completes like another command.
|
||||||
bool complete_add_wrapper(const wcstring &command, const wcstring &wrap_target);
|
bool complete_add_wrapper(const wcstring &command, const wcstring &wrap_target);
|
||||||
bool complete_remove_wrapper(const wcstring &command, const wcstring &wrap_target);
|
bool complete_remove_wrapper(const wcstring &command, const wcstring &wrap_target);
|
||||||
|
|
|
@ -306,9 +306,7 @@ struct var_stack_t {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy this vars_stack.
|
/// Copy this vars_stack.
|
||||||
var_stack_t clone() const {
|
var_stack_t clone() const { return var_stack_t(*this); }
|
||||||
return var_stack_t(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Snapshot this vars_stack. That is, return a new vars_stack that has copies of all local
|
/// Snapshot this vars_stack. That is, return a new vars_stack that has copies of all local
|
||||||
/// variables. Note that this drops all shadowed nodes: only the currently executing function is
|
/// variables. Note that this drops all shadowed nodes: only the currently executing function is
|
||||||
|
@ -610,7 +608,7 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
|
||||||
vars.set_empty(key_and_val, ENV_EXPORT | ENV_GLOBAL);
|
vars.set_empty(key_and_val, ENV_EXPORT | ENV_GLOBAL);
|
||||||
} else {
|
} else {
|
||||||
key.assign(key_and_val, 0, eql);
|
key.assign(key_and_val, 0, eql);
|
||||||
val.assign(key_and_val, eql+1, wcstring::npos);
|
val.assign(key_and_val, eql + 1, wcstring::npos);
|
||||||
if (is_read_only(key) || is_electric(key)) continue;
|
if (is_read_only(key) || is_electric(key)) continue;
|
||||||
vars.set(key, ENV_EXPORT | ENV_GLOBAL, {val});
|
vars.set(key, ENV_EXPORT | ENV_GLOBAL, {val});
|
||||||
}
|
}
|
||||||
|
@ -822,7 +820,8 @@ static void env_set_internal_universal(const wcstring &key, wcstring_list_t val,
|
||||||
/// * ENV_SCOPE, the variable cannot be set in the given scope. This applies to readonly/electric
|
/// * ENV_SCOPE, the variable cannot be set in the given scope. This applies to readonly/electric
|
||||||
/// variables set from the local or universal scopes, or set as exported.
|
/// variables set from the local or universal scopes, or set as exported.
|
||||||
/// * ENV_INVALID, the variable value was invalid. This applies only to special variables.
|
/// * ENV_INVALID, the variable value was invalid. This applies only to special variables.
|
||||||
int env_stack_t::set_internal(const wcstring &key, env_mode_flags_t input_var_mode, wcstring_list_t val) {
|
int env_stack_t::set_internal(const wcstring &key, env_mode_flags_t input_var_mode,
|
||||||
|
wcstring_list_t val) {
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
env_mode_flags_t var_mode = input_var_mode;
|
env_mode_flags_t var_mode = input_var_mode;
|
||||||
bool has_changed_old = vars_stack().has_changed_exported();
|
bool has_changed_old = vars_stack().has_changed_exported();
|
||||||
|
|
|
@ -164,7 +164,7 @@ class env_var_t {
|
||||||
bool operator==(const env_var_t &rhs) const {
|
bool operator==(const env_var_t &rhs) const {
|
||||||
return *vals_ == *rhs.vals_ && flags_ == rhs.flags_;
|
return *vals_ == *rhs.vals_ && flags_ == rhs.flags_;
|
||||||
}
|
}
|
||||||
bool operator!=(const env_var_t &rhs) const { return ! (*this == rhs); }
|
bool operator!=(const env_var_t &rhs) const { return !(*this == rhs); }
|
||||||
};
|
};
|
||||||
typedef std::map<wcstring, env_var_t> var_table_t;
|
typedef std::map<wcstring, env_var_t> var_table_t;
|
||||||
|
|
||||||
|
@ -241,7 +241,6 @@ class env_stack_t final : public env_scoped_t {
|
||||||
env_stack_t(env_stack_t &&);
|
env_stack_t(env_stack_t &&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// Sets the variable with the specified name to the given values.
|
/// Sets the variable with the specified name to the given values.
|
||||||
int set(const wcstring &key, env_mode_flags_t mode, wcstring_list_t vals);
|
int set(const wcstring &key, env_mode_flags_t mode, wcstring_list_t vals);
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
#include <ncurses/term.h>
|
#include <ncurses/term.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
|
@ -43,8 +43,8 @@
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
#include "util.h" // IWYU pragma: keep
|
#include "util.h" // IWYU pragma: keep
|
||||||
#include "wutil.h"
|
|
||||||
#include "wcstringutil.h"
|
#include "wcstringutil.h"
|
||||||
|
#include "wutil.h"
|
||||||
|
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
#define FISH_NOTIFYD_AVAILABLE 1
|
#define FISH_NOTIFYD_AVAILABLE 1
|
||||||
|
@ -229,7 +229,7 @@ static bool append_file_entry(env_var_t::env_var_flags_t flags, const wcstring &
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encoding of a null string.
|
/// Encoding of a null string.
|
||||||
static const wchar_t * const ENV_NULL = L"\x1d";
|
static const wchar_t *const ENV_NULL = L"\x1d";
|
||||||
|
|
||||||
/// Character used to separate arrays in universal variables file.
|
/// Character used to separate arrays in universal variables file.
|
||||||
/// This is 30, the ASCII record separator.
|
/// This is 30, the ASCII record separator.
|
||||||
|
@ -433,7 +433,8 @@ std::string env_universal_t::serialize_with_vars(const var_table_t &vars) {
|
||||||
// variable; soldier on.
|
// variable; soldier on.
|
||||||
const wcstring &key = kv.first;
|
const wcstring &key = kv.first;
|
||||||
const env_var_t &var = kv.second;
|
const env_var_t &var = kv.second;
|
||||||
append_file_entry(var.get_flags(), key, encode_serialized(var.as_list()), &contents, &storage);
|
append_file_entry(var.get_flags(), key, encode_serialized(var.as_list()), &contents,
|
||||||
|
&storage);
|
||||||
}
|
}
|
||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
@ -996,8 +997,9 @@ static bool get_mac_address(unsigned char macaddr[MAC_ADDRESS_MAX_LEN]) { return
|
||||||
|
|
||||||
/// Function to get an identifier based on the hostname.
|
/// Function to get an identifier based on the hostname.
|
||||||
bool get_hostname_identifier(wcstring &result) {
|
bool get_hostname_identifier(wcstring &result) {
|
||||||
//The behavior of gethostname if the buffer size is insufficient differs by implementation and libc version
|
// The behavior of gethostname if the buffer size is insufficient differs by implementation and
|
||||||
//Work around this by using a "guaranteed" sufficient buffer size then truncating the result.
|
// libc version Work around this by using a "guaranteed" sufficient buffer size then truncating
|
||||||
|
// the result.
|
||||||
bool success = false;
|
bool success = false;
|
||||||
char hostname[256] = {};
|
char hostname[256] = {};
|
||||||
if (gethostname(hostname, sizeof(hostname)) == 0) {
|
if (gethostname(hostname, sizeof(hostname)) == 0) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ class pending_signals_t {
|
||||||
/// This is not accessed from a signal handler.
|
/// This is not accessed from a signal handler.
|
||||||
owning_lock<uint32_t> last_counter_{0};
|
owning_lock<uint32_t> last_counter_{0};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
pending_signals_t() = default;
|
pending_signals_t() = default;
|
||||||
|
|
||||||
/// No copying.
|
/// No copying.
|
||||||
|
@ -64,7 +64,8 @@ public:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// The signal count has changed. Store the new counter and fetch all the signals that are set.
|
// The signal count has changed. Store the new counter and fetch all the signals that are
|
||||||
|
// set.
|
||||||
*current = count;
|
*current = count;
|
||||||
std::bitset<SIGNAL_COUNT> result{};
|
std::bitset<SIGNAL_COUNT> result{};
|
||||||
uint32_t bit = 0;
|
uint32_t bit = 0;
|
||||||
|
@ -183,7 +184,9 @@ wcstring event_get_desc(const event_t &evt) {
|
||||||
case event_type_t::generic: {
|
case event_type_t::generic: {
|
||||||
return format_string(_(L"handler for generic event '%ls'"), ed.str_param1.c_str());
|
return format_string(_(L"handler for generic event '%ls'"), ed.str_param1.c_str());
|
||||||
}
|
}
|
||||||
case event_type_t::any: { DIE("Unreachable"); }
|
case event_type_t::any: {
|
||||||
|
DIE("Unreachable");
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
DIE("Unknown event type");
|
DIE("Unknown event type");
|
||||||
}
|
}
|
||||||
|
@ -291,8 +294,7 @@ static void event_fire_internal(const event_t &event) {
|
||||||
void event_fire_delayed() {
|
void event_fire_delayed() {
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
// Do not invoke new event handlers from within event handlers.
|
// Do not invoke new event handlers from within event handlers.
|
||||||
if (is_event)
|
if (is_event) return;
|
||||||
return;
|
|
||||||
|
|
||||||
event_list_t to_send;
|
event_list_t to_send;
|
||||||
to_send.swap(blocked);
|
to_send.swap(blocked);
|
||||||
|
@ -301,7 +303,7 @@ void event_fire_delayed() {
|
||||||
// Append all signal events to to_send.
|
// Append all signal events to to_send.
|
||||||
auto signals = s_pending_signals.acquire_pending();
|
auto signals = s_pending_signals.acquire_pending();
|
||||||
if (signals.any()) {
|
if (signals.any()) {
|
||||||
for (uint32_t sig=0; sig < signals.size(); sig++) {
|
for (uint32_t sig = 0; sig < signals.size(); sig++) {
|
||||||
if (signals.test(sig)) {
|
if (signals.test(sig)) {
|
||||||
auto e = std::make_shared<event_t>(event_type_t::signal);
|
auto e = std::make_shared<event_t>(event_type_t::signal);
|
||||||
e->desc.param1.signal = sig;
|
e->desc.param1.signal = sig;
|
||||||
|
@ -368,7 +370,6 @@ static const wchar_t *event_name_for_type(event_type_t type) {
|
||||||
return L"";
|
return L"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void event_print(io_streams_t &streams, maybe_t<event_type_t> type_filter) {
|
void event_print(io_streams_t &streams, maybe_t<event_type_t> type_filter) {
|
||||||
event_handler_list_t tmp = s_event_handlers;
|
event_handler_list_t tmp = s_event_handlers;
|
||||||
std::sort(tmp.begin(), tmp.end(),
|
std::sort(tmp.begin(), tmp.end(),
|
||||||
|
@ -401,8 +402,7 @@ void event_print(io_streams_t &streams, maybe_t<event_type_t> type_filter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!last_type || *last_type != evt->desc.type) {
|
if (!last_type || *last_type != evt->desc.type) {
|
||||||
if (last_type)
|
if (last_type) streams.out.append(L"\n");
|
||||||
streams.out.append(L"\n");
|
|
||||||
last_type = static_cast<event_type_t>(evt->desc.type);
|
last_type = static_cast<event_type_t>(evt->desc.type);
|
||||||
streams.out.append_format(L"Event %ls\n", event_name_for_type(*last_type));
|
streams.out.append_format(L"Event %ls\n", event_name_for_type(*last_type));
|
||||||
}
|
}
|
||||||
|
@ -421,7 +421,8 @@ void event_print(io_streams_t &streams, maybe_t<event_type_t> type_filter) {
|
||||||
streams.out.append_format(L"%ls %ls\n", evt->desc.str_param1.c_str(),
|
streams.out.append_format(L"%ls %ls\n", evt->desc.str_param1.c_str(),
|
||||||
evt->function_name.c_str());
|
evt->function_name.c_str());
|
||||||
break;
|
break;
|
||||||
case event_type_t::any: DIE("Unreachable");
|
case event_type_t::any:
|
||||||
|
DIE("Unreachable");
|
||||||
default:
|
default:
|
||||||
streams.out.append_format(L"%ls\n", evt->function_name.c_str());
|
streams.out.append_format(L"%ls\n", evt->function_name.c_str());
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
#include <spawn.h>
|
#include <spawn.h>
|
||||||
#endif
|
#endif
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <cstring>
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -675,8 +675,8 @@ static bool handle_builtin_output(const std::shared_ptr<job_t> &j, process_t *p,
|
||||||
|
|
||||||
/// Executes an external command.
|
/// Executes an external command.
|
||||||
/// \return true on success, false if there is an exec error.
|
/// \return true on success, false if there is an exec error.
|
||||||
static bool exec_external_command(env_stack_t &vars, const std::shared_ptr<job_t> &j,
|
static bool exec_external_command(env_stack_t &vars, const std::shared_ptr<job_t> &j, process_t *p,
|
||||||
process_t *p, const io_chain_t &proc_io_chain) {
|
const io_chain_t &proc_io_chain) {
|
||||||
assert(p->type == process_type_t::external && "Process is not external");
|
assert(p->type == process_type_t::external && "Process is not external");
|
||||||
// Get argv and envv before we fork.
|
// Get argv and envv before we fork.
|
||||||
null_terminated_array_t<char> argv_array;
|
null_terminated_array_t<char> argv_array;
|
||||||
|
@ -684,8 +684,7 @@ static bool exec_external_command(env_stack_t &vars, const std::shared_ptr<job_t
|
||||||
|
|
||||||
// Convert our IO chain to a dup2 sequence.
|
// Convert our IO chain to a dup2 sequence.
|
||||||
auto dup2s = dup2_list_t::resolve_chain(proc_io_chain);
|
auto dup2s = dup2_list_t::resolve_chain(proc_io_chain);
|
||||||
if (! dup2s)
|
if (!dup2s) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
// Ensure that stdin is blocking before we hand it off (see issue #176). It's a
|
// Ensure that stdin is blocking before we hand it off (see issue #176). It's a
|
||||||
// little strange that we only do this with stdin and not with stdout or stderr.
|
// little strange that we only do this with stdin and not with stdout or stderr.
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
#ifdef HAVE_SYS_SYSCTL_H
|
#ifdef HAVE_SYS_SYSCTL_H
|
||||||
#include <sys/sysctl.h> // IWYU pragma: keep
|
#include <sys/sysctl.h> // IWYU pragma: keep
|
||||||
|
@ -124,9 +124,7 @@ 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
|
/// Test if the specified string does not contain character which can not be used inside a quoted
|
||||||
/// string.
|
/// string.
|
||||||
static bool is_quotable(const wchar_t *str) {
|
static bool is_quotable(const wchar_t *str) { return !std::wcspbrk(str, L"\n\t\r\b\x1B"); }
|
||||||
return !std::wcspbrk(str, L"\n\t\r\b\x1B");
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_quotable(const wcstring &str) { return is_quotable(str.c_str()); }
|
static bool is_quotable(const wcstring &str) { return is_quotable(str.c_str()); }
|
||||||
|
|
||||||
|
@ -168,7 +166,8 @@ 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
|
/// 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
|
/// index of the bad token. Note that 0 can never be a bad index because the string always starts
|
||||||
/// with [.
|
/// with [.
|
||||||
static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector<long> &idx, size_t array_size) {
|
static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector<long> &idx,
|
||||||
|
size_t array_size) {
|
||||||
const long size = (long)array_size;
|
const long size = (long)array_size;
|
||||||
size_t pos = 1; // skip past the opening square brace
|
size_t pos = 1; // skip past the opening square brace
|
||||||
|
|
||||||
|
@ -360,7 +359,8 @@ static bool expand_variables(wcstring instr, std::vector<completion_t> *out, siz
|
||||||
} else if (history) {
|
} else if (history) {
|
||||||
effective_val_count = history->size();
|
effective_val_count = history->size();
|
||||||
}
|
}
|
||||||
size_t bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_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 (bad_pos != 0) {
|
||||||
if (in[slice_start + bad_pos] == L'0') {
|
if (in[slice_start + bad_pos] == L'0') {
|
||||||
append_syntax_error(errors, slice_start + bad_pos,
|
append_syntax_error(errors, slice_start + bad_pos,
|
||||||
|
@ -638,8 +638,7 @@ static bool expand_cmdsubst(wcstring input, parser_t &parser, std::vector<comple
|
||||||
wchar_t *slice_end;
|
wchar_t *slice_end;
|
||||||
size_t bad_pos;
|
size_t bad_pos;
|
||||||
|
|
||||||
bad_pos =
|
bad_pos = parse_slice(slice_begin, &slice_end, slice_idx, sub_res.size());
|
||||||
parse_slice(slice_begin, &slice_end, slice_idx, sub_res.size());
|
|
||||||
if (bad_pos != 0) {
|
if (bad_pos != 0) {
|
||||||
append_syntax_error(errors, slice_begin - in + bad_pos, L"Invalid index value");
|
append_syntax_error(errors, slice_begin - in + bad_pos, L"Invalid index value");
|
||||||
return false;
|
return false;
|
||||||
|
@ -1140,7 +1139,6 @@ expand_result_t expand_to_command_and_args(const wcstring &instr, const environm
|
||||||
parse_error_list_t *errors) {
|
parse_error_list_t *errors) {
|
||||||
// Fast path.
|
// Fast path.
|
||||||
if (expand_is_clean(instr)) {
|
if (expand_is_clean(instr)) {
|
||||||
|
|
||||||
*out_cmd = instr;
|
*out_cmd = instr;
|
||||||
return expand_result_t::ok;
|
return expand_result_t::ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,13 @@
|
||||||
#include <stdarg.h> // IWYU pragma: keep
|
#include <stdarg.h> // IWYU pragma: keep
|
||||||
#include <stdio.h> // IWYU pragma: keep
|
#include <stdio.h> // IWYU pragma: keep
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <sys/stat.h> // IWYU pragma: keep
|
#include <sys/stat.h> // IWYU pragma: keep
|
||||||
#include <sys/types.h> // IWYU pragma: keep
|
#include <sys/types.h> // IWYU pragma: keep
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cwchar>
|
||||||
#if HAVE_GETTEXT
|
#if HAVE_GETTEXT
|
||||||
#include <libintl.h>
|
#include <libintl.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,8 +45,8 @@
|
||||||
#if defined(TPARM_SOLARIS_KLUDGE)
|
#if defined(TPARM_SOLARIS_KLUDGE)
|
||||||
#undef tparm
|
#undef tparm
|
||||||
|
|
||||||
char *tparm_solaris_kludge(char *str, long p1, long p2, long p3, long p4,
|
char *tparm_solaris_kludge(char *str, long p1, long p2, long p3, long p4, long p5, long p6, long p7,
|
||||||
long p5, long p6, long p7, long p8, long p9) {
|
long p8, long p9) {
|
||||||
return tparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9);
|
return tparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,8 +97,7 @@ int fish_mkstemp_cloexec(char *name_template) {
|
||||||
return wcscasecmp_fallback(a + 1, b + 1);
|
return wcscasecmp_fallback(a + 1, b + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[gnu::unused]] static int wcsncasecmp_fallback(const wchar_t *a, const wchar_t *b,
|
[[gnu::unused]] static int wcsncasecmp_fallback(const wchar_t *a, const wchar_t *b, size_t count) {
|
||||||
size_t count) {
|
|
||||||
if (count == 0) return 0;
|
if (count == 0) return 0;
|
||||||
|
|
||||||
if (*a == 0) {
|
if (*a == 0) {
|
||||||
|
@ -281,8 +280,10 @@ int fish_wcwidth(wchar_t wc) {
|
||||||
// (width 1) to an emoji (probably width 2). So treat it as width 1 so the sums work. See #2652.
|
// (width 1) to an emoji (probably width 2). So treat it as width 1 so the sums work. See #2652.
|
||||||
// VS15 selects text presentation.
|
// VS15 selects text presentation.
|
||||||
const wchar_t variation_selector_16 = L'\uFE0F', variation_selector_15 = L'\uFE0E';
|
const wchar_t variation_selector_16 = L'\uFE0F', variation_selector_15 = L'\uFE0E';
|
||||||
if (wc == variation_selector_16) return 1;
|
if (wc == variation_selector_16)
|
||||||
else if (wc == variation_selector_15) return 0;
|
return 1;
|
||||||
|
else if (wc == variation_selector_15)
|
||||||
|
return 0;
|
||||||
|
|
||||||
// Korean Hangul Jamo median vowels and final consonants.
|
// Korean Hangul Jamo median vowels and final consonants.
|
||||||
// These can either appear in combined form, taking 0 width themselves,
|
// These can either appear in combined form, taking 0 width themselves,
|
||||||
|
|
|
@ -196,8 +196,8 @@ int flock(int fd, int op);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// NetBSD _has_ wcstod_l, but it's doing some weak linking hullabaloo that I don't get.
|
// NetBSD _has_ wcstod_l, but it's doing some weak linking hullabaloo that I don't get.
|
||||||
// Since it doesn't have uselocale (yes, the standard function isn't there, the non-standard extension is),
|
// Since it doesn't have uselocale (yes, the standard function isn't there, the non-standard
|
||||||
// we can't try to use the fallback.
|
// extension is), we can't try to use the fallback.
|
||||||
#if !defined(HAVE_WCSTOD_L) && !defined(__NetBSD__)
|
#if !defined(HAVE_WCSTOD_L) && !defined(__NetBSD__)
|
||||||
// On some platforms if this is incorrectly detected and a system-defined
|
// On some platforms if this is incorrectly detected and a system-defined
|
||||||
// defined version of `wcstod_l` exists, calling `wcstod` from our own
|
// defined version of `wcstod_l` exists, calling `wcstod` from our own
|
||||||
|
@ -207,7 +207,7 @@ int flock(int fd, int op);
|
||||||
// duplication.
|
// duplication.
|
||||||
#undef wcstod_l
|
#undef wcstod_l
|
||||||
namespace fish_compat {
|
namespace fish_compat {
|
||||||
double wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc);
|
double wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc);
|
||||||
}
|
}
|
||||||
#define wcstod_l(x, y, z) fish_compat::wcstod_l(x, y, z)
|
#define wcstod_l(x, y, z) fish_compat::wcstod_l(x, y, z)
|
||||||
#endif
|
#endif
|
||||||
|
|
11
src/fish.cpp
11
src/fish.cpp
|
@ -27,10 +27,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -130,7 +130,9 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
|
||||||
#ifdef CMAKE_BINARY_DIR
|
#ifdef CMAKE_BINARY_DIR
|
||||||
// Detect if we're running right out of the CMAKE build directory
|
// Detect if we're running right out of the CMAKE build directory
|
||||||
if (string_prefixes_string(CMAKE_BINARY_DIR, exec_path.c_str())) {
|
if (string_prefixes_string(CMAKE_BINARY_DIR, exec_path.c_str())) {
|
||||||
debug(2, "Running out of build directory, using paths relative to CMAKE_SOURCE_DIR:\n %s", CMAKE_SOURCE_DIR);
|
debug(2,
|
||||||
|
"Running out of build directory, using paths relative to CMAKE_SOURCE_DIR:\n %s",
|
||||||
|
CMAKE_SOURCE_DIR);
|
||||||
|
|
||||||
done = true;
|
done = true;
|
||||||
paths.data = wcstring{L"" CMAKE_SOURCE_DIR} + L"/share";
|
paths.data = wcstring{L"" CMAKE_SOURCE_DIR} + L"/share";
|
||||||
|
@ -249,7 +251,7 @@ int run_command_list(std::vector<std::string> *cmds, const io_chain_t &io) {
|
||||||
|
|
||||||
/// Parse the argument list, return the index of the first non-flag arguments.
|
/// Parse the argument list, return the index of the first non-flag arguments.
|
||||||
static int fish_parse_opt(int argc, char **argv, fish_cmd_opts_t *opts) {
|
static int fish_parse_opt(int argc, char **argv, fish_cmd_opts_t *opts) {
|
||||||
static const char * const short_opts = "+hPilnvc:C:p:d:f:D:";
|
static const char *const short_opts = "+hPilnvc:C:p:d:f:D:";
|
||||||
static const struct option long_opts[] = {{"command", required_argument, NULL, 'c'},
|
static const struct option long_opts[] = {{"command", required_argument, NULL, 'c'},
|
||||||
{"init-command", required_argument, NULL, 'C'},
|
{"init-command", required_argument, NULL, 'C'},
|
||||||
{"features", required_argument, NULL, 'f'},
|
{"features", required_argument, NULL, 'f'},
|
||||||
|
@ -339,7 +341,8 @@ static int fish_parse_opt(int argc, char **argv, fish_cmd_opts_t *opts) {
|
||||||
if (tmp > 0 && tmp <= 128 && !*end && !errno) {
|
if (tmp > 0 && tmp <= 128 && !*end && !errno) {
|
||||||
set_debug_stack_frames((int)tmp);
|
set_debug_stack_frames((int)tmp);
|
||||||
} else {
|
} else {
|
||||||
std::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);
|
exit(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -23,15 +23,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
@ -119,8 +119,8 @@ struct prettifier_t {
|
||||||
line_continuation_indent = is_continuation ? 1 : 0;
|
line_continuation_indent = is_continuation ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append whitespace as necessary. If we have a newline, append the appropriate indent. Otherwise,
|
// Append whitespace as necessary. If we have a newline, append the appropriate indent.
|
||||||
// append a space.
|
// Otherwise, append a space.
|
||||||
void append_whitespace(indent_t node_indent) {
|
void append_whitespace(indent_t node_indent) {
|
||||||
if (needs_continuation_newline) {
|
if (needs_continuation_newline) {
|
||||||
append_newline(true);
|
append_newline(true);
|
||||||
|
@ -131,7 +131,6 @@ struct prettifier_t {
|
||||||
output.append((node_indent + line_continuation_indent) * SPACES_PER_INDENT, L' ');
|
output.append((node_indent + line_continuation_indent) * SPACES_PER_INDENT, L' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Dump a parse tree node in a form helpful to someone debugging the behavior of this program.
|
// Dump a parse tree node in a form helpful to someone debugging the behavior of this program.
|
||||||
|
@ -160,8 +159,9 @@ static void dump_node(indent_t node_indent, const parse_node_t &node, const wcst
|
||||||
nextc_str[2] = nextc + '@';
|
nextc_str[2] = nextc + '@';
|
||||||
}
|
}
|
||||||
std::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),
|
node.source_start, node.source_length, node_indent,
|
||||||
token_type_description(node.type), prevc_str, source_txt.c_str(), nextc_str);
|
keyword_description(node.keyword), token_type_description(node.type), prevc_str,
|
||||||
|
source_txt.c_str(), nextc_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void prettifier_t::prettify_node(const parse_node_tree_t &tree, node_offset_t node_idx,
|
void prettifier_t::prettify_node(const parse_node_tree_t &tree, node_offset_t node_idx,
|
||||||
|
@ -187,9 +187,10 @@ void prettifier_t::prettify_node(const parse_node_tree_t &tree, node_offset_t no
|
||||||
const parse_token_type_t prev_node_type =
|
const parse_token_type_t prev_node_type =
|
||||||
node_idx > 0 ? tree.at(node_idx - 1).type : token_type_invalid;
|
node_idx > 0 ? tree.at(node_idx - 1).type : token_type_invalid;
|
||||||
|
|
||||||
// Increment the indent if we are either a root job_list, or root case_item_list, or in an if or
|
// Increment the indent if we are either a root job_list, or root case_item_list, or in an
|
||||||
// while header (#1665).
|
// if or while header (#1665).
|
||||||
const bool is_root_job_list = node_type == symbol_job_list && parent_type != symbol_job_list;
|
const bool is_root_job_list =
|
||||||
|
node_type == symbol_job_list && parent_type != symbol_job_list;
|
||||||
const bool is_root_case_list =
|
const bool is_root_case_list =
|
||||||
node_type == symbol_case_item_list && parent_type != symbol_case_item_list;
|
node_type == symbol_case_item_list && parent_type != symbol_case_item_list;
|
||||||
const bool is_if_while_header =
|
const bool is_if_while_header =
|
||||||
|
@ -253,7 +254,8 @@ void prettifier_t::prettify_node(const parse_node_tree_t &tree, node_offset_t no
|
||||||
for (node_offset_t idx = node.child_count; idx > 0; idx--) {
|
for (node_offset_t idx = node.child_count; idx > 0; idx--) {
|
||||||
// Note: We pass our type to our child, which becomes its parent node type.
|
// 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
|
// 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.
|
// because we won't execute this call in that case since node.child_count should be
|
||||||
|
// zero.
|
||||||
pending_node_stack.push({node.child_start + (idx - 1), node_indent, node_type});
|
pending_node_stack.push({node.child_start + (idx - 1), node_indent, node_type});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,7 +437,9 @@ static const wchar_t *html_class_name_for_color(highlight_spec_t spec) {
|
||||||
case highlight_role_t::selection: {
|
case highlight_role_t::selection: {
|
||||||
return P(selection);
|
return P(selection);
|
||||||
}
|
}
|
||||||
default: { return P(other); }
|
default: {
|
||||||
|
return P(other);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,7 +597,8 @@ int main(int argc, char *argv[]) {
|
||||||
if (tmp > 0 && tmp <= 128 && !*end && !errno) {
|
if (tmp > 0 && tmp <= 128 && !*end && !errno) {
|
||||||
set_debug_stack_frames((int)tmp);
|
set_debug_stack_frames((int)tmp);
|
||||||
} else {
|
} else {
|
||||||
std::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);
|
exit(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -612,7 +617,8 @@ int main(int argc, char *argv[]) {
|
||||||
wcstring src;
|
wcstring src;
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
if (output_type == output_type_file) {
|
if (output_type == output_type_file) {
|
||||||
std::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);
|
program_name);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -191,7 +191,8 @@ static double output_elapsed_time(double prev_tstamp, bool first_char_seen) {
|
||||||
if (delta_tstamp_us >= 1000000) {
|
if (delta_tstamp_us >= 1000000) {
|
||||||
std::fwprintf(stderr, L" ");
|
std::fwprintf(stderr, L" ");
|
||||||
} else {
|
} else {
|
||||||
std::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;
|
return now;
|
||||||
}
|
}
|
||||||
|
@ -293,7 +294,8 @@ static void setup_and_process_keys(bool continuous_mode) {
|
||||||
|
|
||||||
if (continuous_mode) {
|
if (continuous_mode) {
|
||||||
std::fwprintf(stderr, L"\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"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",
|
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);
|
shell_modes.c_cc[VINTR] + 0x40, shell_modes.c_cc[VEOF] + 0x40);
|
||||||
std::fwprintf(stderr, L"\n");
|
std::fwprintf(stderr, L"\n");
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
@ -23,8 +22,9 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cwchar>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -494,7 +494,7 @@ static char *str2hex(const char *input) {
|
||||||
/// comes back through double conversion.
|
/// comes back through double conversion.
|
||||||
static void test_convert() {
|
static void test_convert() {
|
||||||
int i;
|
int i;
|
||||||
std::vector<char> sb {};
|
std::vector<char> sb{};
|
||||||
|
|
||||||
say(L"Testing wide/narrow string conversion");
|
say(L"Testing wide/narrow string conversion");
|
||||||
|
|
||||||
|
@ -612,7 +612,8 @@ static void test_tokenizer() {
|
||||||
}
|
}
|
||||||
if (types[i] != token.type) {
|
if (types[i] != token.type) {
|
||||||
err(L"Tokenization error:");
|
err(L"Tokenization error:");
|
||||||
std::fwprintf(stdout,
|
std::fwprintf(
|
||||||
|
stdout,
|
||||||
L"Token number %zu of string \n'%ls'\n, expected type %ld, got token type "
|
L"Token number %zu of string \n'%ls'\n, expected type %ld, got token type "
|
||||||
L"%ld\n",
|
L"%ld\n",
|
||||||
i + 1, str, (long)types[i], (long)token.type);
|
i + 1, str, (long)types[i], (long)token.type);
|
||||||
|
@ -734,9 +735,7 @@ static void test_pthread() {
|
||||||
say(L"Testing pthreads");
|
say(L"Testing pthreads");
|
||||||
pthread_t result = {};
|
pthread_t result = {};
|
||||||
int val = 3;
|
int val = 3;
|
||||||
bool made = make_pthread(&result, [&val](){
|
bool made = make_pthread(&result, [&val]() { val += 2; });
|
||||||
val += 2;
|
|
||||||
});
|
|
||||||
do_test(made);
|
do_test(made);
|
||||||
void *ignore = nullptr;
|
void *ignore = nullptr;
|
||||||
int ret = pthread_join(result, &ignore);
|
int ret = pthread_join(result, &ignore);
|
||||||
|
@ -1900,18 +1899,20 @@ static void test_abbreviations() {
|
||||||
err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str());
|
err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str());
|
||||||
|
|
||||||
// If commands should be expanded.
|
// If commands should be expanded.
|
||||||
expanded = reader_expand_abbreviation_in_command(L"if gc", std::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 (!expanded) err(L"gc not expanded on line %ld", (long)__LINE__);
|
||||||
if (result != L"if git checkout")
|
if (result != L"if git checkout")
|
||||||
err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str());
|
err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str());
|
||||||
|
|
||||||
// Others should not be.
|
// Others should not be.
|
||||||
expanded = reader_expand_abbreviation_in_command(L"of gc", std::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__);
|
if (expanded) err(L"gc incorrectly expanded on line %ld", (long)__LINE__);
|
||||||
|
|
||||||
// Others should not be.
|
// Others should not be.
|
||||||
expanded =
|
expanded = reader_expand_abbreviation_in_command(L"command gc", std::wcslen(L"command gc"),
|
||||||
reader_expand_abbreviation_in_command(L"command gc", std::wcslen(L"command gc"), vars, &result);
|
vars, &result);
|
||||||
if (expanded) err(L"gc incorrectly expanded on line %ld", (long)__LINE__);
|
if (expanded) err(L"gc incorrectly expanded on line %ld", (long)__LINE__);
|
||||||
|
|
||||||
vars.pop();
|
vars.pop();
|
||||||
|
@ -2252,8 +2253,7 @@ static bool run_one_test_test(int expected, wcstring_list_t &lst, bool bracket)
|
||||||
io_streams_t streams(0);
|
io_streams_t streams(0);
|
||||||
int result = builtin_test(parser, streams, argv);
|
int result = builtin_test(parser, streams, argv);
|
||||||
|
|
||||||
if (expected != result)
|
if (expected != result) err(L"expected builtin_test() to return %d, got %d", expected, result);
|
||||||
err(L"expected builtin_test() to return %d, got %d", expected, result);
|
|
||||||
|
|
||||||
delete[] argv;
|
delete[] argv;
|
||||||
|
|
||||||
|
@ -2759,8 +2759,8 @@ static void perform_one_autosuggestion_cd_test(const wcstring &command, const wc
|
||||||
bool expects_error = (expected == L"<error>");
|
bool expects_error = (expected == L"<error>");
|
||||||
|
|
||||||
if (comps.empty() && !expects_error) {
|
if (comps.empty() && !expects_error) {
|
||||||
std::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",
|
||||||
command.c_str());
|
line, command.c_str());
|
||||||
do_test_from(!comps.empty(), line);
|
do_test_from(!comps.empty(), line);
|
||||||
return;
|
return;
|
||||||
} else if (!comps.empty() && expects_error) {
|
} else if (!comps.empty() && expects_error) {
|
||||||
|
@ -2795,8 +2795,8 @@ static void perform_one_completion_cd_test(const wcstring &command, const wcstri
|
||||||
bool expects_error = (expected == L"<error>");
|
bool expects_error = (expected == L"<error>");
|
||||||
|
|
||||||
if (comps.empty() && !expects_error) {
|
if (comps.empty() && !expects_error) {
|
||||||
std::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",
|
||||||
command.c_str());
|
line, command.c_str());
|
||||||
do_test_from(!comps.empty(), line);
|
do_test_from(!comps.empty(), line);
|
||||||
return;
|
return;
|
||||||
} else if (!comps.empty() && expects_error) {
|
} else if (!comps.empty() && expects_error) {
|
||||||
|
@ -4547,7 +4547,7 @@ static void test_pcre2_escape() {
|
||||||
|
|
||||||
// all the following are intended to be ultimately matched literally - even if they don't look
|
// all the following are intended to be ultimately matched literally - even if they don't look
|
||||||
// like that's the intent - so we escape them.
|
// like that's the intent - so we escape them.
|
||||||
const wchar_t * const tests[][2] = {
|
const wchar_t *const tests[][2] = {
|
||||||
{L".ext", L"\\.ext"},
|
{L".ext", L"\\.ext"},
|
||||||
{L"{word}", L"\\{word\\}"},
|
{L"{word}", L"\\{word\\}"},
|
||||||
{L"hola-mundo", L"hola\\-mundo"},
|
{L"hola-mundo", L"hola\\-mundo"},
|
||||||
|
@ -4558,7 +4558,8 @@ static void test_pcre2_escape() {
|
||||||
for (const auto &test : tests) {
|
for (const auto &test : tests) {
|
||||||
auto escaped = escape_string(test[0], 0, STRING_STYLE_REGEX);
|
auto escaped = escape_string(test[0], 0, STRING_STYLE_REGEX);
|
||||||
if (escaped != test[1]) {
|
if (escaped != test[1]) {
|
||||||
err(L"pcre2_escape error: pcre2_escape(%ls) -> %ls, expected %ls", test[0], escaped.c_str(), test[1]);
|
err(L"pcre2_escape error: pcre2_escape(%ls) -> %ls, expected %ls", test[0],
|
||||||
|
escaped.c_str(), test[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4947,9 +4948,9 @@ static void test_env_vars() {
|
||||||
env_var_t v2 = {wcstring_list_t{L"abc"}, env_var_t::flag_export};
|
env_var_t v2 = {wcstring_list_t{L"abc"}, env_var_t::flag_export};
|
||||||
env_var_t v3 = {wcstring_list_t{L"abc"}, 0};
|
env_var_t v3 = {wcstring_list_t{L"abc"}, 0};
|
||||||
env_var_t v4 = {wcstring_list_t{L"abc", L"def"}, env_var_t::flag_export};
|
env_var_t v4 = {wcstring_list_t{L"abc", L"def"}, env_var_t::flag_export};
|
||||||
do_test(v1 == v2 && ! (v1 != v2));
|
do_test(v1 == v2 && !(v1 != v2));
|
||||||
do_test(v1 != v3 && ! (v1 == v3));
|
do_test(v1 != v3 && !(v1 == v3));
|
||||||
do_test(v1 != v4 && ! (v1 == v4));
|
do_test(v1 != v4 && !(v1 == v4));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_illegal_command_exit_code() {
|
static void test_illegal_command_exit_code() {
|
||||||
|
@ -5211,8 +5212,8 @@ int main(int argc, char **argv) {
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
if (!std::strcmp(wd, "/")) {
|
if (!std::strcmp(wd, "/")) {
|
||||||
std::fwprintf(stderr,
|
std::fwprintf(
|
||||||
L"Unable to find 'tests' directory, which should contain file test.fish\n");
|
stderr, L"Unable to find 'tests' directory, which should contain file test.fish\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (chdir(dirname(wd)) < 0) {
|
if (chdir(dirname(wd)) < 0) {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// The contents of FISH-BUILD-VERSION-FILE looks like:
|
// The contents of FISH-BUILD-VERSION-FILE looks like:
|
||||||
// FISH_BUILD_VERSION="2.7.1-62-gc0480092-dirty"
|
// FISH_BUILD_VERSION="2.7.1-62-gc0480092-dirty"
|
||||||
// Arrange for it to become a variable.
|
// Arrange for it to become a variable.
|
||||||
static const char * const
|
static const char *const
|
||||||
#include "FISH-BUILD-VERSION-FILE"
|
#include "FISH-BUILD-VERSION-FILE"
|
||||||
;
|
;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,7 +13,8 @@ features_t &mutable_fish_features() { return global_features; }
|
||||||
const features_t::metadata_t features_t::metadata[features_t::flag_count] = {
|
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"},
|
{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"},
|
{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"},
|
{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) {
|
const struct features_t::metadata_t *features_t::metadata_for(const wchar_t *name) {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
class features_t {
|
class features_t {
|
||||||
public:
|
public:
|
||||||
/// The list of flags.
|
/// The list of flags.
|
||||||
enum flag_t {
|
enum flag_t {
|
||||||
/// Whether ^ is supported for stderr redirection.
|
/// Whether ^ is supported for stderr redirection.
|
||||||
|
|
|
@ -1247,7 +1247,9 @@ const highlighter_t::color_array_t &highlighter_t::highlight() {
|
||||||
this->color_node(node, highlight_role_t::comment);
|
this->color_node(node, highlight_role_t::comment);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: { break; }
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
// We need the sys/file.h for the flock() declaration on Linux but not OS X.
|
// We need the sys/file.h for the flock() declaration on Linux but not OS X.
|
||||||
#include <sys/file.h> // IWYU pragma: keep
|
#include <sys/file.h> // IWYU pragma: keep
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
@ -554,7 +554,6 @@ bool history_item_t::merge(const history_item_t &item) {
|
||||||
|
|
||||||
history_item_t::history_item_t(const wcstring &str, time_t when, history_identifier_t ident)
|
history_item_t::history_item_t(const wcstring &str, time_t when, history_identifier_t ident)
|
||||||
: creation_timestamp(when), identifier(ident) {
|
: creation_timestamp(when), identifier(ident) {
|
||||||
|
|
||||||
contents = trim(str);
|
contents = trim(str);
|
||||||
contents_lower.reserve(contents.size());
|
contents_lower.reserve(contents.size());
|
||||||
for (const auto &c : contents) {
|
for (const auto &c : contents) {
|
||||||
|
@ -1971,7 +1970,6 @@ void history_t::resolve_pending() {
|
||||||
this->has_pending_item = false;
|
this->has_pending_item = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static std::atomic<bool> private_mode{false};
|
static std::atomic<bool> private_mode{false};
|
||||||
|
|
||||||
void start_private_mode() {
|
void start_private_mode() {
|
||||||
|
@ -1981,6 +1979,4 @@ void start_private_mode() {
|
||||||
vars.set_one(L"fish_private_mode", ENV_GLOBAL, L"1");
|
vars.set_one(L"fish_private_mode", ENV_GLOBAL, L"1");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool in_private_mode() {
|
bool in_private_mode() { return private_mode.load(); }
|
||||||
return private_mode.load();
|
|
||||||
}
|
|
||||||
|
|
159
src/input.cpp
159
src/input.cpp
|
@ -2,8 +2,8 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cwchar>
|
||||||
#if HAVE_TERM_H
|
#if HAVE_TERM_H
|
||||||
#include <curses.h>
|
#include <curses.h>
|
||||||
#include <term.h>
|
#include <term.h>
|
||||||
|
@ -229,7 +229,7 @@ void input_mapping_add(const wchar_t *sequence, const wchar_t *const *commands,
|
||||||
|
|
||||||
mapping_list_t &ml = user ? s_mapping_list : s_preset_mapping_list;
|
mapping_list_t &ml = user ? s_mapping_list : s_preset_mapping_list;
|
||||||
|
|
||||||
for (input_mapping_t& m : ml) {
|
for (input_mapping_t &m : ml) {
|
||||||
if (m.seq == sequence && m.mode == mode) {
|
if (m.seq == sequence && m.mode == mode) {
|
||||||
m.commands = commands_vector;
|
m.commands = commands_vector;
|
||||||
m.sets_mode = sets_mode;
|
m.sets_mode = sets_mode;
|
||||||
|
@ -289,7 +289,8 @@ void init_input() {
|
||||||
input_mapping_add(L"\x3", L"commandline ''", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
input_mapping_add(L"\x3", L"commandline ''", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||||
input_mapping_add(L"\x4", L"exit", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
input_mapping_add(L"\x4", L"exit", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||||
input_mapping_add(L"\x5", L"bind", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
input_mapping_add(L"\x5", L"bind", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||||
input_mapping_add(L"\x7f", L"backward-delete-char", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
input_mapping_add(L"\x7f", L"backward-delete-char", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE,
|
||||||
|
false);
|
||||||
// Arrows - can't have functions, so *-or-search isn't available.
|
// Arrows - can't have functions, so *-or-search isn't available.
|
||||||
input_mapping_add(L"\x1B[A", L"up-line", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
input_mapping_add(L"\x1B[A", L"up-line", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||||
input_mapping_add(L"\x1B[B", L"down-line", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
input_mapping_add(L"\x1B[B", L"down-line", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||||
|
@ -498,7 +499,9 @@ char_event_t input_readch(bool allow_commands) {
|
||||||
input_common_next_ch(evt);
|
input_common_next_ch(evt);
|
||||||
return input_readch();
|
return input_readch();
|
||||||
}
|
}
|
||||||
default: { return evt; }
|
default: {
|
||||||
|
return evt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (evt.is_eof()) {
|
} else if (evt.is_eof()) {
|
||||||
// If we have EOF, we need to immediately quit.
|
// If we have EOF, we need to immediately quit.
|
||||||
|
@ -540,8 +543,7 @@ bool input_mapping_erase(const wcstring &sequence, const wcstring &mode, bool us
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
bool result = false;
|
bool result = false;
|
||||||
mapping_list_t &ml = user ? s_mapping_list : s_preset_mapping_list;
|
mapping_list_t &ml = user ? s_mapping_list : s_preset_mapping_list;
|
||||||
for (std::vector<input_mapping_t>::iterator it = ml.begin(), end = ml.end();
|
for (std::vector<input_mapping_t>::iterator it = ml.begin(), end = ml.end(); it != end; ++it) {
|
||||||
it != end; ++it) {
|
|
||||||
if (sequence == it->seq && mode == it->mode) {
|
if (sequence == it->seq && mode == it->mode) {
|
||||||
ml.erase(it);
|
ml.erase(it);
|
||||||
result = true;
|
result = true;
|
||||||
|
@ -551,8 +553,8 @@ bool input_mapping_erase(const wcstring &sequence, const wcstring &mode, bool us
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool input_mapping_get(const wcstring &sequence, const wcstring &mode, wcstring_list_t *out_cmds, bool user,
|
bool input_mapping_get(const wcstring &sequence, const wcstring &mode, wcstring_list_t *out_cmds,
|
||||||
wcstring *out_sets_mode) {
|
bool user, wcstring *out_sets_mode) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
mapping_list_t &ml = user ? s_mapping_list : s_preset_mapping_list;
|
mapping_list_t &ml = user ? s_mapping_list : s_preset_mapping_list;
|
||||||
for (const input_mapping_t &m : ml) {
|
for (const input_mapping_t &m : ml) {
|
||||||
|
@ -571,52 +573,21 @@ static std::vector<terminfo_mapping_t> create_input_terminfo() {
|
||||||
assert(curses_initialized);
|
assert(curses_initialized);
|
||||||
if (!cur_term) return {}; // setupterm() failed so we can't referency any key definitions
|
if (!cur_term) return {}; // setupterm() failed so we can't referency any key definitions
|
||||||
return {
|
return {
|
||||||
TERMINFO_ADD(key_a1),
|
TERMINFO_ADD(key_a1), TERMINFO_ADD(key_a3), TERMINFO_ADD(key_b2),
|
||||||
TERMINFO_ADD(key_a3),
|
TERMINFO_ADD(key_backspace), TERMINFO_ADD(key_beg), TERMINFO_ADD(key_btab),
|
||||||
TERMINFO_ADD(key_b2),
|
TERMINFO_ADD(key_c1), TERMINFO_ADD(key_c3), TERMINFO_ADD(key_cancel),
|
||||||
TERMINFO_ADD(key_backspace),
|
TERMINFO_ADD(key_catab), TERMINFO_ADD(key_clear), TERMINFO_ADD(key_close),
|
||||||
TERMINFO_ADD(key_beg),
|
TERMINFO_ADD(key_command), TERMINFO_ADD(key_copy), TERMINFO_ADD(key_create),
|
||||||
TERMINFO_ADD(key_btab),
|
TERMINFO_ADD(key_ctab), TERMINFO_ADD(key_dc), TERMINFO_ADD(key_dl),
|
||||||
TERMINFO_ADD(key_c1),
|
TERMINFO_ADD(key_down), TERMINFO_ADD(key_eic), TERMINFO_ADD(key_end),
|
||||||
TERMINFO_ADD(key_c3),
|
TERMINFO_ADD(key_enter), TERMINFO_ADD(key_eol), TERMINFO_ADD(key_eos),
|
||||||
TERMINFO_ADD(key_cancel),
|
TERMINFO_ADD(key_exit), TERMINFO_ADD(key_f0), TERMINFO_ADD(key_f1),
|
||||||
TERMINFO_ADD(key_catab),
|
TERMINFO_ADD(key_f2), TERMINFO_ADD(key_f3), TERMINFO_ADD(key_f4), TERMINFO_ADD(key_f5),
|
||||||
TERMINFO_ADD(key_clear),
|
TERMINFO_ADD(key_f6), TERMINFO_ADD(key_f7), TERMINFO_ADD(key_f8), TERMINFO_ADD(key_f9),
|
||||||
TERMINFO_ADD(key_close),
|
TERMINFO_ADD(key_f10), TERMINFO_ADD(key_f11), TERMINFO_ADD(key_f12),
|
||||||
TERMINFO_ADD(key_command),
|
TERMINFO_ADD(key_f13), TERMINFO_ADD(key_f14), TERMINFO_ADD(key_f15),
|
||||||
TERMINFO_ADD(key_copy),
|
TERMINFO_ADD(key_f16), TERMINFO_ADD(key_f17), TERMINFO_ADD(key_f18),
|
||||||
TERMINFO_ADD(key_create),
|
TERMINFO_ADD(key_f19), TERMINFO_ADD(key_f20),
|
||||||
TERMINFO_ADD(key_ctab),
|
|
||||||
TERMINFO_ADD(key_dc),
|
|
||||||
TERMINFO_ADD(key_dl),
|
|
||||||
TERMINFO_ADD(key_down),
|
|
||||||
TERMINFO_ADD(key_eic),
|
|
||||||
TERMINFO_ADD(key_end),
|
|
||||||
TERMINFO_ADD(key_enter),
|
|
||||||
TERMINFO_ADD(key_eol),
|
|
||||||
TERMINFO_ADD(key_eos),
|
|
||||||
TERMINFO_ADD(key_exit),
|
|
||||||
TERMINFO_ADD(key_f0),
|
|
||||||
TERMINFO_ADD(key_f1),
|
|
||||||
TERMINFO_ADD(key_f2),
|
|
||||||
TERMINFO_ADD(key_f3),
|
|
||||||
TERMINFO_ADD(key_f4),
|
|
||||||
TERMINFO_ADD(key_f5),
|
|
||||||
TERMINFO_ADD(key_f6),
|
|
||||||
TERMINFO_ADD(key_f7),
|
|
||||||
TERMINFO_ADD(key_f8),
|
|
||||||
TERMINFO_ADD(key_f9),
|
|
||||||
TERMINFO_ADD(key_f10),
|
|
||||||
TERMINFO_ADD(key_f11),
|
|
||||||
TERMINFO_ADD(key_f12),
|
|
||||||
TERMINFO_ADD(key_f13),
|
|
||||||
TERMINFO_ADD(key_f14),
|
|
||||||
TERMINFO_ADD(key_f15),
|
|
||||||
TERMINFO_ADD(key_f16),
|
|
||||||
TERMINFO_ADD(key_f17),
|
|
||||||
TERMINFO_ADD(key_f18),
|
|
||||||
TERMINFO_ADD(key_f19),
|
|
||||||
TERMINFO_ADD(key_f20),
|
|
||||||
#if 0
|
#if 0
|
||||||
// I know of no keyboard with more than 20 function keys, so adding the rest here makes very
|
// I know of no keyboard with more than 20 function keys, so adding the rest here makes very
|
||||||
// little sense, since it will take up a lot of room in any listings (like tab completions),
|
// little sense, since it will take up a lot of room in any listings (like tab completions),
|
||||||
|
@ -665,66 +636,26 @@ static std::vector<terminfo_mapping_t> create_input_terminfo() {
|
||||||
TERMINFO_ADD(key_f62),
|
TERMINFO_ADD(key_f62),
|
||||||
TERMINFO_ADD(key_f63),
|
TERMINFO_ADD(key_f63),
|
||||||
#endif
|
#endif
|
||||||
TERMINFO_ADD(key_find),
|
TERMINFO_ADD(key_find), TERMINFO_ADD(key_help), TERMINFO_ADD(key_home),
|
||||||
TERMINFO_ADD(key_help),
|
TERMINFO_ADD(key_ic), TERMINFO_ADD(key_il), TERMINFO_ADD(key_left),
|
||||||
TERMINFO_ADD(key_home),
|
TERMINFO_ADD(key_ll), TERMINFO_ADD(key_mark), TERMINFO_ADD(key_message),
|
||||||
TERMINFO_ADD(key_ic),
|
TERMINFO_ADD(key_move), TERMINFO_ADD(key_next), TERMINFO_ADD(key_npage),
|
||||||
TERMINFO_ADD(key_il),
|
TERMINFO_ADD(key_open), TERMINFO_ADD(key_options), TERMINFO_ADD(key_ppage),
|
||||||
TERMINFO_ADD(key_left),
|
TERMINFO_ADD(key_previous), TERMINFO_ADD(key_print), TERMINFO_ADD(key_redo),
|
||||||
TERMINFO_ADD(key_ll),
|
TERMINFO_ADD(key_reference), TERMINFO_ADD(key_refresh), TERMINFO_ADD(key_replace),
|
||||||
TERMINFO_ADD(key_mark),
|
TERMINFO_ADD(key_restart), TERMINFO_ADD(key_resume), TERMINFO_ADD(key_right),
|
||||||
TERMINFO_ADD(key_message),
|
TERMINFO_ADD(key_save), TERMINFO_ADD(key_sbeg), TERMINFO_ADD(key_scancel),
|
||||||
TERMINFO_ADD(key_move),
|
TERMINFO_ADD(key_scommand), TERMINFO_ADD(key_scopy), TERMINFO_ADD(key_screate),
|
||||||
TERMINFO_ADD(key_next),
|
TERMINFO_ADD(key_sdc), TERMINFO_ADD(key_sdl), TERMINFO_ADD(key_select),
|
||||||
TERMINFO_ADD(key_npage),
|
TERMINFO_ADD(key_send), TERMINFO_ADD(key_seol), TERMINFO_ADD(key_sexit),
|
||||||
TERMINFO_ADD(key_open),
|
TERMINFO_ADD(key_sf), TERMINFO_ADD(key_sfind), TERMINFO_ADD(key_shelp),
|
||||||
TERMINFO_ADD(key_options),
|
TERMINFO_ADD(key_shome), TERMINFO_ADD(key_sic), TERMINFO_ADD(key_sleft),
|
||||||
TERMINFO_ADD(key_ppage),
|
TERMINFO_ADD(key_smessage), TERMINFO_ADD(key_smove), TERMINFO_ADD(key_snext),
|
||||||
TERMINFO_ADD(key_previous),
|
TERMINFO_ADD(key_soptions), TERMINFO_ADD(key_sprevious), TERMINFO_ADD(key_sprint),
|
||||||
TERMINFO_ADD(key_print),
|
TERMINFO_ADD(key_sr), TERMINFO_ADD(key_sredo), TERMINFO_ADD(key_sreplace),
|
||||||
TERMINFO_ADD(key_redo),
|
TERMINFO_ADD(key_sright), TERMINFO_ADD(key_srsume), TERMINFO_ADD(key_ssave),
|
||||||
TERMINFO_ADD(key_reference),
|
TERMINFO_ADD(key_ssuspend), TERMINFO_ADD(key_stab), TERMINFO_ADD(key_sundo),
|
||||||
TERMINFO_ADD(key_refresh),
|
TERMINFO_ADD(key_suspend), TERMINFO_ADD(key_undo), TERMINFO_ADD(key_up)
|
||||||
TERMINFO_ADD(key_replace),
|
|
||||||
TERMINFO_ADD(key_restart),
|
|
||||||
TERMINFO_ADD(key_resume),
|
|
||||||
TERMINFO_ADD(key_right),
|
|
||||||
TERMINFO_ADD(key_save),
|
|
||||||
TERMINFO_ADD(key_sbeg),
|
|
||||||
TERMINFO_ADD(key_scancel),
|
|
||||||
TERMINFO_ADD(key_scommand),
|
|
||||||
TERMINFO_ADD(key_scopy),
|
|
||||||
TERMINFO_ADD(key_screate),
|
|
||||||
TERMINFO_ADD(key_sdc),
|
|
||||||
TERMINFO_ADD(key_sdl),
|
|
||||||
TERMINFO_ADD(key_select),
|
|
||||||
TERMINFO_ADD(key_send),
|
|
||||||
TERMINFO_ADD(key_seol),
|
|
||||||
TERMINFO_ADD(key_sexit),
|
|
||||||
TERMINFO_ADD(key_sf),
|
|
||||||
TERMINFO_ADD(key_sfind),
|
|
||||||
TERMINFO_ADD(key_shelp),
|
|
||||||
TERMINFO_ADD(key_shome),
|
|
||||||
TERMINFO_ADD(key_sic),
|
|
||||||
TERMINFO_ADD(key_sleft),
|
|
||||||
TERMINFO_ADD(key_smessage),
|
|
||||||
TERMINFO_ADD(key_smove),
|
|
||||||
TERMINFO_ADD(key_snext),
|
|
||||||
TERMINFO_ADD(key_soptions),
|
|
||||||
TERMINFO_ADD(key_sprevious),
|
|
||||||
TERMINFO_ADD(key_sprint),
|
|
||||||
TERMINFO_ADD(key_sr),
|
|
||||||
TERMINFO_ADD(key_sredo),
|
|
||||||
TERMINFO_ADD(key_sreplace),
|
|
||||||
TERMINFO_ADD(key_sright),
|
|
||||||
TERMINFO_ADD(key_srsume),
|
|
||||||
TERMINFO_ADD(key_ssave),
|
|
||||||
TERMINFO_ADD(key_ssuspend),
|
|
||||||
TERMINFO_ADD(key_stab),
|
|
||||||
TERMINFO_ADD(key_sundo),
|
|
||||||
TERMINFO_ADD(key_suspend),
|
|
||||||
TERMINFO_ADD(key_undo),
|
|
||||||
TERMINFO_ADD(key_up)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,12 +63,13 @@ std::vector<input_mapping_name_t> input_mapping_get_names(bool user = true);
|
||||||
void input_mapping_clear(const wchar_t *mode = NULL, bool user = true);
|
void input_mapping_clear(const wchar_t *mode = NULL, bool user = true);
|
||||||
|
|
||||||
/// Erase binding for specified key sequence.
|
/// Erase binding for specified key sequence.
|
||||||
bool input_mapping_erase(const wcstring &sequence, const wcstring &mode = DEFAULT_BIND_MODE, bool user = true);
|
bool input_mapping_erase(const wcstring &sequence, const wcstring &mode = DEFAULT_BIND_MODE,
|
||||||
|
bool user = true);
|
||||||
|
|
||||||
/// Gets the command bound to the specified key sequence in the specified mode. Returns true if it
|
/// Gets the command bound to the specified key sequence in the specified mode. Returns true if it
|
||||||
/// exists, false if not.
|
/// exists, false if not.
|
||||||
bool input_mapping_get(const wcstring &sequence, const wcstring &mode, wcstring_list_t *out_cmds, bool user,
|
bool input_mapping_get(const wcstring &sequence, const wcstring &mode, wcstring_list_t *out_cmds,
|
||||||
wcstring *out_new_mode);
|
bool user, wcstring *out_new_mode);
|
||||||
|
|
||||||
/// Return the current bind mode.
|
/// Return the current bind mode.
|
||||||
wcstring input_get_bind_mode(const environment_t &vars);
|
wcstring input_get_bind_mode(const environment_t &vars);
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <cstring>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
#ifdef HAVE_SYS_SELECT_H
|
#ifdef HAVE_SYS_SELECT_H
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -208,7 +208,9 @@ char_event_t input_common_readch() {
|
||||||
case 0: {
|
case 0: {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
default: { return res; }
|
default: {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/io.cpp
10
src/io.cpp
|
@ -4,8 +4,8 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <cstring>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
@ -49,7 +49,8 @@ void io_buffer_t::run_background_fillthread(autoclose_fd_t readfd) {
|
||||||
// 3. read until EAGAIN (would block), appending
|
// 3. read until EAGAIN (would block), appending
|
||||||
// 4. release the lock
|
// 4. release the lock
|
||||||
// The purpose of holding the lock around the read calls is to ensure that data from background
|
// The purpose of holding the lock around the read calls is to ensure that data from background
|
||||||
// processes isn't weirdly interspersed with data directly transferred (from a builtin to a buffer).
|
// processes isn't weirdly interspersed with data directly transferred (from a builtin to a
|
||||||
|
// buffer).
|
||||||
|
|
||||||
const int fd = readfd.fd();
|
const int fd = readfd.fd();
|
||||||
|
|
||||||
|
@ -90,7 +91,7 @@ void io_buffer_t::run_background_fillthread(autoclose_fd_t readfd) {
|
||||||
// It's important that if select() indicated we were readable, that we call select() again
|
// It's important that if select() indicated we were readable, that we call select() again
|
||||||
// allowing it to time out. Note the typical case is that the fd will be closed, in which
|
// allowing it to time out. Note the typical case is that the fd will be closed, in which
|
||||||
// case select will return immediately.
|
// case select will return immediately.
|
||||||
if (! readable) {
|
if (!readable) {
|
||||||
shutdown = this->shutdown_fillthread_.load(std::memory_order_relaxed);
|
shutdown = this->shutdown_fillthread_.load(std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +192,7 @@ io_pipe_t::~io_pipe_t() = default;
|
||||||
io_bufferfill_t::~io_bufferfill_t() = default;
|
io_bufferfill_t::~io_bufferfill_t() = default;
|
||||||
|
|
||||||
io_buffer_t::~io_buffer_t() {
|
io_buffer_t::~io_buffer_t() {
|
||||||
assert(! fillthread_ && "io_buffer_t destroyed with outstanding fillthread");
|
assert(!fillthread_ && "io_buffer_t destroyed with outstanding fillthread");
|
||||||
}
|
}
|
||||||
|
|
||||||
void io_chain_t::remove(const shared_ptr<const io_data_t> &element) {
|
void io_chain_t::remove(const shared_ptr<const io_data_t> &element) {
|
||||||
|
@ -247,7 +248,6 @@ void io_print(const io_chain_t &chain)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int move_fd_to_unused(int fd, const io_chain_t &io_chain, bool cloexec) {
|
int move_fd_to_unused(int fd, const io_chain_t &io_chain, bool cloexec) {
|
||||||
if (fd < 0 || io_chain.get_io_for_fd(fd).get() == NULL) {
|
if (fd < 0 || io_chain.get_io_for_fd(fd).get() == NULL) {
|
||||||
return fd;
|
return fd;
|
||||||
|
|
9
src/io.h
9
src/io.h
|
@ -76,7 +76,7 @@ class separated_buffer_t {
|
||||||
separated_buffer_t(const separated_buffer_t &) = delete;
|
separated_buffer_t(const separated_buffer_t &) = delete;
|
||||||
void operator=(const separated_buffer_t &) = delete;
|
void operator=(const separated_buffer_t &) = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Construct a separated_buffer_t with the given buffer limit \p limit, or 0 for no limit.
|
/// Construct a separated_buffer_t with the given buffer limit \p limit, or 0 for no limit.
|
||||||
separated_buffer_t(size_t limit) : buffer_limit_(limit) {}
|
separated_buffer_t(size_t limit) : buffer_limit_(limit) {}
|
||||||
|
|
||||||
|
@ -96,9 +96,7 @@ public:
|
||||||
discard = true;
|
discard = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset_discard() {
|
void reset_discard() { discard = false; }
|
||||||
discard = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serialize the contents to a single string, where explicitly separated elements have a
|
/// Serialize the contents to a single string, where explicitly separated elements have a
|
||||||
/// newline appended.
|
/// newline appended.
|
||||||
|
@ -122,7 +120,8 @@ public:
|
||||||
void append(Iterator begin, Iterator end, separation_type_t sep = separation_type_t::inferred) {
|
void append(Iterator begin, Iterator end, separation_type_t sep = separation_type_t::inferred) {
|
||||||
if (!try_add_size(std::distance(begin, end))) return;
|
if (!try_add_size(std::distance(begin, end))) return;
|
||||||
// Try merging with the last element.
|
// Try merging with the last element.
|
||||||
if (sep == separation_type_t::inferred && !elements_.empty() && !elements_.back().is_explicitly_separated()) {
|
if (sep == separation_type_t::inferred && !elements_.empty() &&
|
||||||
|
!elements_.back().is_explicitly_separated()) {
|
||||||
elements_.back().contents.append(begin, end);
|
elements_.back().contents.append(begin, end);
|
||||||
} else {
|
} else {
|
||||||
elements_.emplace_back(StringType(begin, end), sep);
|
elements_.emplace_back(StringType(begin, end), sep);
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <cstring>
|
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
|
@ -191,9 +191,9 @@ class maybe_t : private maybe_detail::conditionally_copyable_t<T> {
|
||||||
|
|
||||||
// Helper to replace missing_or_empty() on env_var_t.
|
// Helper to replace missing_or_empty() on env_var_t.
|
||||||
// Uses SFINAE to only introduce this function if T has an empty() type.
|
// Uses SFINAE to only introduce this function if T has an empty() type.
|
||||||
template<typename S = T>
|
template <typename S = T>
|
||||||
decltype(S().empty(), bool()) missing_or_empty() const {
|
decltype(S().empty(), bool()) missing_or_empty() const {
|
||||||
return ! has_value() || value().empty();
|
return !has_value() || value().empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare values for equality.
|
// Compare values for equality.
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
// IWYU pragma: no_include <cstddef>
|
// IWYU pragma: no_include <cstddef>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
@ -163,12 +163,11 @@ line_t pager_t::completion_print_item(const wcstring &prefix, const comp_t *c, s
|
||||||
const wcstring &comp = c->comp.at(i);
|
const wcstring &comp = c->comp.at(i);
|
||||||
|
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
comp_remaining -= print_max(PAGER_SPACER_STRING, bg, comp_remaining,
|
comp_remaining -=
|
||||||
true /* has_more */, &line_data);
|
print_max(PAGER_SPACER_STRING, bg, comp_remaining, true /* has_more */, &line_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
comp_remaining -=
|
comp_remaining -= print_max(prefix, prefix_col, comp_remaining, !comp.empty(), &line_data);
|
||||||
print_max(prefix, prefix_col, comp_remaining, !comp.empty(), &line_data);
|
|
||||||
comp_remaining -=
|
comp_remaining -=
|
||||||
print_max(comp, comp_col, comp_remaining, i + 1 < c->comp.size(), &line_data);
|
print_max(comp, comp_col, comp_remaining, i + 1 < c->comp.size(), &line_data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -1314,7 +1314,7 @@ parse_execution_result_t parse_execution_context_t::run_job_conjunction(
|
||||||
assert((conj == parse_bool_and || conj == parse_bool_or) && "Unexpected conjunction");
|
assert((conj == parse_bool_and || conj == parse_bool_or) && "Unexpected conjunction");
|
||||||
skip = should_skip(conj);
|
skip = should_skip(conj);
|
||||||
}
|
}
|
||||||
if (! skip) {
|
if (!skip) {
|
||||||
result = run_1_job(cursor.child<0>(), associated_block);
|
result = run_1_job(cursor.child<0>(), associated_block);
|
||||||
}
|
}
|
||||||
continuation = cursor.child<1>();
|
continuation = cursor.child<1>();
|
||||||
|
|
|
@ -127,7 +127,8 @@ class parse_execution_context_t {
|
||||||
io_chain_t *out_chain);
|
io_chain_t *out_chain);
|
||||||
|
|
||||||
parse_execution_result_t run_1_job(tnode_t<grammar::job> job, const block_t *associated_block);
|
parse_execution_result_t run_1_job(tnode_t<grammar::job> job, const block_t *associated_block);
|
||||||
parse_execution_result_t run_job_conjunction(tnode_t<grammar::job_conjunction> job_conj, const block_t *associated_block);
|
parse_execution_result_t run_job_conjunction(tnode_t<grammar::job_conjunction> job_conj,
|
||||||
|
const block_t *associated_block);
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
parse_execution_result_t run_job_list(tnode_t<Type> job_list_node,
|
parse_execution_result_t run_job_list(tnode_t<Type> job_list_node,
|
||||||
const block_t *associated_block);
|
const block_t *associated_block);
|
||||||
|
|
|
@ -214,9 +214,7 @@ DEF_ALT(job_decorator) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// A job_conjunction is a job followed by a continuation.
|
// A job_conjunction is a job followed by a continuation.
|
||||||
DEF(job_conjunction) produces_sequence<job, job_conjunction_continuation> {
|
DEF(job_conjunction) produces_sequence<job, job_conjunction_continuation>{BODY(job_conjunction)};
|
||||||
BODY(job_conjunction)
|
|
||||||
};
|
|
||||||
|
|
||||||
DEF_ALT(job_conjunction_continuation) {
|
DEF_ALT(job_conjunction_continuation) {
|
||||||
using andands = seq<tok_andand, optional_newlines, job_conjunction>;
|
using andands = seq<tok_andand, optional_newlines, job_conjunction>;
|
||||||
|
@ -279,9 +277,8 @@ DEF_ALT(case_item_list) {
|
||||||
ALT_BODY(case_item_list, empty, case_items, blank_line);
|
ALT_BODY(case_item_list, empty, case_items, blank_line);
|
||||||
};
|
};
|
||||||
|
|
||||||
DEF(case_item) produces_sequence<keyword<parse_keyword_case>, argument_list, tok_end, job_list> {
|
DEF(case_item)
|
||||||
BODY(case_item)
|
produces_sequence<keyword<parse_keyword_case>, argument_list, tok_end, job_list>{BODY(case_item)};
|
||||||
};
|
|
||||||
|
|
||||||
DEF(block_statement)
|
DEF(block_statement)
|
||||||
produces_sequence<block_header, job_list, end_command, arguments_or_redirections_list>{
|
produces_sequence<block_header, job_list, end_command, arguments_or_redirections_list>{
|
||||||
|
@ -297,9 +294,7 @@ DEF_ALT(block_header) {
|
||||||
|
|
||||||
DEF(for_header)
|
DEF(for_header)
|
||||||
produces_sequence<keyword<parse_keyword_for>, tok_string, keyword<parse_keyword_in>, argument_list,
|
produces_sequence<keyword<parse_keyword_for>, tok_string, keyword<parse_keyword_in>, argument_list,
|
||||||
tok_end> {
|
tok_end>{BODY(for_header)};
|
||||||
BODY(for_header)
|
|
||||||
};
|
|
||||||
|
|
||||||
DEF(while_header)
|
DEF(while_header)
|
||||||
produces_sequence<keyword<parse_keyword_while>, job_conjunction, tok_end, andor_job_list>{
|
produces_sequence<keyword<parse_keyword_while>, job_conjunction, tok_end, andor_job_list>{
|
||||||
|
|
|
@ -57,7 +57,9 @@ RESOLVE(job_list) {
|
||||||
case parse_token_type_terminate: {
|
case parse_token_type_terminate: {
|
||||||
return production_for<empty>(); // no more commands, just transition to empty
|
return production_for<empty>(); // no more commands, just transition to empty
|
||||||
}
|
}
|
||||||
default: { return NO_PRODUCTION; }
|
default: {
|
||||||
|
return NO_PRODUCTION;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +168,9 @@ RESOLVE(statement) {
|
||||||
return NO_PRODUCTION;
|
return NO_PRODUCTION;
|
||||||
}
|
}
|
||||||
// All other keywords fall through to decorated statement.
|
// All other keywords fall through to decorated statement.
|
||||||
default: { return production_for<decorated>(); }
|
default: {
|
||||||
|
return production_for<decorated>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -176,7 +180,9 @@ RESOLVE(statement) {
|
||||||
case parse_token_type_terminate: {
|
case parse_token_type_terminate: {
|
||||||
return NO_PRODUCTION;
|
return NO_PRODUCTION;
|
||||||
}
|
}
|
||||||
default: { return NO_PRODUCTION; }
|
default: {
|
||||||
|
return NO_PRODUCTION;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +194,9 @@ RESOLVE(else_clause) {
|
||||||
case parse_keyword_else: {
|
case parse_keyword_else: {
|
||||||
return production_for<else_cont>();
|
return production_for<else_cont>();
|
||||||
}
|
}
|
||||||
default: { return production_for<empty>(); }
|
default: {
|
||||||
|
return production_for<empty>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +208,9 @@ RESOLVE(else_continuation) {
|
||||||
case parse_keyword_if: {
|
case parse_keyword_if: {
|
||||||
return production_for<else_if>();
|
return production_for<else_if>();
|
||||||
}
|
}
|
||||||
default: { return production_for<else_only>(); }
|
default: {
|
||||||
|
return production_for<else_only>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +262,9 @@ RESOLVE(argument_list) {
|
||||||
case parse_token_type_string: {
|
case parse_token_type_string: {
|
||||||
return production_for<arg>();
|
return production_for<arg>();
|
||||||
}
|
}
|
||||||
default: { return production_for<empty>(); }
|
default: {
|
||||||
|
return production_for<empty>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +279,9 @@ RESOLVE(freestanding_argument_list) {
|
||||||
case parse_token_type_end: {
|
case parse_token_type_end: {
|
||||||
return production_for<semicolon>();
|
return production_for<semicolon>();
|
||||||
}
|
}
|
||||||
default: { return production_for<empty>(); }
|
default: {
|
||||||
|
return production_for<empty>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,12 +302,13 @@ RESOLVE(block_header) {
|
||||||
case parse_keyword_begin: {
|
case parse_keyword_begin: {
|
||||||
return production_for<beginh>();
|
return production_for<beginh>();
|
||||||
}
|
}
|
||||||
default: { return NO_PRODUCTION; }
|
default: {
|
||||||
|
return NO_PRODUCTION;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RESOLVE(decorated_statement) {
|
RESOLVE(decorated_statement) {
|
||||||
|
|
||||||
// If this is e.g. 'command --help' then the command is 'command' and not a decoration. If the
|
// If this is e.g. 'command --help' then the command is 'command' and not a decoration. If the
|
||||||
// second token is not a string, then this is a naked 'command' and we should execute it as
|
// second token is not a string, then this is a naked 'command' and we should execute it as
|
||||||
// undecorated.
|
// undecorated.
|
||||||
|
@ -357,7 +372,6 @@ RESOLVE(optional_background) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const production_element_t *parse_productions::production_for_token(parse_token_type_t node_type,
|
const production_element_t *parse_productions::production_for_token(parse_token_type_t node_type,
|
||||||
const parse_token_t &input1,
|
const parse_token_t &input1,
|
||||||
const parse_token_t &input2,
|
const parse_token_t &input2,
|
||||||
|
|
|
@ -178,7 +178,9 @@ static wcstring token_type_user_presentable_description(
|
||||||
return L"end of the statement";
|
return L"end of the statement";
|
||||||
case parse_token_type_terminate:
|
case parse_token_type_terminate:
|
||||||
return L"end of the input";
|
return L"end of the input";
|
||||||
default: { return format_string(L"a %ls", token_type_description(type)); }
|
default: {
|
||||||
|
return format_string(L"a %ls", token_type_description(type));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +204,9 @@ static wcstring block_type_user_presentable_description(parse_token_type_t type)
|
||||||
case symbol_switch_statement: {
|
case symbol_switch_statement: {
|
||||||
return L"switch statement";
|
return L"switch statement";
|
||||||
}
|
}
|
||||||
default: { return token_type_description(type); }
|
default: {
|
||||||
|
return token_type_description(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,8 +694,7 @@ void parse_ll_t::parse_error_failed_production(struct parse_stack_element_t &sta
|
||||||
void parse_ll_t::report_tokenizer_error(const tok_t &tok) {
|
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);
|
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,
|
this->parse_error_at_location(tok.offset, tok.length, tok.offset + tok.error_offset,
|
||||||
parse_error_code, L"%ls",
|
parse_error_code, L"%ls", tokenizer_get_error_message(tok.error));
|
||||||
tokenizer_get_error_message(tok.error));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_ll_t::parse_error_unexpected_token(const wchar_t *expected, parse_token_t token) {
|
void parse_ll_t::parse_error_unexpected_token(const wchar_t *expected, parse_token_t token) {
|
||||||
|
@ -730,7 +733,9 @@ static bool type_is_terminal_type(parse_token_type_t type) {
|
||||||
case parse_token_type_terminate: {
|
case parse_token_type_terminate: {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
default: { return false; }
|
default: {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ constexpr source_offset_t SOURCE_OFFSET_INVALID = static_cast<source_offset_t>(-
|
||||||
/// A struct representing the token type that we use internally.
|
/// A struct representing the token type that we use internally.
|
||||||
struct parse_token_t {
|
struct parse_token_t {
|
||||||
enum parse_token_type_t type; // The type of the token as represented by the parser
|
enum parse_token_type_t type; // The type of the token as represented by the parser
|
||||||
enum parse_keyword_t keyword{parse_keyword_none}; // Any keyword represented by this token
|
enum parse_keyword_t keyword { parse_keyword_none }; // Any keyword represented by this token
|
||||||
bool has_dash_prefix{false}; // Hackish: whether the source contains a dash prefix
|
bool has_dash_prefix{false}; // Hackish: whether the source contains a dash prefix
|
||||||
bool is_help_argument{false}; // Hackish: whether the source looks like '-h' or '--help'
|
bool is_help_argument{false}; // Hackish: whether the source looks like '-h' or '--help'
|
||||||
bool is_newline{false}; // Hackish: if TOK_END, whether the source is a newline.
|
bool is_newline{false}; // Hackish: if TOK_END, whether the source is a newline.
|
||||||
|
@ -130,9 +130,7 @@ class parse_node_t {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicate if the node has comment nodes.
|
/// Indicate if the node has comment nodes.
|
||||||
bool has_comments() const {
|
bool has_comments() const { return this->flags & parse_node_flag_has_comments; }
|
||||||
return this->flags & parse_node_flag_has_comments;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicates if we have a preceding escaped newline.
|
/// Indicates if we have a preceding escaped newline.
|
||||||
bool has_preceding_escaped_newline() const {
|
bool has_preceding_escaped_newline() const {
|
||||||
|
|
|
@ -328,7 +328,9 @@ static void job_or_process_extent(const wchar_t *buff, size_t cursor_pos, const
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: { break; }
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,7 +512,8 @@ void parse_util_get_parameter_info(const wcstring &cmd, const size_t pos, wchar_
|
||||||
|
|
||||||
if (offset != 0) {
|
if (offset != 0) {
|
||||||
if (finished) {
|
if (finished) {
|
||||||
while ((cmd_tmp[prev_pos] != 0) && (std::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;
|
*offset = prev_pos;
|
||||||
} else {
|
} else {
|
||||||
*offset = pos;
|
*offset = pos;
|
||||||
|
@ -674,7 +677,8 @@ std::vector<int> parse_util_compute_indents(const wcstring &src) {
|
||||||
// foo ; cas', we get an invalid parse tree (since 'cas' is not valid) but we indent it as if it
|
// foo ; cas', we get an invalid parse tree (since 'cas' is not valid) but we indent it as if it
|
||||||
// were a case item list.
|
// were a case item list.
|
||||||
parse_node_tree_t tree;
|
parse_node_tree_t tree;
|
||||||
parse_tree_from_string(src, parse_flag_continue_after_error | parse_flag_include_comments |
|
parse_tree_from_string(src,
|
||||||
|
parse_flag_continue_after_error | parse_flag_include_comments |
|
||||||
parse_flag_accept_incomplete_tokens,
|
parse_flag_accept_incomplete_tokens,
|
||||||
&tree, NULL /* errors */);
|
&tree, NULL /* errors */);
|
||||||
|
|
||||||
|
@ -826,7 +830,9 @@ static const wchar_t *error_format_for_character(wchar_t wc) {
|
||||||
case VARIABLE_EXPAND_EMPTY: {
|
case VARIABLE_EXPAND_EMPTY: {
|
||||||
return ERROR_NOT_PID;
|
return ERROR_NOT_PID;
|
||||||
}
|
}
|
||||||
default: { return ERROR_BAD_VAR_CHAR1; }
|
default: {
|
||||||
|
return ERROR_BAD_VAR_CHAR1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -393,7 +393,8 @@ void parser_t::stack_trace_internal(size_t block_idx, wcstring *buff) const {
|
||||||
// We can't quote the arguments because we print this in quotes.
|
// We can't quote the arguments because we print this in quotes.
|
||||||
// As a special-case, add the empty argument as "".
|
// As a special-case, add the empty argument as "".
|
||||||
if (process->argv(i)[0]) {
|
if (process->argv(i)[0]) {
|
||||||
tmp.append(escape_string(process->argv(i), ESCAPE_ALL | ESCAPE_NO_QUOTED));
|
tmp.append(
|
||||||
|
escape_string(process->argv(i), ESCAPE_ALL | ESCAPE_NO_QUOTED));
|
||||||
} else {
|
} else {
|
||||||
tmp.append(L"\"\"");
|
tmp.append(L"\"\"");
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,7 @@
|
||||||
class io_chain_t;
|
class io_chain_t;
|
||||||
|
|
||||||
/// event_blockage_t represents a block on events.
|
/// event_blockage_t represents a block on events.
|
||||||
struct event_blockage_t {
|
struct event_blockage_t {};
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::list<event_blockage_t> event_blockage_list_t;
|
typedef std::list<event_blockage_t> event_blockage_list_t;
|
||||||
|
|
||||||
|
|
|
@ -10,26 +10,20 @@
|
||||||
|
|
||||||
typedef std::unordered_set<wcstring> string_set_t;
|
typedef std::unordered_set<wcstring> string_set_t;
|
||||||
|
|
||||||
static const wcstring skip_keywords[] {
|
static const wcstring skip_keywords[]{
|
||||||
L"else",
|
L"else",
|
||||||
L"begin",
|
L"begin",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const wcstring subcommand_keywords[] {
|
static const wcstring subcommand_keywords[]{L"command", L"builtin", L"while", L"exec",
|
||||||
L"command", L"builtin", L"while", L"exec",
|
L"if", L"and", L"or", L"not"};
|
||||||
L"if", L"and", L"or", L"not"
|
|
||||||
};
|
|
||||||
|
|
||||||
static const string_set_t block_keywords = {
|
static const string_set_t block_keywords = {L"for", L"while", L"if",
|
||||||
L"for", L"while", L"if",
|
L"function", L"switch", L"begin"};
|
||||||
L"function", L"switch", L"begin"
|
|
||||||
};
|
|
||||||
|
|
||||||
static const wcstring reserved_keywords[] = {
|
static const wcstring reserved_keywords[] = {L"end", L"case", L"else", L"return",
|
||||||
L"end", L"case", L"else", L"return",
|
|
||||||
L"continue", L"break", L"argparse", L"read",
|
L"continue", L"break", L"argparse", L"read",
|
||||||
L"set", L"status", L"test", L"["
|
L"set", L"status", L"test", L"["};
|
||||||
};
|
|
||||||
|
|
||||||
// The lists above are purposely implemented separately from the logic below, so that future
|
// 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
|
// maintainers may assume the contents of the list based off their names, and not off what the
|
||||||
|
@ -37,7 +31,7 @@ static const wcstring reserved_keywords[] = {
|
||||||
|
|
||||||
static size_t list_max_length(const string_set_t &list) {
|
static size_t list_max_length(const string_set_t &list) {
|
||||||
size_t result = 0;
|
size_t result = 0;
|
||||||
for (const auto &w: list) {
|
for (const auto &w : list) {
|
||||||
if (w.length() > result) {
|
if (w.length() > result) {
|
||||||
result = w.length();
|
result = w.length();
|
||||||
}
|
}
|
||||||
|
@ -50,7 +44,7 @@ bool parser_keywords_skip_arguments(const wcstring &cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parser_keywords_is_subcommand(const wcstring &cmd) {
|
bool parser_keywords_is_subcommand(const wcstring &cmd) {
|
||||||
const static string_set_t search_list = ([](){
|
const static string_set_t search_list = ([]() {
|
||||||
string_set_t results;
|
string_set_t results;
|
||||||
results.insert(std::begin(subcommand_keywords), std::end(subcommand_keywords));
|
results.insert(std::begin(subcommand_keywords), std::end(subcommand_keywords));
|
||||||
results.insert(std::begin(skip_keywords), std::end(skip_keywords));
|
results.insert(std::begin(skip_keywords), std::end(skip_keywords));
|
||||||
|
@ -73,7 +67,7 @@ bool parser_keywords_is_block(const wcstring &word) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parser_keywords_is_reserved(const wcstring &word) {
|
bool parser_keywords_is_reserved(const wcstring &word) {
|
||||||
const static string_set_t search_list = ([](){
|
const static string_set_t search_list = ([]() {
|
||||||
string_set_t results;
|
string_set_t results;
|
||||||
results.insert(std::begin(subcommand_keywords), std::end(subcommand_keywords));
|
results.insert(std::begin(subcommand_keywords), std::end(subcommand_keywords));
|
||||||
results.insert(std::begin(skip_keywords), std::end(skip_keywords));
|
results.insert(std::begin(skip_keywords), std::end(skip_keywords));
|
||||||
|
|
14
src/path.cpp
14
src/path.cpp
|
@ -4,9 +4,9 @@
|
||||||
#include "config.h" // IWYU pragma: keep
|
#include "config.h" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <cstring>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -87,18 +87,18 @@ static bool path_get_path_core(const wcstring &cmd, wcstring *out_path,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifdef __sun
|
#ifdef __sun
|
||||||
//Solaris 5.11 can return any of the following three if the path
|
// Solaris 5.11 can return any of the following three if the path
|
||||||
//does not exist. Yes, even 0. No, none of this is documented.
|
// does not exist. Yes, even 0. No, none of this is documented.
|
||||||
case 0:
|
case 0:
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
case EEXIST: {
|
case EEXIST: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//WSL has a bug where access(2) can return EINVAL
|
// WSL has a bug where access(2) can return EINVAL
|
||||||
//See https://github.com/Microsoft/BashOnWindows/issues/2522
|
// See https://github.com/Microsoft/BashOnWindows/issues/2522
|
||||||
//The only other way EINVAL can happen is if the wrong
|
// The only other way EINVAL can happen is if the wrong
|
||||||
//mode was specified, but we have X_OK hard-coded above.
|
// mode was specified, but we have X_OK hard-coded above.
|
||||||
case EINVAL: {
|
case EINVAL: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <cstring>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#if FISH_USE_POSIX_SPAWN
|
#if FISH_USE_POSIX_SPAWN
|
||||||
#include <spawn.h>
|
#include <spawn.h>
|
||||||
|
@ -49,18 +49,18 @@ bool child_set_group(job_t *j, process_t *p) {
|
||||||
// Put a cap on how many times we retry so we are never stuck here
|
// Put a cap on how many times we retry so we are never stuck here
|
||||||
if (i < 100) {
|
if (i < 100) {
|
||||||
if (errno == EPERM) {
|
if (errno == EPERM) {
|
||||||
// The setpgid(2) man page says that EPERM is returned only if attempts are made to
|
// The setpgid(2) man page says that EPERM is returned only if attempts are made
|
||||||
// move processes into groups across session boundaries (which can never be the case
|
// to move processes into groups across session boundaries (which can never be
|
||||||
// in fish, anywhere) or to change the process group ID of a session leader (again,
|
// the case in fish, anywhere) or to change the process group ID of a session
|
||||||
// can never be the case). I'm pretty sure this is a WSL bug, as we see the same
|
// leader (again, can never be the case). I'm pretty sure this is a WSL bug, as
|
||||||
// with tcsetpgrp(2) in other places and it disappears on retry.
|
// we see the same with tcsetpgrp(2) in other places and it disappears on retry.
|
||||||
debug_safe(2, "setpgid(2) returned EPERM. Retrying");
|
debug_safe(2, "setpgid(2) returned EPERM. Retrying");
|
||||||
continue;
|
continue;
|
||||||
} else if (errno == EINTR) {
|
} else if (errno == EINTR) {
|
||||||
// I don't think signals are blocked here. The parent (fish) redirected the signal
|
// I don't think signals are blocked here. The parent (fish) redirected the
|
||||||
// handlers and `setup_child_process()` calls `signal_reset_handlers()` after we're
|
// signal handlers and `setup_child_process()` calls `signal_reset_handlers()`
|
||||||
// done here (and not `signal_unblock()`). We're already in a loop, so let's just
|
// after we're done here (and not `signal_unblock()`). We're already in a loop,
|
||||||
// handle EINTR just in case.
|
// so let's just handle EINTR just in case.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,9 @@ bool child_set_group(job_t *j, process_t *p) {
|
||||||
pid_buff, argv0, job_id_buff, command, getpgid_buff, job_pgid_buff);
|
pid_buff, argv0, job_id_buff, command, getpgid_buff, job_pgid_buff);
|
||||||
|
|
||||||
if (is_windows_subsystem_for_linux() && errno == EPERM) {
|
if (is_windows_subsystem_for_linux() && errno == EPERM) {
|
||||||
debug_safe(1, "Please update to Windows 10 1809/17763 or higher to address known issues "
|
debug_safe(
|
||||||
|
1,
|
||||||
|
"Please update to Windows 10 1809/17763 or higher to address known issues "
|
||||||
"with process groups and zombie processes.");
|
"with process groups and zombie processes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,8 +109,8 @@ bool child_set_group(job_t *j, process_t *p) {
|
||||||
/// if it's to run in the foreground.
|
/// if it's to run in the foreground.
|
||||||
bool set_child_group(job_t *j, pid_t child_pid) {
|
bool set_child_group(job_t *j, pid_t child_pid) {
|
||||||
if (j->get_flag(job_flag_t::JOB_CONTROL)) {
|
if (j->get_flag(job_flag_t::JOB_CONTROL)) {
|
||||||
assert (j->pgid != INVALID_PID
|
assert(j->pgid != INVALID_PID &&
|
||||||
&& "set_child_group called with JOB_CONTROL before job pgid determined!");
|
"set_child_group called with JOB_CONTROL before job pgid determined!");
|
||||||
|
|
||||||
// The parent sets the child's group. This incurs the well-known unavoidable race with the
|
// The parent sets the child's group. This incurs the well-known unavoidable race with the
|
||||||
// child exiting, so ignore ESRCH and EPERM (in case the pid was recycled).
|
// child exiting, so ignore ESRCH and EPERM (in case the pid was recycled).
|
||||||
|
@ -117,14 +119,13 @@ bool set_child_group(job_t *j, pid_t child_pid) {
|
||||||
if (errno != ESRCH && errno != EPERM && errno != EACCES) {
|
if (errno != ESRCH && errno != EPERM && errno != EACCES) {
|
||||||
safe_perror("setpgid");
|
safe_perror("setpgid");
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Just in case it's ever not right to ignore the setpgid call, (i.e. if this
|
// Just in case it's ever not right to ignore the setpgid call, (i.e. if this
|
||||||
// ever leads to a terminal hang due if both this setpgid call AND posix_spawn's
|
// ever leads to a terminal hang due if both this setpgid call AND posix_spawn's
|
||||||
// internal setpgid calls failed), write to the debug log so a future developer
|
// internal setpgid calls failed), write to the debug log so a future developer
|
||||||
// doesn't go crazy trying to track this down.
|
// doesn't go crazy trying to track this down.
|
||||||
debug(2, "Error %d while calling setpgid for child %d (probably harmless)",
|
debug(2, "Error %d while calling setpgid for child %d (probably harmless)", errno,
|
||||||
errno, child_pid);
|
child_pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -169,7 +170,6 @@ int setup_child_process(process_t *p, const dup2_list_t &dup2s) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int g_fork_count = 0;
|
int g_fork_count = 0;
|
||||||
|
|
||||||
/// This function is a wrapper around fork. If the fork calls fails with EAGAIN, it is retried
|
/// This function is a wrapper around fork. If the fork calls fails with EAGAIN, it is retried
|
||||||
|
|
17
src/proc.cpp
17
src/proc.cpp
|
@ -6,13 +6,13 @@
|
||||||
// IWYU pragma: no_include <__bit_reference>
|
// IWYU pragma: no_include <__bit_reference>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <atomic>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
#if HAVE_TERM_H
|
#if HAVE_TERM_H
|
||||||
#include <curses.h>
|
#include <curses.h>
|
||||||
|
@ -60,7 +60,7 @@ bool job_list_is_empty() {
|
||||||
return parser_t::principal_parser().job_list().empty();
|
return parser_t::principal_parser().job_list().empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
job_list_t& jobs() {
|
job_list_t &jobs() {
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
return parser_t::principal_parser().job_list();
|
return parser_t::principal_parser().job_list();
|
||||||
}
|
}
|
||||||
|
@ -342,7 +342,7 @@ static void process_mark_finished_children(bool block_ok) {
|
||||||
topic_set_t reaptopics{};
|
topic_set_t reaptopics{};
|
||||||
generation_list_t gens{};
|
generation_list_t gens{};
|
||||||
gens.fill(invalid_generation);
|
gens.fill(invalid_generation);
|
||||||
for (const auto j: jobs()) {
|
for (const auto j : jobs()) {
|
||||||
for (const auto &proc : j->processes) {
|
for (const auto &proc : j->processes) {
|
||||||
if (auto mtopic = j->reap_topic_for_process(proc.get())) {
|
if (auto mtopic = j->reap_topic_for_process(proc.get())) {
|
||||||
topic_t topic = *mtopic;
|
topic_t topic = *mtopic;
|
||||||
|
@ -402,7 +402,8 @@ static void process_mark_finished_children(bool block_ok) {
|
||||||
// Poll disowned processes/process groups, but do nothing with the result. Only used to avoid
|
// Poll disowned processes/process groups, but do nothing with the result. Only used to avoid
|
||||||
// zombie processes. Entries have already been converted to negative for process groups.
|
// zombie processes. Entries have already been converted to negative for process groups.
|
||||||
int status;
|
int status;
|
||||||
s_disowned_pids.erase(std::remove_if(s_disowned_pids.begin(), s_disowned_pids.end(),
|
s_disowned_pids.erase(
|
||||||
|
std::remove_if(s_disowned_pids.begin(), s_disowned_pids.end(),
|
||||||
[&status](pid_t pid) { return waitpid(pid, &status, WNOHANG) > 0; }),
|
[&status](pid_t pid) { return waitpid(pid, &status, WNOHANG) > 0; }),
|
||||||
s_disowned_pids.end());
|
s_disowned_pids.end());
|
||||||
}
|
}
|
||||||
|
@ -658,7 +659,7 @@ bool job_reap(parser_t &parser, bool allow_interactive) {
|
||||||
|
|
||||||
/// Get the CPU time for the specified process.
|
/// Get the CPU time for the specified process.
|
||||||
unsigned long proc_get_jiffies(process_t *p) {
|
unsigned long proc_get_jiffies(process_t *p) {
|
||||||
if (! have_proc_stat) return 0;
|
if (!have_proc_stat) return 0;
|
||||||
if (p->pid <= 0) return 0;
|
if (p->pid <= 0) return 0;
|
||||||
|
|
||||||
wchar_t fn[FN_SIZE];
|
wchar_t fn[FN_SIZE];
|
||||||
|
@ -701,8 +702,8 @@ void proc_update_jiffies() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return control of the terminal to a job's process group. restore_attrs is true if we are restoring
|
// Return control of the terminal to a job's process group. restore_attrs is true if we are
|
||||||
// a previously-stopped job, in which case we need to restore terminal attributes.
|
// restoring a previously-stopped job, in which case we need to restore terminal attributes.
|
||||||
bool terminal_give_to_job(const job_t *j, bool restore_attrs) {
|
bool terminal_give_to_job(const job_t *j, bool restore_attrs) {
|
||||||
if (j->pgid == 0) {
|
if (j->pgid == 0) {
|
||||||
debug(2, "terminal_give_to_job() returning early due to no process group");
|
debug(2, "terminal_give_to_job() returning early due to no process group");
|
||||||
|
|
|
@ -352,8 +352,7 @@ class job_t {
|
||||||
/// untruncated job string when we don't care what the job is, only which of the currently
|
/// untruncated job string when we don't care what the job is, only which of the currently
|
||||||
/// running jobs it is.
|
/// running jobs it is.
|
||||||
wcstring preview() const {
|
wcstring preview() const {
|
||||||
if (processes.empty())
|
if (processes.empty()) return L"";
|
||||||
return L"";
|
|
||||||
// Note argv0 may be empty in e.g. a block process.
|
// Note argv0 may be empty in e.g. a block process.
|
||||||
const wchar_t *argv0 = processes.front()->argv0();
|
const wchar_t *argv0 = processes.front()->argv0();
|
||||||
wcstring result = argv0 ? argv0 : L"null";
|
wcstring result = argv0 ? argv0 : L"null";
|
||||||
|
@ -534,8 +533,9 @@ void hup_background_jobs();
|
||||||
/// Give ownership of the terminal to the specified job.
|
/// Give ownership of the terminal to the specified job.
|
||||||
///
|
///
|
||||||
/// \param j The job to give the terminal to.
|
/// \param j The job to give the terminal to.
|
||||||
/// \param restore_attrs If this variable is set, we are giving back control to a job that was previously
|
/// \param restore_attrs If this variable is set, we are giving back control to a job that was
|
||||||
/// stopped. In that case, we need to set the terminal attributes to those saved in the job.
|
/// previously stopped. In that case, we need to set the terminal attributes to those saved in the
|
||||||
|
/// job.
|
||||||
bool terminal_give_to_job(const job_t *j, bool restore_attrs);
|
bool terminal_give_to_job(const job_t *j, bool restore_attrs);
|
||||||
|
|
||||||
/// Given that we are about to run a builtin, acquire the terminal if it is owned by the given job.
|
/// Given that we are about to run a builtin, acquire the terminal if it is owned by the given job.
|
||||||
|
|
|
@ -32,8 +32,8 @@
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
@ -436,9 +436,7 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
||||||
|
|
||||||
/// Insert the character into the command line buffer and print it to the screen using syntax
|
/// Insert the character into the command line buffer and print it to the screen using syntax
|
||||||
/// highlighting, etc.
|
/// highlighting, etc.
|
||||||
bool insert_char(editable_line_t *el, wchar_t c) {
|
bool insert_char(editable_line_t *el, wchar_t c) { return insert_string(el, wcstring{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,
|
void move_word(editable_line_t *el, bool move_right, bool erase, enum move_word_style_t style,
|
||||||
bool newv);
|
bool newv);
|
||||||
|
@ -643,8 +641,9 @@ void reader_data_t::repaint() {
|
||||||
size_t cursor_position = focused_on_pager ? pager.cursor_position() : cmd_line->position;
|
size_t cursor_position = focused_on_pager ? pager.cursor_position() : cmd_line->position;
|
||||||
|
|
||||||
// Prepend the mode prompt to the left prompt.
|
// 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,
|
s_write(&screen, mode_prompt_buff + left_prompt_buff, right_prompt_buff, full_line,
|
||||||
indents, cursor_position, current_page_rendering, focused_on_pager);
|
cmd_line->size(), colors, indents, cursor_position, current_page_rendering,
|
||||||
|
focused_on_pager);
|
||||||
|
|
||||||
repaint_needed = false;
|
repaint_needed = false;
|
||||||
}
|
}
|
||||||
|
@ -909,8 +908,7 @@ void reader_data_t::exec_mode_prompt() {
|
||||||
mode_prompt_buff.clear();
|
mode_prompt_buff.clear();
|
||||||
if (function_exists(MODE_PROMPT_FUNCTION_NAME, parser())) {
|
if (function_exists(MODE_PROMPT_FUNCTION_NAME, parser())) {
|
||||||
wcstring_list_t mode_indicator_list;
|
wcstring_list_t mode_indicator_list;
|
||||||
exec_subshell(MODE_PROMPT_FUNCTION_NAME, parser(), mode_indicator_list,
|
exec_subshell(MODE_PROMPT_FUNCTION_NAME, parser(), mode_indicator_list, false);
|
||||||
false);
|
|
||||||
// We do not support multiple lines in the mode indicator, so just concatenate all of
|
// We do not support multiple lines in the mode indicator, so just concatenate all of
|
||||||
// them.
|
// them.
|
||||||
for (size_t i = 0; i < mode_indicator_list.size(); i++) {
|
for (size_t i = 0; i < mode_indicator_list.size(); i++) {
|
||||||
|
@ -1776,7 +1774,6 @@ static void reader_interactive_init() {
|
||||||
signal_set_handlers();
|
signal_set_handlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// It shouldn't be necessary to place fish in its own process group and force control
|
// It shouldn't be necessary to place fish in its own process group and force control
|
||||||
// of the terminal, but that works around fish being started with an invalid pgroup,
|
// of the terminal, but that works around fish being started with an invalid pgroup,
|
||||||
// such as when launched via firejail (#5295)
|
// such as when launched via firejail (#5295)
|
||||||
|
@ -2497,7 +2494,8 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
||||||
case rl::repaint_mode: {
|
case rl::repaint_mode: {
|
||||||
// Repaint the mode-prompt only if it exists.
|
// Repaint the mode-prompt only if it exists.
|
||||||
// This is an optimization basically exclusively for vi-mode, since the prompt
|
// 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.
|
// may sometimes take a while but when switching the mode all we care about is the
|
||||||
|
// mode-prompt.
|
||||||
if (function_exists(MODE_PROMPT_FUNCTION_NAME, parser())) {
|
if (function_exists(MODE_PROMPT_FUNCTION_NAME, parser())) {
|
||||||
exec_mode_prompt();
|
exec_mode_prompt();
|
||||||
s_reset(&screen, screen_reset_current_line_and_prompt);
|
s_reset(&screen, screen_reset_current_line_and_prompt);
|
||||||
|
@ -2893,16 +2891,16 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
||||||
}
|
}
|
||||||
case rl::backward_word:
|
case rl::backward_word:
|
||||||
case rl::backward_bigword: {
|
case rl::backward_bigword: {
|
||||||
auto move_style = (c == rl::backward_word) ? move_word_style_punctuation
|
auto move_style =
|
||||||
: move_word_style_whitespace;
|
(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,
|
move_word(active_edit_line(), MOVE_DIR_LEFT, false /* do not erase */, move_style,
|
||||||
false);
|
false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case rl::forward_word:
|
case rl::forward_word:
|
||||||
case rl::forward_bigword: {
|
case rl::forward_bigword: {
|
||||||
auto move_style = (c == rl::forward_word) ? move_word_style_punctuation
|
auto move_style =
|
||||||
: move_word_style_whitespace;
|
(c == rl::forward_word) ? move_word_style_punctuation : move_word_style_whitespace;
|
||||||
editable_line_t *el = active_edit_line();
|
editable_line_t *el = active_edit_line();
|
||||||
if (el->position < el->size()) {
|
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);
|
||||||
|
|
|
@ -62,8 +62,8 @@ class dup2_list_t {
|
||||||
static maybe_t<dup2_list_t> resolve_chain(const io_chain_t &);
|
static maybe_t<dup2_list_t> resolve_chain(const io_chain_t &);
|
||||||
|
|
||||||
/// \return the fd ultimately dup'd to a target fd, or -1 if the target is closed.
|
/// \return the fd ultimately dup'd to a target fd, or -1 if the target is closed.
|
||||||
/// For example, if target fd is 1, and we have a dup2 chain 5->3 and 3->1, then we will return 5.
|
/// For example, if target fd is 1, and we have a dup2 chain 5->3 and 3->1, then we will
|
||||||
/// If the target is not referenced in the chain, returns target.
|
/// return 5. If the target is not referenced in the chain, returns target.
|
||||||
int fd_for_target_fd(int target) const;
|
int fd_for_target_fd(int target) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
|
|
||||||
#if HAVE_CURSES_H
|
#if HAVE_CURSES_H
|
||||||
|
@ -105,7 +105,8 @@ static bool is_screen_name_escape_seq(const wchar_t *code, size_t *resulting_len
|
||||||
// Consider just <esc>k to be the code.
|
// Consider just <esc>k to be the code.
|
||||||
*resulting_length = 2;
|
*resulting_length = 2;
|
||||||
} else {
|
} else {
|
||||||
const wchar_t *escape_sequence_end = screen_name_end + std::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;
|
*resulting_length = escape_sequence_end - code;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -191,7 +192,10 @@ static bool is_color_escape_seq(const wchar_t *code, size_t *resulting_length) {
|
||||||
// Detect these terminfo color escapes with parameter value up to max_colors, all of which
|
// Detect these terminfo color escapes with parameter value up to max_colors, all of which
|
||||||
// don't move the cursor.
|
// don't move the cursor.
|
||||||
const char *const esc[] = {
|
const char *const esc[] = {
|
||||||
set_a_foreground, set_a_background, set_foreground, set_background,
|
set_a_foreground,
|
||||||
|
set_a_background,
|
||||||
|
set_foreground,
|
||||||
|
set_background,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (size_t p = 0; p < sizeof esc / sizeof *esc; p++) {
|
for (size_t p = 0; p < sizeof esc / sizeof *esc; p++) {
|
||||||
|
@ -218,8 +222,7 @@ static bool is_visual_escape_seq(const wchar_t *code, size_t *resulting_length)
|
||||||
enter_standout_mode, exit_standout_mode, enter_blink_mode, enter_protected_mode,
|
enter_standout_mode, exit_standout_mode, enter_blink_mode, enter_protected_mode,
|
||||||
enter_italics_mode, exit_italics_mode, enter_reverse_mode, enter_shadow_mode,
|
enter_italics_mode, exit_italics_mode, enter_reverse_mode, enter_shadow_mode,
|
||||||
exit_shadow_mode, enter_standout_mode, exit_standout_mode, enter_secure_mode,
|
exit_shadow_mode, enter_standout_mode, exit_standout_mode, enter_secure_mode,
|
||||||
enter_dim_mode, enter_blink_mode, enter_alt_charset_mode, exit_alt_charset_mode
|
enter_dim_mode, enter_blink_mode, enter_alt_charset_mode, exit_alt_charset_mode};
|
||||||
};
|
|
||||||
|
|
||||||
for (size_t p = 0; p < sizeof esc2 / sizeof *esc2; p++) {
|
for (size_t p = 0; p < sizeof esc2 / sizeof *esc2; p++) {
|
||||||
if (!esc2[p]) continue;
|
if (!esc2[p]) continue;
|
||||||
|
@ -237,8 +240,8 @@ static bool is_visual_escape_seq(const wchar_t *code, size_t *resulting_length)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of characters in the escape code starting at 'code'. We only handle sequences
|
/// Returns the number of characters in the escape code starting at 'code'. We only handle sequences
|
||||||
/// that begin with \x1B. If it doesn't we return zero. We also return zero if we don't recognize the
|
/// that begin with \x1B. If it doesn't we return zero. We also return zero if we don't recognize
|
||||||
/// escape sequence based on querying terminfo and other heuristics.
|
/// the escape sequence based on querying terminfo and other heuristics.
|
||||||
size_t escape_code_length(const wchar_t *code) {
|
size_t escape_code_length(const wchar_t *code) {
|
||||||
assert(code != NULL);
|
assert(code != NULL);
|
||||||
if (*code != L'\x1B') return 0;
|
if (*code != L'\x1B') return 0;
|
||||||
|
@ -495,8 +498,8 @@ 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
|
// 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).
|
// Note that this is required to avoid some visual glitches in iTerm (issue #1448).
|
||||||
bool use_multi =
|
bool use_multi = multi_str != NULL && multi_str[0] != '\0' &&
|
||||||
multi_str != NULL && multi_str[0] != '\0' && abs(x_steps) * std::strlen(str) > std::strlen(multi_str);
|
abs(x_steps) * std::strlen(str) > std::strlen(multi_str);
|
||||||
if (use_multi && cur_term) {
|
if (use_multi && cur_term) {
|
||||||
char *multi_param = tparm((char *)multi_str, abs(x_steps));
|
char *multi_param = tparm((char *)multi_str, abs(x_steps));
|
||||||
writembs(outp, multi_param);
|
writembs(outp, multi_param);
|
||||||
|
@ -1132,8 +1135,8 @@ void s_reset(screen_t *s, screen_reset_mode_t mode) {
|
||||||
abandon_line_string.append(get_omitted_newline_str());
|
abandon_line_string.append(get_omitted_newline_str());
|
||||||
|
|
||||||
if (cur_term && exit_attribute_mode) {
|
if (cur_term && exit_attribute_mode) {
|
||||||
abandon_line_string.append(
|
abandon_line_string.append(str2wcstring(
|
||||||
str2wcstring(tparm((char *)exit_attribute_mode))); // normal text ANSI escape sequence
|
tparm((char *)exit_attribute_mode))); // normal text ANSI escape sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
int newline_glitch_width = term_has_xn ? 0 : 1;
|
int newline_glitch_width = term_has_xn ? 0 : 1;
|
||||||
|
|
|
@ -416,4 +416,3 @@ void signal_unblock_all() {
|
||||||
sigemptyset(&iset);
|
sigemptyset(&iset);
|
||||||
sigprocmask(SIG_SETMASK, &iset, NULL);
|
sigprocmask(SIG_SETMASK, &iset, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
222
src/tinyexpr.cpp
222
src/tinyexpr.cpp
|
@ -24,26 +24,36 @@
|
||||||
|
|
||||||
// This version has been altered and ported to C++ for inclusion in fish.
|
// This version has been altered and ported to C++ for inclusion in fish.
|
||||||
#include "tinyexpr.h"
|
#include "tinyexpr.h"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <cstring>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
// TODO: It would be nice not to rely on a typedef for this, especially one that can only do functions with two args.
|
// TODO: It would be nice not to rely on a typedef for this, especially one that can only do
|
||||||
|
// functions with two args.
|
||||||
typedef double (*te_fun2)(double, double);
|
typedef double (*te_fun2)(double, double);
|
||||||
typedef double (*te_fun1)(double);
|
typedef double (*te_fun1)(double);
|
||||||
typedef double (*te_fun0)();
|
typedef double (*te_fun0)();
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TE_CONSTANT = 0,
|
TE_CONSTANT = 0,
|
||||||
TE_FUNCTION0, TE_FUNCTION1, TE_FUNCTION2, TE_FUNCTION3,
|
TE_FUNCTION0,
|
||||||
TOK_NULL, TOK_ERROR, TOK_END, TOK_SEP,
|
TE_FUNCTION1,
|
||||||
TOK_OPEN, TOK_CLOSE, TOK_NUMBER, TOK_INFIX
|
TE_FUNCTION2,
|
||||||
|
TE_FUNCTION3,
|
||||||
|
TOK_NULL,
|
||||||
|
TOK_ERROR,
|
||||||
|
TOK_END,
|
||||||
|
TOK_SEP,
|
||||||
|
TOK_OPEN,
|
||||||
|
TOK_CLOSE,
|
||||||
|
TOK_NUMBER,
|
||||||
|
TOK_INFIX
|
||||||
};
|
};
|
||||||
|
|
||||||
int get_arity(const int type) {
|
int get_arity(const int type) {
|
||||||
|
@ -55,7 +65,10 @@ int get_arity(const int type) {
|
||||||
|
|
||||||
typedef struct te_expr {
|
typedef struct te_expr {
|
||||||
int type;
|
int type;
|
||||||
union {double value; const void *function;};
|
union {
|
||||||
|
double value;
|
||||||
|
const void *function;
|
||||||
|
};
|
||||||
te_expr *parameters[];
|
te_expr *parameters[];
|
||||||
} te_expr;
|
} te_expr;
|
||||||
|
|
||||||
|
@ -67,7 +80,10 @@ typedef struct te_builtin {
|
||||||
} te_builtin;
|
} te_builtin;
|
||||||
|
|
||||||
typedef struct state {
|
typedef struct state {
|
||||||
union {double value; const void *function;};
|
union {
|
||||||
|
double value;
|
||||||
|
const void *function;
|
||||||
|
};
|
||||||
const char *start;
|
const char *start;
|
||||||
const char *next;
|
const char *next;
|
||||||
int type;
|
int type;
|
||||||
|
@ -86,11 +102,11 @@ double te_eval(const te_expr *n);
|
||||||
void te_free(te_expr *n);
|
void te_free(te_expr *n);
|
||||||
|
|
||||||
// TODO: That move there? Ouch. Replace with a proper class with a constructor.
|
// TODO: That move there? Ouch. Replace with a proper class with a constructor.
|
||||||
#define NEW_EXPR(type, ...) new_expr((type), std::move((const te_expr*[]){__VA_ARGS__}))
|
#define NEW_EXPR(type, ...) new_expr((type), std::move((const te_expr *[]){__VA_ARGS__}))
|
||||||
|
|
||||||
static te_expr *new_expr(const int type, const te_expr *parameters[]) {
|
static te_expr *new_expr(const int type, const te_expr *parameters[]) {
|
||||||
const int arity = get_arity(type);
|
const int arity = get_arity(type);
|
||||||
const int psize = sizeof(te_expr*) * arity;
|
const int psize = sizeof(te_expr *) * arity;
|
||||||
const int size = sizeof(te_expr) + psize;
|
const int size = sizeof(te_expr) + psize;
|
||||||
te_expr *ret = (te_expr *)malloc(size);
|
te_expr *ret = (te_expr *)malloc(size);
|
||||||
// This sets float to 0, which depends on the implementation.
|
// This sets float to 0, which depends on the implementation.
|
||||||
|
@ -103,7 +119,6 @@ static te_expr *new_expr(const int type, const te_expr *parameters[]) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void te_free_parameters(te_expr *n) {
|
void te_free_parameters(te_expr *n) {
|
||||||
if (!n) return;
|
if (!n) return;
|
||||||
int arity = get_arity(n->type);
|
int arity = get_arity(n->type);
|
||||||
|
@ -114,27 +129,22 @@ void te_free_parameters(te_expr *n) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void te_free(te_expr *n) {
|
void te_free(te_expr *n) {
|
||||||
if (!n) return;
|
if (!n) return;
|
||||||
te_free_parameters(n);
|
te_free_parameters(n);
|
||||||
free(n);
|
free(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static constexpr double pi() { return M_PI; }
|
static constexpr double pi() { return M_PI; }
|
||||||
static constexpr double e() { return M_E; }
|
static constexpr double e() { return M_E; }
|
||||||
|
|
||||||
static double fac(double a) { /* simplest version of fac */
|
static double fac(double a) { /* simplest version of fac */
|
||||||
if (a < 0.0)
|
if (a < 0.0) return NAN;
|
||||||
return NAN;
|
if (a > UINT_MAX) return INFINITY;
|
||||||
if (a > UINT_MAX)
|
|
||||||
return INFINITY;
|
|
||||||
unsigned int ua = (unsigned int)(a);
|
unsigned int ua = (unsigned int)(a);
|
||||||
unsigned long int result = 1, i;
|
unsigned long int result = 1, i;
|
||||||
for (i = 1; i <= ua; i++) {
|
for (i = 1; i <= ua; i++) {
|
||||||
if (i > ULONG_MAX / result)
|
if (i > ULONG_MAX / result) return INFINITY;
|
||||||
return INFINITY;
|
|
||||||
result *= i;
|
result *= i;
|
||||||
}
|
}
|
||||||
return (double)result;
|
return (double)result;
|
||||||
|
@ -147,15 +157,14 @@ static double ncr(double n, double r) {
|
||||||
unsigned long int result = 1;
|
unsigned long int result = 1;
|
||||||
if (ur > un / 2) ur = un - ur;
|
if (ur > un / 2) ur = un - ur;
|
||||||
for (i = 1; i <= ur; i++) {
|
for (i = 1; i <= ur; i++) {
|
||||||
if (result > ULONG_MAX / (un - ur + i))
|
if (result > ULONG_MAX / (un - ur + i)) return INFINITY;
|
||||||
return INFINITY;
|
|
||||||
result *= un - ur + i;
|
result *= un - ur + i;
|
||||||
result /= i;
|
result /= i;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double npr(double n, double r) {return ncr(n, r) * fac(r);}
|
static double npr(double n, double r) { return ncr(n, r) * fac(r); }
|
||||||
|
|
||||||
static const te_builtin functions[] = {
|
static const te_builtin functions[] = {
|
||||||
/* must be in alphabetical order */
|
/* must be in alphabetical order */
|
||||||
|
@ -183,14 +192,14 @@ static const te_builtin functions[] = {
|
||||||
{"sinh", (const void *)(te_fun1)sinh, TE_FUNCTION1},
|
{"sinh", (const void *)(te_fun1)sinh, TE_FUNCTION1},
|
||||||
{"sqrt", (const void *)(te_fun1)sqrt, TE_FUNCTION1},
|
{"sqrt", (const void *)(te_fun1)sqrt, TE_FUNCTION1},
|
||||||
{"tan", (const void *)(te_fun1)tan, TE_FUNCTION1},
|
{"tan", (const void *)(te_fun1)tan, TE_FUNCTION1},
|
||||||
{"tanh", (const void *)(te_fun1)tanh, TE_FUNCTION1}
|
{"tanh", (const void *)(te_fun1)tanh, TE_FUNCTION1}};
|
||||||
};
|
|
||||||
|
|
||||||
static const te_builtin *find_builtin(const char *name, int len) {
|
static const te_builtin *find_builtin(const char *name, int len) {
|
||||||
const auto end = std::end(functions);
|
const auto end = std::end(functions);
|
||||||
const te_builtin *found = std::lower_bound(std::begin(functions), end, name,
|
const te_builtin *found = std::lower_bound(std::begin(functions), end, name,
|
||||||
[len](const te_builtin &lhs, const char *rhs) {
|
[len](const te_builtin &lhs, const char *rhs) {
|
||||||
// The length is important because that's where the parens start
|
// The length is important because that's where
|
||||||
|
// the parens start
|
||||||
return std::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.
|
// We need to compare again because we might have gotten the first "larger" element.
|
||||||
|
@ -198,80 +207,115 @@ static const te_builtin *find_builtin(const char *name, int len) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr double add(double a, double b) {return a + b;}
|
static constexpr double add(double a, double b) { return a + b; }
|
||||||
static constexpr double sub(double a, double b) {return a - b;}
|
static constexpr double sub(double a, double b) { return a - b; }
|
||||||
static constexpr double mul(double a, double b) {return a * b;}
|
static constexpr double mul(double a, double b) { return a * b; }
|
||||||
static constexpr double divide(double a, double b) {
|
static constexpr double divide(double a, double b) {
|
||||||
// If b isn't zero, divide.
|
// If b isn't zero, divide.
|
||||||
// If a isn't zero, return signed INFINITY.
|
// If a isn't zero, return signed INFINITY.
|
||||||
// Else, return NAN.
|
// Else, return NAN.
|
||||||
return b ? a / b : a ? copysign(1, a) * copysign(1,b) * INFINITY : NAN;
|
return b ? a / b : a ? copysign(1, a) * copysign(1, b) * INFINITY : NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr double negate(double a) {return -a;}
|
static constexpr double negate(double a) { return -a; }
|
||||||
|
|
||||||
void next_token(state *s) {
|
void next_token(state *s) {
|
||||||
s->type = TOK_NULL;
|
s->type = TOK_NULL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!*s->next){
|
if (!*s->next) {
|
||||||
s->type = TOK_END;
|
s->type = TOK_END;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try reading a number. */
|
/* Try reading a number. */
|
||||||
if ((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') {
|
if ((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') {
|
||||||
s->value = strtod(s->next, (char**)&s->next);
|
s->value = strtod(s->next, (char **)&s->next);
|
||||||
s->type = TOK_NUMBER;
|
s->type = TOK_NUMBER;
|
||||||
} else {
|
} else {
|
||||||
/* Look for a variable or builtin function call. */
|
/* Look for a variable or builtin function call. */
|
||||||
if (s->next[0] >= 'a' && s->next[0] <= 'z') {
|
if (s->next[0] >= 'a' && s->next[0] <= 'z') {
|
||||||
const char *start;
|
const char *start;
|
||||||
start = s->next;
|
start = s->next;
|
||||||
while ((s->next[0] >= 'a' && s->next[0] <= 'z') || (s->next[0] >= '0' && s->next[0] <= '9') || (s->next[0] == '_')) s->next++;
|
while ((s->next[0] >= 'a' && s->next[0] <= 'z') ||
|
||||||
|
(s->next[0] >= '0' && s->next[0] <= '9') || (s->next[0] == '_'))
|
||||||
|
s->next++;
|
||||||
|
|
||||||
const te_builtin *var = find_builtin(start, s->next - start);
|
const te_builtin *var = find_builtin(start, s->next - start);
|
||||||
|
|
||||||
if (var) {
|
if (var) {
|
||||||
switch(var->type) {
|
switch (var->type) {
|
||||||
case TE_FUNCTION0: case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3:
|
case TE_FUNCTION0:
|
||||||
|
case TE_FUNCTION1:
|
||||||
|
case TE_FUNCTION2:
|
||||||
|
case TE_FUNCTION3:
|
||||||
s->type = var->type;
|
s->type = var->type;
|
||||||
s->function = var->address;
|
s->function = var->address;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (s->type != TOK_ERROR
|
} else if (s->type != TOK_ERROR || s->error == TE_ERROR_UNKNOWN) {
|
||||||
|| s->error == TE_ERROR_UNKNOWN) {
|
|
||||||
// Our error is more specific, so it takes precedence.
|
// Our error is more specific, so it takes precedence.
|
||||||
s->type = TOK_ERROR;
|
s->type = TOK_ERROR;
|
||||||
s->error = TE_ERROR_UNKNOWN_VARIABLE;
|
s->error = TE_ERROR_UNKNOWN_VARIABLE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Look for an operator or special character. */
|
/* Look for an operator or special character. */
|
||||||
switch (s->next++[0]) {
|
switch (s->next++ [0]) {
|
||||||
// The "te_fun2" casts are necessary to pick the right overload.
|
// The "te_fun2" casts are necessary to pick the right overload.
|
||||||
case '+': s->type = TOK_INFIX; s->function = (const void *)(te_fun2) add; break;
|
case '+':
|
||||||
case '-': s->type = TOK_INFIX; s->function = (const void *)(te_fun2) sub; break;
|
s->type = TOK_INFIX;
|
||||||
case '*': s->type = TOK_INFIX; s->function = (const void *)(te_fun2) mul; break;
|
s->function = (const void *)(te_fun2)add;
|
||||||
case '/': s->type = TOK_INFIX; s->function = (const void *)(te_fun2) divide; break;
|
break;
|
||||||
case '^': s->type = TOK_INFIX; s->function = (const void *)(te_fun2) pow; break;
|
case '-':
|
||||||
case '%': s->type = TOK_INFIX; s->function = (const void *)(te_fun2) fmod; break;
|
s->type = TOK_INFIX;
|
||||||
case '(': s->type = TOK_OPEN; break;
|
s->function = (const void *)(te_fun2)sub;
|
||||||
case ')': s->type = TOK_CLOSE; break;
|
break;
|
||||||
case ',': s->type = TOK_SEP; break;
|
case '*':
|
||||||
case ' ': case '\t': case '\n': case '\r': break;
|
s->type = TOK_INFIX;
|
||||||
default: s->type = TOK_ERROR; s->error = TE_ERROR_MISSING_OPERATOR; break;
|
s->function = (const void *)(te_fun2)mul;
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
s->type = TOK_INFIX;
|
||||||
|
s->function = (const void *)(te_fun2)divide;
|
||||||
|
break;
|
||||||
|
case '^':
|
||||||
|
s->type = TOK_INFIX;
|
||||||
|
s->function = (const void *)(te_fun2)pow;
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
s->type = TOK_INFIX;
|
||||||
|
s->function = (const void *)(te_fun2)fmod;
|
||||||
|
break;
|
||||||
|
case '(':
|
||||||
|
s->type = TOK_OPEN;
|
||||||
|
break;
|
||||||
|
case ')':
|
||||||
|
s->type = TOK_CLOSE;
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
s->type = TOK_SEP;
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s->type = TOK_ERROR;
|
||||||
|
s->error = TE_ERROR_MISSING_OPERATOR;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (s->type == TOK_NULL);
|
} while (s->type == TOK_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static te_expr *expr(state *s);
|
static te_expr *expr(state *s);
|
||||||
static te_expr *power(state *s);
|
static te_expr *power(state *s);
|
||||||
|
|
||||||
static te_expr *base(state *s) {
|
static te_expr *base(state *s) {
|
||||||
/* <base> = <constant> | <variable> | <function-0> {"(" ")"} | <function-1> <power> | <function-X> "(" <expr> {"," <expr>} ")" | "(" <list> ")" */
|
/* <base> = <constant> | <variable> | <function-0> {"(" ")"} | <function-1> <power> |
|
||||||
|
* <function-X> "(" <expr> {"," <expr>} ")" | "(" <list> ")" */
|
||||||
te_expr *ret;
|
te_expr *ret;
|
||||||
int arity;
|
int arity;
|
||||||
|
|
||||||
|
@ -290,8 +334,7 @@ static te_expr *base(state *s) {
|
||||||
next_token(s);
|
next_token(s);
|
||||||
if (s->type == TOK_CLOSE) {
|
if (s->type == TOK_CLOSE) {
|
||||||
next_token(s);
|
next_token(s);
|
||||||
} else if (s->type != TOK_ERROR
|
} else if (s->type != TOK_ERROR || s->error == TE_ERROR_UNKNOWN) {
|
||||||
|| s->error == TE_ERROR_UNKNOWN) {
|
|
||||||
s->type = TOK_ERROR;
|
s->type = TOK_ERROR;
|
||||||
s->error = TE_ERROR_MISSING_CLOSING_PAREN;
|
s->error = TE_ERROR_MISSING_CLOSING_PAREN;
|
||||||
}
|
}
|
||||||
|
@ -299,7 +342,8 @@ static te_expr *base(state *s) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TE_FUNCTION1:
|
case TE_FUNCTION1:
|
||||||
case TE_FUNCTION2: case TE_FUNCTION3:
|
case TE_FUNCTION2:
|
||||||
|
case TE_FUNCTION3:
|
||||||
arity = get_arity(s->type);
|
arity = get_arity(s->type);
|
||||||
|
|
||||||
ret = new_expr(s->type, 0);
|
ret = new_expr(s->type, 0);
|
||||||
|
@ -308,23 +352,20 @@ static te_expr *base(state *s) {
|
||||||
|
|
||||||
if (s->type == TOK_OPEN) {
|
if (s->type == TOK_OPEN) {
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < arity; i++) {
|
for (i = 0; i < arity; i++) {
|
||||||
next_token(s);
|
next_token(s);
|
||||||
ret->parameters[i] = expr(s);
|
ret->parameters[i] = expr(s);
|
||||||
if(s->type != TOK_SEP) {
|
if (s->type != TOK_SEP) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(s->type == TOK_CLOSE && i == arity - 1) {
|
if (s->type == TOK_CLOSE && i == arity - 1) {
|
||||||
next_token(s);
|
next_token(s);
|
||||||
} else if (s->type != TOK_ERROR
|
} else if (s->type != TOK_ERROR || s->error == TE_ERROR_UNKNOWN) {
|
||||||
|| s->error == TE_ERROR_UNKNOWN) {
|
|
||||||
s->type = TOK_ERROR;
|
s->type = TOK_ERROR;
|
||||||
s->error = i < arity ? TE_ERROR_TOO_FEW_ARGS
|
s->error = i < arity ? TE_ERROR_TOO_FEW_ARGS : TE_ERROR_TOO_MANY_ARGS;
|
||||||
: TE_ERROR_TOO_MANY_ARGS;
|
|
||||||
}
|
}
|
||||||
} else if (s->type != TOK_ERROR
|
} else if (s->type != TOK_ERROR || s->error == TE_ERROR_UNKNOWN) {
|
||||||
|| s->error == TE_ERROR_UNKNOWN) {
|
|
||||||
s->type = TOK_ERROR;
|
s->type = TOK_ERROR;
|
||||||
s->error = TE_ERROR_MISSING_OPENING_PAREN;
|
s->error = TE_ERROR_MISSING_OPENING_PAREN;
|
||||||
}
|
}
|
||||||
|
@ -336,8 +377,7 @@ static te_expr *base(state *s) {
|
||||||
ret = expr(s);
|
ret = expr(s);
|
||||||
if (s->type == TOK_CLOSE) {
|
if (s->type == TOK_CLOSE) {
|
||||||
next_token(s);
|
next_token(s);
|
||||||
} else if (s->type != TOK_ERROR
|
} else if (s->type != TOK_ERROR || s->error == TE_ERROR_UNKNOWN) {
|
||||||
|| s->error == TE_ERROR_UNKNOWN) {
|
|
||||||
s->type = TOK_ERROR;
|
s->type = TOK_ERROR;
|
||||||
s->error = TE_ERROR_MISSING_CLOSING_PAREN;
|
s->error = TE_ERROR_MISSING_CLOSING_PAREN;
|
||||||
}
|
}
|
||||||
|
@ -365,7 +405,6 @@ static te_expr *base(state *s) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static te_expr *power(state *s) {
|
static te_expr *power(state *s) {
|
||||||
/* <power> = {("-" | "+")} <base> */
|
/* <power> = {("-" | "+")} <base> */
|
||||||
int sign = 1;
|
int sign = 1;
|
||||||
|
@ -380,7 +419,7 @@ static te_expr *power(state *s) {
|
||||||
ret = base(s);
|
ret = base(s);
|
||||||
} else {
|
} else {
|
||||||
ret = NEW_EXPR(TE_FUNCTION1, base(s));
|
ret = NEW_EXPR(TE_FUNCTION1, base(s));
|
||||||
ret->function = (const void *) negate;
|
ret->function = (const void *)negate;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -390,56 +429,55 @@ static te_expr *factor(state *s) {
|
||||||
/* <factor> = <power> {"^" <power>} */
|
/* <factor> = <power> {"^" <power>} */
|
||||||
te_expr *ret = power(s);
|
te_expr *ret = power(s);
|
||||||
|
|
||||||
while (s->type == TOK_INFIX && (s->function == (const void*)(te_fun2)pow)) {
|
while (s->type == TOK_INFIX && (s->function == (const void *)(te_fun2)pow)) {
|
||||||
te_fun2 t = (te_fun2) s->function;
|
te_fun2 t = (te_fun2)s->function;
|
||||||
next_token(s);
|
next_token(s);
|
||||||
ret = NEW_EXPR(TE_FUNCTION2, ret, power(s));
|
ret = NEW_EXPR(TE_FUNCTION2, ret, power(s));
|
||||||
ret->function = (const void *) t;
|
ret->function = (const void *)t;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static te_expr *term(state *s) {
|
static te_expr *term(state *s) {
|
||||||
/* <term> = <factor> {("*" | "/" | "%") <factor>} */
|
/* <term> = <factor> {("*" | "/" | "%") <factor>} */
|
||||||
te_expr *ret = factor(s);
|
te_expr *ret = factor(s);
|
||||||
|
|
||||||
while (s->type == TOK_INFIX && (s->function == (const void*)(te_fun2)mul || s->function == (const void*)(te_fun2)divide || s->function == (const void*)(te_fun2)fmod)) {
|
while (s->type == TOK_INFIX && (s->function == (const void *)(te_fun2)mul ||
|
||||||
te_fun2 t = (te_fun2) s->function;
|
s->function == (const void *)(te_fun2)divide ||
|
||||||
|
s->function == (const void *)(te_fun2)fmod)) {
|
||||||
|
te_fun2 t = (te_fun2)s->function;
|
||||||
next_token(s);
|
next_token(s);
|
||||||
ret = NEW_EXPR(TE_FUNCTION2, ret, factor(s));
|
ret = NEW_EXPR(TE_FUNCTION2, ret, factor(s));
|
||||||
ret->function = (const void *) t;
|
ret->function = (const void *)t;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static te_expr *expr(state *s) {
|
static te_expr *expr(state *s) {
|
||||||
/* <expr> = <term> {("+" | "-") <term>} */
|
/* <expr> = <term> {("+" | "-") <term>} */
|
||||||
te_expr *ret = term(s);
|
te_expr *ret = term(s);
|
||||||
|
|
||||||
while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
|
while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
|
||||||
te_fun2 t = (te_fun2) s->function;
|
te_fun2 t = (te_fun2)s->function;
|
||||||
next_token(s);
|
next_token(s);
|
||||||
ret = NEW_EXPR(TE_FUNCTION2, ret, term(s));
|
ret = NEW_EXPR(TE_FUNCTION2, ret, term(s));
|
||||||
ret->function = (const void *) t;
|
ret->function = (const void *)t;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define TE_FUN(...) ((double (*)(__VA_ARGS__))n->function)
|
||||||
#define TE_FUN(...) ((double(*)(__VA_ARGS__))n->function)
|
|
||||||
#define M(e) te_eval(n->parameters[e])
|
#define M(e) te_eval(n->parameters[e])
|
||||||
|
|
||||||
|
|
||||||
double te_eval(const te_expr *n) {
|
double te_eval(const te_expr *n) {
|
||||||
if (!n) return NAN;
|
if (!n) return NAN;
|
||||||
|
|
||||||
switch(n->type) {
|
switch (n->type) {
|
||||||
case TE_CONSTANT: return n->value;
|
case TE_CONSTANT:
|
||||||
|
return n->value;
|
||||||
case TE_FUNCTION0:
|
case TE_FUNCTION0:
|
||||||
return TE_FUN(void)();
|
return TE_FUN(void)();
|
||||||
case TE_FUNCTION1:
|
case TE_FUNCTION1:
|
||||||
|
@ -448,9 +486,9 @@ double te_eval(const te_expr *n) {
|
||||||
return TE_FUN(double, double)(M(0), M(1));
|
return TE_FUN(double, double)(M(0), M(1));
|
||||||
case TE_FUNCTION3:
|
case TE_FUNCTION3:
|
||||||
return TE_FUN(double, double, double)(M(0), M(1), M(2));
|
return TE_FUN(double, double, double)(M(0), M(1), M(2));
|
||||||
default: return NAN;
|
default:
|
||||||
|
return NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef TE_FUN
|
#undef TE_FUN
|
||||||
|
@ -476,7 +514,6 @@ static void optimize(te_expr *n) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
te_expr *te_compile(const char *expression, te_error_t *error) {
|
te_expr *te_compile(const char *expression, te_error_t *error) {
|
||||||
state s;
|
state s;
|
||||||
s.start = s.next = expression;
|
s.start = s.next = expression;
|
||||||
|
@ -492,12 +529,11 @@ te_expr *te_compile(const char *expression, te_error_t *error) {
|
||||||
if (s.error != TE_ERROR_NONE) {
|
if (s.error != TE_ERROR_NONE) {
|
||||||
error->type = s.error;
|
error->type = s.error;
|
||||||
} else {
|
} else {
|
||||||
// If we're not at the end but there's no error, then that means we have a superfluous
|
// If we're not at the end but there's no error, then that means we have a
|
||||||
// token that we have no idea what to do with.
|
// superfluous token that we have no idea what to do with. This occurs in e.g. `2 +
|
||||||
// This occurs in e.g. `2 + 2 4` - the "4" is just not part of the expression.
|
// 2 4` - the "4" is just not part of the expression. We can report either "too many
|
||||||
// We can report either "too many arguments" or "expected operator", but the operator
|
// arguments" or "expected operator", but the operator should be reported between
|
||||||
// should be reported between the "2" and the "4".
|
// the "2" and the "4". So we report TOO_MANY_ARGS on the "4".
|
||||||
// So we report TOO_MANY_ARGS on the "4".
|
|
||||||
error->type = TE_ERROR_TOO_MANY_ARGS;
|
error->type = TE_ERROR_TOO_MANY_ARGS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,8 @@ enum parse_bool_statement_type_t bool_statement_type(tnode_t<grammar::job_decora
|
||||||
return static_cast<parse_bool_statement_type_t>(stmt.tag());
|
return static_cast<parse_bool_statement_type_t>(stmt.tag());
|
||||||
}
|
}
|
||||||
|
|
||||||
enum parse_bool_statement_type_t bool_statement_type(tnode_t<grammar::job_conjunction_continuation> cont) {
|
enum parse_bool_statement_type_t bool_statement_type(
|
||||||
|
tnode_t<grammar::job_conjunction_continuation> cont) {
|
||||||
return static_cast<parse_bool_statement_type_t>(cont.tag());
|
return static_cast<parse_bool_statement_type_t>(cont.tag());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -239,7 +239,8 @@ parse_statement_decoration_t get_decoration(tnode_t<grammar::plain_statement> st
|
||||||
/// Return the type for a boolean statement.
|
/// Return the type for a boolean statement.
|
||||||
enum parse_bool_statement_type_t bool_statement_type(tnode_t<grammar::job_decorator> stmt);
|
enum parse_bool_statement_type_t bool_statement_type(tnode_t<grammar::job_decorator> stmt);
|
||||||
|
|
||||||
enum parse_bool_statement_type_t bool_statement_type(tnode_t<grammar::job_conjunction_continuation> stmt);
|
enum parse_bool_statement_type_t bool_statement_type(
|
||||||
|
tnode_t<grammar::job_conjunction_continuation> stmt);
|
||||||
|
|
||||||
/// Given a redirection, get the redirection type (or none) and target (file path, or fd).
|
/// Given a redirection, get the redirection type (or none) and target (file path, or fd).
|
||||||
maybe_t<redirection_type_t> redirection_type(tnode_t<grammar::redirection> redirection,
|
maybe_t<redirection_type_t> redirection_type(tnode_t<grammar::redirection> redirection,
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
#include "wutil.h" // IWYU pragma: keep
|
#include "wutil.h" // IWYU pragma: keep
|
||||||
|
|
||||||
// _(s) is already wgettext(s).c_str(), so let's not convert back to wcstring
|
// _(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) {
|
const wchar_t *tokenizer_get_error_message(tokenizer_error_t err) {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case tokenizer_error_t::none:
|
case tokenizer_error_t::none:
|
||||||
return L"";
|
return L"";
|
||||||
|
@ -112,7 +112,9 @@ static bool tok_is_string_character(wchar_t c, bool is_first) {
|
||||||
// Conditional separator.
|
// Conditional separator.
|
||||||
return !caret_redirs() || !is_first;
|
return !caret_redirs() || !is_first;
|
||||||
}
|
}
|
||||||
default: { return true; }
|
default: {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,7 +631,9 @@ bool move_word_state_machine_t::consume_char_punctuation(wchar_t c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case s_end:
|
case s_end:
|
||||||
default: { break; }
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return consumed;
|
return consumed;
|
||||||
|
@ -697,7 +701,9 @@ bool move_word_state_machine_t::consume_char_path_components(wchar_t c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case s_end:
|
case s_end:
|
||||||
default: { break; }
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return consumed;
|
return consumed;
|
||||||
|
@ -731,7 +737,9 @@ bool move_word_state_machine_t::consume_char_whitespace(wchar_t c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case s_end:
|
case s_end:
|
||||||
default: { break; }
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return consumed;
|
return consumed;
|
||||||
|
|
|
@ -139,7 +139,9 @@ static int __utf8_forbitten(unsigned char octet) {
|
||||||
case 0xff: {
|
case 0xff: {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
default: { return 0; }
|
default: {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "fallback.h" // IWYU pragma: keep
|
#include "fallback.h" // IWYU pragma: keep
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
typedef wcstring::size_type size_type;
|
typedef wcstring::size_type size_type;
|
||||||
|
|
||||||
wcstring_range wcstring_tok(wcstring& str, const wcstring& needle, wcstring_range last) {
|
wcstring_range wcstring_tok(wcstring &str, const wcstring &needle, wcstring_range last) {
|
||||||
size_type pos = last.second == wcstring::npos ? wcstring::npos : last.first;
|
size_type pos = last.second == wcstring::npos ? wcstring::npos : last.first;
|
||||||
if (pos != wcstring::npos && last.second != wcstring::npos) pos += last.second;
|
if (pos != wcstring::npos && last.second != wcstring::npos) pos += last.second;
|
||||||
if (pos != wcstring::npos && pos != 0) ++pos;
|
if (pos != wcstring::npos && pos != 0) ++pos;
|
||||||
|
@ -31,7 +31,7 @@ wcstring_range wcstring_tok(wcstring& str, const wcstring& needle, wcstring_rang
|
||||||
}
|
}
|
||||||
|
|
||||||
wcstring truncate(const wcstring &input, int max_len, ellipsis_type etype) {
|
wcstring truncate(const wcstring &input, int max_len, ellipsis_type etype) {
|
||||||
if (input.size() <= (size_t) max_len) {
|
if (input.size() <= (size_t)max_len) {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,9 +47,7 @@ wcstring truncate(const wcstring &input, int max_len, ellipsis_type etype) {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
wcstring trim(const wcstring &input) {
|
wcstring trim(const wcstring &input) { return trim(input, L"\t\v \r\n"); }
|
||||||
return trim(input, L"\t\v \r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
wcstring trim(const wcstring &input, const wchar_t *any_of) {
|
wcstring trim(const wcstring &input, const wchar_t *any_of) {
|
||||||
auto begin_offset = input.find_first_not_of(any_of);
|
auto begin_offset = input.find_first_not_of(any_of);
|
||||||
|
|
|
@ -18,7 +18,7 @@ typedef std::pair<wcstring::size_type, wcstring::size_type> wcstring_range;
|
||||||
/// This will be (npos, npos) when it's done. In the form of (pos, npos)
|
/// This will be (npos, npos) when it's done. In the form of (pos, npos)
|
||||||
/// when the token is already known to be the final token.
|
/// when the token is already known to be the final token.
|
||||||
/// @note The final token may not necessarily return (pos, npos).
|
/// @note The final token may not necessarily return (pos, npos).
|
||||||
wcstring_range wcstring_tok(wcstring& str, const wcstring& needle,
|
wcstring_range wcstring_tok(wcstring &str, const wcstring &needle,
|
||||||
wcstring_range last = wcstring_range(0, 0));
|
wcstring_range last = wcstring_range(0, 0));
|
||||||
|
|
||||||
/// Given iterators into a string (forward or reverse), splits the haystack iterators
|
/// Given iterators into a string (forward or reverse), splits the haystack iterators
|
||||||
|
@ -29,7 +29,7 @@ wcstring_range wcstring_tok(wcstring& str, const wcstring& needle,
|
||||||
/// Max output entries will be max + 1 (after max splits)
|
/// Max output entries will be max + 1 (after max splits)
|
||||||
template <typename ITER>
|
template <typename ITER>
|
||||||
void split_about(ITER haystack_start, ITER haystack_end, ITER needle_start, ITER needle_end,
|
void split_about(ITER haystack_start, ITER haystack_end, ITER needle_start, ITER needle_end,
|
||||||
wcstring_list_t* output, long max = LONG_MAX, bool no_empty = false) {
|
wcstring_list_t *output, long max = LONG_MAX, bool no_empty = false) {
|
||||||
long remaining = max;
|
long remaining = max;
|
||||||
ITER haystack_cursor = haystack_start;
|
ITER haystack_cursor = haystack_start;
|
||||||
while (remaining > 0 && haystack_cursor != haystack_end) {
|
while (remaining > 0 && haystack_cursor != haystack_end) {
|
||||||
|
@ -57,13 +57,14 @@ void split_about(ITER haystack_start, ITER haystack_end, ITER needle_start, ITER
|
||||||
|
|
||||||
enum class ellipsis_type {
|
enum class ellipsis_type {
|
||||||
None,
|
None,
|
||||||
//Prefer niceness over minimalness
|
// Prefer niceness over minimalness
|
||||||
Prettiest,
|
Prettiest,
|
||||||
//Make every character count ($ instead of ...)
|
// Make every character count ($ instead of ...)
|
||||||
Shortest,
|
Shortest,
|
||||||
};
|
};
|
||||||
|
|
||||||
wcstring truncate(const wcstring &input, int max_len, ellipsis_type etype = ellipsis_type::Prettiest);
|
wcstring truncate(const wcstring &input, int max_len,
|
||||||
|
ellipsis_type etype = ellipsis_type::Prettiest);
|
||||||
wcstring trim(const wcstring &input);
|
wcstring trim(const wcstring &input);
|
||||||
wcstring trim(const wcstring &input, const wchar_t *any_of);
|
wcstring trim(const wcstring &input, const wchar_t *any_of);
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,8 @@
|
||||||
#include "config.h" // IWYU pragma: keep
|
#include "config.h" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
// This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves
|
// 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
|
// differently for the user, since it allows the user to intersperse the options with the other
|
||||||
|
@ -263,8 +263,8 @@ void wgetopter_t::_update_long_opt(int argc, wchar_t **argv, const struct woptio
|
||||||
else {
|
else {
|
||||||
if (wopterr) {
|
if (wopterr) {
|
||||||
if (argv[woptind - 1][1] == '-') // --option
|
if (argv[woptind - 1][1] == '-') // --option
|
||||||
std::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"),
|
||||||
pfound->name);
|
argv[0], pfound->name);
|
||||||
else
|
else
|
||||||
// +option or -option
|
// +option or -option
|
||||||
std::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"),
|
||||||
|
|
|
@ -336,8 +336,9 @@ 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 stat_res The result of calling stat on the file
|
||||||
/// \param buf The struct buf output 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.
|
/// \param err The errno value after a failed stat call on the file.
|
||||||
static const wchar_t *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,
|
||||||
int stat_res, const struct stat &buf, int err) {
|
const struct stat &lbuf, int stat_res, const struct stat &buf,
|
||||||
|
int err) {
|
||||||
if (lstat_res) {
|
if (lstat_res) {
|
||||||
return COMPLETE_FILE_DESC;
|
return COMPLETE_FILE_DESC;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstring>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <cstring>
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
#include <sys/statfs.h>
|
#include <sys/statfs.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,8 +18,8 @@
|
||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cwchar>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -231,13 +231,9 @@ dir_t::~dir_t() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dir_t::valid() const {
|
bool dir_t::valid() const { return this->dir != nullptr; }
|
||||||
return this->dir != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dir_t::read(wcstring &name) {
|
bool dir_t::read(wcstring &name) { return wreaddir(this->dir, name); }
|
||||||
return wreaddir(this->dir, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
int wstat(const wcstring &file_name, struct stat *buf) {
|
int wstat(const wcstring &file_name, struct stat *buf) {
|
||||||
const cstring tmp = wcs2string(file_name);
|
const cstring tmp = wcs2string(file_name);
|
||||||
|
@ -289,7 +285,9 @@ int make_fd_blocking(int fd) {
|
||||||
|
|
||||||
int fd_check_is_remote(int fd) {
|
int fd_check_is_remote(int fd) {
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
struct statfs buf{0};
|
struct statfs buf {
|
||||||
|
0
|
||||||
|
};
|
||||||
if (fstatfs(fd, &buf) < 0) {
|
if (fstatfs(fd, &buf) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
12
src/wutil.h
12
src/wutil.h
|
@ -3,13 +3,13 @@
|
||||||
#define FISH_WUTIL_H
|
#define FISH_WUTIL_H
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <locale.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <locale.h>
|
|
||||||
#include <string>
|
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#ifdef HAVE_XLOCALE_H
|
#ifdef HAVE_XLOCALE_H
|
||||||
#include <xlocale.h>
|
#include <xlocale.h>
|
||||||
|
@ -181,16 +181,16 @@ struct dir_t {
|
||||||
#ifndef HASH_FILE_ID
|
#ifndef HASH_FILE_ID
|
||||||
#define HASH_FILE_ID 1
|
#define HASH_FILE_ID 1
|
||||||
namespace std {
|
namespace std {
|
||||||
template<>
|
template <>
|
||||||
struct hash<file_id_t> {
|
struct hash<file_id_t> {
|
||||||
size_t operator()(const file_id_t &f) const {
|
size_t operator()(const file_id_t &f) const {
|
||||||
std::hash<decltype(f.device)> hasher1;
|
std::hash<decltype(f.device)> hasher1;
|
||||||
std::hash<decltype(f.inode)> hasher2;
|
std::hash<decltype(f.inode)> hasher2;
|
||||||
|
|
||||||
return hasher1(f.device) ^ hasher2(f.inode);
|
return hasher1(f.device) ^ hasher2(f.inode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace std
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
file_id_t file_id_for_fd(int fd);
|
file_id_t file_id_for_fd(int fd);
|
||||||
|
|
Loading…
Reference in a new issue