mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-22 12:11:16 -03:00
Compare commits
20 Commits
2.2b1
...
Integratio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e752ac3035 | ||
|
|
8ca21767fe | ||
|
|
e60db8075c | ||
|
|
322a611872 | ||
|
|
ecb2da3142 | ||
|
|
d79a72d722 | ||
|
|
781bbe217a | ||
|
|
064ad7b981 | ||
|
|
6fbb3c9976 | ||
|
|
7b34aaa432 | ||
|
|
5c6143d8e9 | ||
|
|
ea407476d0 | ||
|
|
b6b6de3304 | ||
|
|
79a6961793 | ||
|
|
6c53862ff1 | ||
|
|
c0cf25cf0b | ||
|
|
edf6a951ee | ||
|
|
1c99ef5b6e | ||
|
|
a83323705d | ||
|
|
49b49d7ed4 |
@@ -206,7 +206,9 @@ static void write_part(const wchar_t *begin,
|
||||
{
|
||||
case TOK_STRING:
|
||||
{
|
||||
out.append(escape_string(tok_last(&tok), UNESCAPE_INCOMPLETE));
|
||||
wcstring tmp = tok_last(&tok);
|
||||
unescape_string_in_place(&tmp, UNESCAPE_INCOMPLETE);
|
||||
out.append(tmp);
|
||||
out.push_back(L'\n');
|
||||
break;
|
||||
}
|
||||
@@ -230,8 +232,9 @@ static void write_part(const wchar_t *begin,
|
||||
}
|
||||
|
||||
// debug( 0, L"woot2 %ls -> %ls", buff, esc );
|
||||
|
||||
stdout_buffer.append(begin, end - begin);
|
||||
wcstring tmp = wcstring(begin, end - begin);
|
||||
unescape_string_in_place(&tmp, UNESCAPE_INCOMPLETE);
|
||||
stdout_buffer.append(tmp);
|
||||
stdout_buffer.append(L"\n");
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
abbr -a word="phrase"
|
||||
abbr -s
|
||||
abbr -l
|
||||
abbr -r word
|
||||
abbr -e word
|
||||
\endfish
|
||||
|
||||
\subsection abbr-description Description
|
||||
@@ -24,7 +24,7 @@ The following parameters are available:
|
||||
|
||||
- `-l` or `--list` Lists all abbreviated words.
|
||||
|
||||
- `-r WORD` or `--remove WORD` Remove the abbreviation WORD.
|
||||
- `-e WORD` or `--erase WORD` Erase the abbreviation WORD.
|
||||
|
||||
\subsection abbr-example Examples
|
||||
|
||||
@@ -34,9 +34,9 @@ abbr -a gco git checkout
|
||||
Add a new abbreviation where `gco` will be replaced with `git checkout`.
|
||||
|
||||
\fish
|
||||
abbr -r gco
|
||||
abbr -e gco
|
||||
\endfish
|
||||
Remove the `gco` abbreviation.
|
||||
Erase the `gco` abbreviation.
|
||||
|
||||
\fish
|
||||
ssh another_host abbr -s | source
|
||||
|
||||
@@ -162,7 +162,7 @@ Quick answer:
|
||||
Run the following command in fish:
|
||||
|
||||
\fish{cli-dark}
|
||||
echo 'function fish_title;end' >> ~/.config/fish/config.fish
|
||||
function fish_title; end; funcsave fish_title
|
||||
\endfish
|
||||
|
||||
Problem solved!
|
||||
|
||||
10
doc_src/fish_vi_mode.txt
Normal file
10
doc_src/fish_vi_mode.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
408-600-6421\section fish_vi_mode fish_vi_mode - Enable vi mode
|
||||
|
||||
\subsection fish_vi_mode-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
fish_vi_mode
|
||||
\endfish
|
||||
|
||||
\subsection fish_vi_mode-description Description
|
||||
|
||||
`fish_vi_mode` enters a vi-like command editing mode. To always start in vi mode, add `fish_vi_mode` to your `config.fish` file.
|
||||
@@ -27,7 +27,7 @@
|
||||
- <a href="#tut_path">$PATH</a>
|
||||
- <a href="#tut_startup">Startup</a>
|
||||
- <a href="#tut_autoload">Autoloading Functions</a>
|
||||
- <a href="#tut-more">Ready for more?</a>
|
||||
- <a href="#tut_more">Ready for more?</a>
|
||||
|
||||
\htmlonly[block]
|
||||
</div>
|
||||
@@ -510,18 +510,25 @@ Multiple lines are OK. Colors can be set via `set_color`, passing it named ANSI
|
||||
|
||||
You can choose among some sample prompts by running `fish_config prompt`. `fish` also supports RPROMPT through `fish_right_prompt`.
|
||||
|
||||
\section tut-path $PATH
|
||||
\section tut_path $PATH
|
||||
|
||||
`$PATH` is an environment variable containing the directories in which `fish` searches for commands. Instead of separating entries with a colon, $PATH is a list. You can modify $PATH in a few ways:
|
||||
`$PATH` is an environment variable containing the directories in which `fish` searches for commands. Unlike other shells, $PATH is a [list](#tut_lists), not a colon-delimited string.
|
||||
|
||||
-# By modifying the `$fish_user_paths` variable, which is automatically appended to `$PATH`. For example, to permanently add `/usr/local/bin` to your `$PATH`, you could write:
|
||||
To prepend to `$PATH`, you can write:
|
||||
|
||||
\fish{cli-dark}
|
||||
>_ set -U fish_user_paths $fish_user_paths /usr/local/bin
|
||||
>_ set PATH /new/path $PATH
|
||||
\endfish
|
||||
|
||||
-# Directly in config.fish (see below).
|
||||
You can do so directly in `fish.config`, like you might do in other shells with `.profile`. See [this example](#path_example).
|
||||
|
||||
A faster way is to modify the `$fish_user_paths` [universal variable](#tut_universal), which is automatically prepended to `$PATH`. For example, to permanently add `/usr/local/bin` to your `$PATH`, you could write:
|
||||
|
||||
\fish{cli-dark}
|
||||
>_ set -U fish_user_paths /usr/local/bin $fish_user_paths
|
||||
\endfish
|
||||
|
||||
The advantage is that you don't have to go mucking around in files: just run this once at the command line, and it will affect the current session and all future instances too. (Note: you should NOT add this line to `fish.config`. If you do, the variable will get longer each time you run fish!)
|
||||
|
||||
\section tut_startup Startup (Where's .bashrc?)
|
||||
|
||||
@@ -529,6 +536,7 @@ You can choose among some sample prompts by running `fish_config prompt`. `fish`
|
||||
|
||||
It is possible to directly create functions and variables in `config.fish` file, using the commands shown above. For example:
|
||||
|
||||
<a name="path_example"></a>
|
||||
\fish{cli-dark}
|
||||
>_ cat ~/.config/fish/config.fish
|
||||
|
||||
@@ -541,7 +549,7 @@ end
|
||||
|
||||
However, it is more common and efficient to use autoloading functions and universal variables.
|
||||
|
||||
\section tut-autoload Autoloading Functions
|
||||
\section tut_autoload Autoloading Functions
|
||||
|
||||
When `fish` encounters a command, it attempts to autoload a function for that command, by looking for a file with the name of that command in `~/.config/fish/functions/`.
|
||||
|
||||
@@ -565,7 +573,7 @@ end
|
||||
|
||||
See the documentation for <a href="commands.html#funced">funced</a> and <a href="commands.html#funcsave">funcsave</a> for ways to create these files automatically.
|
||||
|
||||
\section tut-universal Universal Variables
|
||||
\section tut_universal Universal Variables
|
||||
|
||||
A universal variable is a variable whose value is shared across all instances of `fish`, now and in the future – even after a reboot. You can make a variable universal with `set -U`:
|
||||
|
||||
@@ -580,7 +588,7 @@ Now in another shell:
|
||||
vim
|
||||
\endfish
|
||||
|
||||
\section tut-more Ready for more?
|
||||
\section tut_more Ready for more?
|
||||
|
||||
If you want to learn more about fish, there is <a href="index.html">lots of detailed documentation</a>, an <a href="https://lists.sourceforge.net/lists/listinfo/fish-users">official mailing list</a>, the IRC channel \#fish on `irc.oftc.net`, and the <a href="https://github.com/fish-shell/fish-shell/">github page</a>.
|
||||
|
||||
|
||||
19
env.cpp
19
env.cpp
@@ -1264,7 +1264,7 @@ wcstring_list_t env_get_names(int flags)
|
||||
Get list of all exported variables
|
||||
*/
|
||||
|
||||
static void get_exported(const env_node_t *n, std::map<wcstring, wcstring> &h)
|
||||
static void get_exported(const env_node_t *n, std::map<wcstring, wcstring> *h)
|
||||
{
|
||||
if (!n)
|
||||
return;
|
||||
@@ -1279,10 +1279,19 @@ static void get_exported(const env_node_t *n, std::map<wcstring, wcstring> &h)
|
||||
{
|
||||
const wcstring &key = iter->first;
|
||||
const var_entry_t &val_entry = iter->second;
|
||||
if (val_entry.exportv && (val_entry.val != ENV_NULL))
|
||||
|
||||
if (val_entry.exportv && val_entry.val != ENV_NULL)
|
||||
{
|
||||
// Don't use std::map::insert here, since we need to overwrite existing values from previous scopes
|
||||
h[key] = val_entry.val;
|
||||
// Export the variable
|
||||
// Don't use std::map::insert here, since we need to overwrite existing
|
||||
// values from previous scopes
|
||||
(*h)[key] = val_entry.val;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need to erase from the map if we are not exporting,
|
||||
// since a lower scope may have exported. See #2132
|
||||
h->erase(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1333,7 +1342,7 @@ static void update_export_array_if_necessary(bool recalc)
|
||||
|
||||
debug(4, L"env_export_arr() recalc");
|
||||
|
||||
get_exported(top, vals);
|
||||
get_exported(top, &vals);
|
||||
|
||||
if (uvars())
|
||||
{
|
||||
|
||||
@@ -698,7 +698,7 @@ bool env_universal_t::open_and_acquire_lock(const wcstring &path, int *out_fd)
|
||||
*/
|
||||
int result_fd = -1;
|
||||
bool needs_lock = true;
|
||||
int flags = O_RDONLY | O_CREAT;
|
||||
int flags = O_RDWR | O_CREAT;
|
||||
#ifdef O_EXLOCK
|
||||
flags |= O_EXLOCK;
|
||||
needs_lock = false;
|
||||
@@ -741,8 +741,7 @@ bool env_universal_t::open_and_acquire_lock(const wcstring &path, int *out_fd)
|
||||
/* error */
|
||||
if (errno != EINTR)
|
||||
{
|
||||
int err = errno;
|
||||
report_error(err, L"Unable to lock universal variable file '%ls'", path.c_str());
|
||||
/* Do nothing per #2149 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1376,7 +1375,13 @@ class universal_notifier_named_pipe_t : public universal_notifier_t
|
||||
{
|
||||
// Maybe open failed, maybe mkfifo failed
|
||||
int err = errno;
|
||||
report_error(err, L"Unable to make or open a FIFO for universal variables with path '%ls'", vars_path.c_str());
|
||||
// We explicitly do NOT report an error for ENOENT or EACCESS
|
||||
// This works around #1955, where $XDG_RUNTIME_DIR may get a bogus value under suc
|
||||
if (err != ENOENT && err != EPERM)
|
||||
{
|
||||
report_error(err, L"Unable to make or open a FIFO for universal variables with path '%ls'", vars_path.c_str());
|
||||
}
|
||||
pipe_fd= -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1034,7 +1034,7 @@ static int expand_variables(parser_t &parser, const wcstring &instr, std::vector
|
||||
{
|
||||
if (errors)
|
||||
{
|
||||
parse_util_expand_variable_error(instr, 0 /* global_token_pos */, c, errors);
|
||||
parse_util_expand_variable_error(instr, 0 /* global_token_pos */, i, errors);
|
||||
}
|
||||
|
||||
is_ok = false;
|
||||
|
||||
@@ -1327,7 +1327,7 @@
|
||||
"SYSCONFDIR=L\\\"/usr/local/etc\\\"",
|
||||
"BINDIR=L\\\"/usr/local/bin\\\"",
|
||||
"DOCDIR=L\\\"/usr/local/share/doc\\\"",
|
||||
"FISH_BUILD_VERSION=\\\"2.2b1\\\"",
|
||||
"FISH_BUILD_VERSION=\\\"2.2.0\\\"",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
@@ -1455,7 +1455,7 @@
|
||||
"SYSCONFDIR=L\\\"/usr/local/etc\\\"",
|
||||
"BINDIR=L\\\"/usr/local/bin\\\"",
|
||||
"DOCDIR=L\\\"/usr/local/share/doc\\\"",
|
||||
"FISH_BUILD_VERSION=\\\"2.2b1\\\"",
|
||||
"FISH_BUILD_VERSION=\\\"2.2.0\\\"",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
@@ -1483,7 +1483,7 @@
|
||||
"SYSCONFDIR=L\\\"/usr/local/etc\\\"",
|
||||
"BINDIR=L\\\"/usr/local/bin\\\"",
|
||||
"DOCDIR=L\\\"/usr/local/share/doc\\\"",
|
||||
"FISH_BUILD_VERSION=\\\"2.2b1\\\"",
|
||||
"FISH_BUILD_VERSION=\\\"2.2.0\\\"",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
|
||||
@@ -222,7 +222,7 @@
|
||||
#define PACKAGE_NAME "fish"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "fish 2.2b1"
|
||||
#define PACKAGE_STRING "fish 2.2.0"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "fish"
|
||||
@@ -231,7 +231,7 @@
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "2.2b1"
|
||||
#define PACKAGE_VERSION "2.2.0"
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
16
reader.cpp
16
reader.cpp
@@ -128,6 +128,10 @@ commence.
|
||||
#define RIGHT_PROMPT_FUNCTION_NAME L"fish_right_prompt"
|
||||
|
||||
|
||||
/* The name of the function for getting the input mode indicator */
|
||||
#define MODE_PROMPT_FUNCTION_NAME L"fish_mode_prompt"
|
||||
|
||||
|
||||
/**
|
||||
The default title for the reader. This is used by reader_readline.
|
||||
*/
|
||||
@@ -997,6 +1001,18 @@ static void exec_prompt()
|
||||
{
|
||||
proc_push_interactive(0);
|
||||
|
||||
// Prepend any mode indicator to the left prompt (#1988)
|
||||
if (function_exists(MODE_PROMPT_FUNCTION_NAME))
|
||||
{
|
||||
wcstring_list_t mode_indicator_list;
|
||||
exec_subshell(MODE_PROMPT_FUNCTION_NAME, mode_indicator_list, apply_exit_status);
|
||||
// We do not support multiple lines in the mode indicator, so just concatenate all of them
|
||||
for (size_t i = 0; i < mode_indicator_list.size(); i++)
|
||||
{
|
||||
data->left_prompt_buff += mode_indicator_list.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (! data->left_prompt.empty())
|
||||
{
|
||||
wcstring_list_t prompt_list;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
complete -c abbr -f -s a -l add -d 'Add abbreviation'
|
||||
complete -c abbr -s r -l remove -d 'Remove abbreviation' -xa '(abbr -l)'
|
||||
complete -c abbr -s e -l erase -d 'Erase abbreviation' -xa '(abbr -l)'
|
||||
complete -c abbr -f -s s -l show -d 'Print all abbreviations'
|
||||
complete -c abbr -f -s l -l list -d 'Print all abbreviation names'
|
||||
complete -c abbr -f -s h -l help -d 'Help'
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
function abbr --description "Manage abbreviations"
|
||||
if not set -q argv[1]
|
||||
__fish_print_help abbr
|
||||
return 1
|
||||
end
|
||||
|
||||
# parse arguments
|
||||
set -l mode
|
||||
set -l mode_flag # the flag that was specified, for better errors
|
||||
@@ -26,8 +21,8 @@ function abbr --description "Manage abbreviations"
|
||||
case '-a' '--add'
|
||||
set new_mode add
|
||||
set needs_arg coalesce
|
||||
case '-r' '--remove'
|
||||
set new_mode remove
|
||||
case '-e' '--erase'
|
||||
set new_mode erase
|
||||
set needs_arg single
|
||||
case '-l' '--list'
|
||||
set new_mode list
|
||||
@@ -56,6 +51,18 @@ function abbr --description "Manage abbreviations"
|
||||
printf ( _ "%s: option requires an argument -- %s\n" ) abbr $mode_flag >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
# If run with no options, treat it like --add if we have an argument, or
|
||||
# --show if we do not have an argument
|
||||
if test -z "$mode"
|
||||
if set -q argv[1]
|
||||
set mode 'add'
|
||||
set mode_arg "$argv"
|
||||
set -e argv
|
||||
else
|
||||
set mode 'show'
|
||||
end
|
||||
end
|
||||
|
||||
# none of our modes want any excess arguments
|
||||
if set -q argv[1]
|
||||
@@ -91,7 +98,7 @@ function abbr --description "Manage abbreviations"
|
||||
set fish_user_abbreviations $fish_user_abbreviations $mode_arg
|
||||
return 0
|
||||
|
||||
case 'remove'
|
||||
case 'erase'
|
||||
set -l key
|
||||
__fish_abbr_parse_entry $mode_arg key
|
||||
if set -l idx (__fish_abbr_get_by_key $key)
|
||||
@@ -106,7 +113,14 @@ function abbr --description "Manage abbreviations"
|
||||
for i in $fish_user_abbreviations
|
||||
# Disable newline splitting
|
||||
set -lx IFS ''
|
||||
echo abbr -a \'(__fish_abbr_escape $i)\'
|
||||
__fish_abbr_parse_entry $i key value
|
||||
|
||||
# Check to see if either key or value has a leading dash
|
||||
# If so, we need to write --
|
||||
set -l opt_double_dash ''
|
||||
switch $key ; case '-*'; set opt_double_dash ' --'; end
|
||||
switch $value ; case '-*'; set opt_double_dash ' --'; end
|
||||
echo abbr$opt_double_dash (__fish_abbr_escape "$key") (__fish_abbr_escape "$value")
|
||||
end
|
||||
return 0
|
||||
|
||||
@@ -121,7 +135,17 @@ function abbr --description "Manage abbreviations"
|
||||
end
|
||||
|
||||
function __fish_abbr_escape
|
||||
echo $argv | sed -e s,\\\\,\\\\\\\\,g -e s,\',\\\\\',g
|
||||
# Prettify the common case: if everything is alphanumeric,
|
||||
# we do not need escapes.
|
||||
# Do this by deleting alnum characters, and check if there's anything left.
|
||||
# Note we need to preserve spaces, so spaces are not considered alnum
|
||||
if test -z (echo -n "$argv" | tr -d '[:alnum:]_')
|
||||
echo $argv
|
||||
else
|
||||
# Escape via single quotes
|
||||
# printf is nice for stripping the newline that sed outputs
|
||||
printf "'%s'" (echo -n $argv | sed -e s,\\\\,\\\\\\\\,g -e s,\',\\\\\',g)
|
||||
end
|
||||
end
|
||||
|
||||
function __fish_abbr_get_by_key
|
||||
|
||||
19
share/functions/fish_mode_prompt.fish
Normal file
19
share/functions/fish_mode_prompt.fish
Normal file
@@ -0,0 +1,19 @@
|
||||
# The fish_mode_prompt function is prepended to the prompt
|
||||
function fish_mode_prompt --description "Displays the current mode"
|
||||
# Do nothing if not in vi mode
|
||||
if set -q __fish_vi_mode
|
||||
switch $fish_bind_mode
|
||||
case default
|
||||
set_color --bold --background red white
|
||||
echo '[N]'
|
||||
case insert
|
||||
set_color --bold --background green white
|
||||
echo '[I]'
|
||||
case visual
|
||||
set_color --bold --background magenta white
|
||||
echo '[V]'
|
||||
end
|
||||
set_color normal
|
||||
echo -n ' '
|
||||
end
|
||||
end
|
||||
@@ -191,7 +191,7 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish'
|
||||
bind -M insert \cb backward-word
|
||||
bind -M insert \cf forward-word
|
||||
|
||||
bind -M insert -m default \cc backward-char force-repaint
|
||||
bind -M insert \cc 'commandline ""'
|
||||
bind -M insert -m default \e backward-char force-repaint
|
||||
|
||||
bind -M insert \cd exit
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
function fish_vi_mode
|
||||
function fish_prompt
|
||||
fish_vi_prompt
|
||||
end
|
||||
# Set the __fish_vi_mode variable
|
||||
# This triggers fish_mode_prompt to output the mode indicator
|
||||
set -g __fish_vi_mode 1
|
||||
|
||||
# Turn on vi keybindings
|
||||
set -g fish_key_bindings fish_vi_key_bindings
|
||||
end
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
function fish_vi_prompt_cm --description "Displays the current mode"
|
||||
echo -n " "
|
||||
switch $fish_bind_mode
|
||||
case default
|
||||
set_color --bold --background red white
|
||||
echo "[N]"
|
||||
case insert
|
||||
set_color --bold --background green white
|
||||
echo "[I]"
|
||||
case visual
|
||||
set_color --bold --background magenta white
|
||||
echo "[V]"
|
||||
end
|
||||
set_color normal
|
||||
end
|
||||
|
||||
function fish_vi_prompt --description "Simple vi prompt"
|
||||
|
||||
# Just calculate these once, to save a few cycles when displaying the prompt
|
||||
if not set -q __fish_prompt_hostname
|
||||
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
|
||||
end
|
||||
|
||||
if not set -q __fish_prompt_normal
|
||||
set -g __fish_prompt_normal (set_color normal)
|
||||
end
|
||||
|
||||
switch $USER
|
||||
|
||||
case root toor
|
||||
|
||||
if not set -q __fish_prompt_cwd
|
||||
if set -q fish_color_cwd_root
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd_root)
|
||||
else
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
|
||||
end
|
||||
end
|
||||
|
||||
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal" (fish_vi_prompt_cm) '# '
|
||||
|
||||
case '*'
|
||||
|
||||
if not set -q __fish_prompt_cwd
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
|
||||
end
|
||||
|
||||
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal" (fish_vi_prompt_cm) '> '
|
||||
|
||||
end
|
||||
end
|
||||
@@ -29,6 +29,8 @@ body {
|
||||
border-right: none;
|
||||
padding-bottom: 15px;
|
||||
padding-top: 15px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
font-size: 17pt;
|
||||
text-align: center;
|
||||
width: 15%;
|
||||
@@ -232,12 +234,22 @@ body {
|
||||
border-bottom: #444 dotted 1px;
|
||||
}
|
||||
|
||||
.abbreviation_actions {
|
||||
width: 5em;
|
||||
.abbreviation_actions {
|
||||
width: 8em;
|
||||
text-align: right;
|
||||
border-bottom: #444 dotted 1px;
|
||||
}
|
||||
|
||||
.abbreviation_input {
|
||||
background-color: #111;
|
||||
border: solid 1px #777;
|
||||
height: 1.5em;
|
||||
color: white;
|
||||
font: inherit;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* The CSS we apply when a table row is filtered */
|
||||
.data_table_row_filtered {
|
||||
display: none;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
controllers = angular.module("controllers", []);
|
||||
|
||||
controllers.controller("main", function($scope, $location) {
|
||||
$scope.currentTab = "colors";
|
||||
|
||||
// substr(1) strips a leading slash
|
||||
$scope.currentTab = $location.path().substr(1) || "colors";
|
||||
$scope.changeView = function(view) {
|
||||
$location.path(view);
|
||||
$scope.currentTab = view;
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
<table class="data_table">
|
||||
<tbody>
|
||||
<tr class="data_table_row" ng-repeat="abbreviation in abbreviations | filterAbbreviations:query" ng-click="editAbbreviation(abbreviation)">
|
||||
<td ng-class="{ data_table_cell: true }" style="text-align: right; padding-right: 30px;">
|
||||
<td ng-class="{ data_table_cell: true }" style="text-align: right; padding-right: 30px;">
|
||||
<span ng-hide="abbreviation.editable">{{ abbreviation.word }}</span>
|
||||
<span ng-show="abbreviation.editable"><input ng-model="abbreviation.word"></span>
|
||||
<span ng-show="abbreviation.editable"><input ng-model="abbreviation.word" class="abbreviation_input" style="text-align: right; min-width: 10em;"></span>
|
||||
</td>
|
||||
<td ng-class="{ data_table_cell: true }" style="text-align: left; padding-right: 30px;">
|
||||
<span ng-hide="abbreviation.editable">{{ abbreviation.phrase }}</span>
|
||||
<span ng-show="abbreviation.editable"><input ng-model="abbreviation.phrase"></span>
|
||||
<span ng-show="abbreviation.editable"><input ng-model="abbreviation.phrase" class="abbreviation_input" style="text-align: left; min-width: 22em;"></span>
|
||||
</td>
|
||||
<td ng-class="{ data_table_cell: true }" class="abbreviation_actions">
|
||||
<span ng-show="abbreviation.editable && abbreviation.word && abbreviation.phrase" ng-click="saveAbbreviation(abbreviation)">Save</span>
|
||||
<a ng-show="abbreviation.word" ng-click="removeAbbreviation(abbreviation)"><img alt="Delete" src="delete.png"></a>
|
||||
<span ng-show="abbreviation.editable && abbreviation.word && abbreviation.phrase" ng-click="saveAbbreviation(abbreviation)"><span class="save_button" style="margin: inherit;">Save</span></span>
|
||||
<a ng-show="abbreviation.word" ng-click="removeAbbreviation(abbreviation)"><img alt="Delete" src="delete.png" style="vertical-align: text-bottom"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -6,6 +6,7 @@ import sys
|
||||
import multiprocessing.pool
|
||||
import os
|
||||
import operator
|
||||
import socket
|
||||
IS_PY2 = sys.version_info[0] == 2
|
||||
|
||||
if IS_PY2:
|
||||
@@ -18,6 +19,14 @@ else:
|
||||
import socketserver as SocketServer
|
||||
from urllib.parse import parse_qs
|
||||
|
||||
# Check to see if IPv6 is enabled in the kernel
|
||||
HAS_IPV6 = True
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
||||
s.close()
|
||||
except:
|
||||
HAS_IPV6 = False
|
||||
|
||||
# Disable CLI web browsers
|
||||
term = os.environ.pop('TERM', None)
|
||||
import webbrowser
|
||||
@@ -419,7 +428,7 @@ class FishConfigTCPServer(SocketServer.TCPServer):
|
||||
"""TCPServer that only accepts connections from localhost (IPv4/IPv6)."""
|
||||
WHITELIST = set(['::1', '::ffff:127.0.0.1', '127.0.0.1'])
|
||||
|
||||
address_family = socket.AF_INET6
|
||||
address_family = socket.AF_INET6 if HAS_IPV6 else socket.AF_INET
|
||||
|
||||
def verify_request(self, request, client_address):
|
||||
return client_address[0] in FishConfigTCPServer.WHITELIST
|
||||
@@ -693,14 +702,14 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
return result
|
||||
|
||||
def do_remove_abbreviation(self, abbreviation):
|
||||
out, err = run_fish_cmd('abbr -r %s' % abbreviation['word'])
|
||||
out, err = run_fish_cmd('abbr --remove %s' % abbreviation['word'])
|
||||
if out or err:
|
||||
return err
|
||||
else:
|
||||
return True
|
||||
|
||||
def do_save_abbreviation(self, abbreviation):
|
||||
out, err = run_fish_cmd('abbr -a \'%s %s\'' % (abbreviation['word'], abbreviation['phrase']))
|
||||
out, err = run_fish_cmd('abbr --add -- \'%s %s\'' % (abbreviation['word'], abbreviation['phrase']))
|
||||
if err:
|
||||
return err
|
||||
else:
|
||||
@@ -910,16 +919,18 @@ authkey = binascii.b2a_hex(os.urandom(16)).decode('ascii')
|
||||
|
||||
# Try to find a suitable port
|
||||
PORT = 8000
|
||||
HOST = "::" if HAS_IPV6 else "localhost"
|
||||
while PORT <= 9000:
|
||||
try:
|
||||
Handler = FishConfigHTTPRequestHandler
|
||||
httpd = FishConfigTCPServer(("::", PORT), Handler)
|
||||
httpd = FishConfigTCPServer((HOST, PORT), Handler)
|
||||
# Success
|
||||
break
|
||||
except socket.error:
|
||||
err_type, err_value = sys.exc_info()[:2]
|
||||
# str(err_value) handles Python3 correctly
|
||||
if 'Address already in use' not in str(err_value):
|
||||
print(str(err_value))
|
||||
break
|
||||
PORT += 1
|
||||
|
||||
|
||||
1
tests/abbr.err
Normal file
1
tests/abbr.err
Normal file
@@ -0,0 +1 @@
|
||||
abbr: no such abbreviation 'NOT_AN_ABBR'
|
||||
33
tests/abbr.in
Normal file
33
tests/abbr.in
Normal file
@@ -0,0 +1,33 @@
|
||||
# Test basic add and list
|
||||
abbr __abbr1 alpha beta gamma
|
||||
abbr | grep __abbr1
|
||||
|
||||
# Erasing one that doesn't exist should do nothing
|
||||
abbr --erase NOT_AN_ABBR
|
||||
abbr | grep __abbr1
|
||||
|
||||
# Adding existing one should be idempotent
|
||||
abbr __abbr1 alpha beta gamma
|
||||
abbr | grep __abbr1
|
||||
|
||||
# Replacing
|
||||
abbr __abbr1 delta
|
||||
abbr | grep __abbr1
|
||||
|
||||
# -s and --show tests
|
||||
abbr -s | grep __abbr1
|
||||
abbr --show | grep __abbr1
|
||||
|
||||
# Test erasing
|
||||
abbr -e __abbr1
|
||||
abbr | grep __abbr1
|
||||
|
||||
# Ensure we escape special characters on output
|
||||
abbr '~__abbr2' '$xyz'
|
||||
abbr | grep __abbr2
|
||||
abbr -e '~__abbr2'
|
||||
|
||||
# Ensure we handle leading dashes in abbreviation names properly
|
||||
abbr -- '--__abbr3' 'xyz'
|
||||
abbr | grep __abbr3
|
||||
abbr -e '--__abbr3'
|
||||
8
tests/abbr.out
Normal file
8
tests/abbr.out
Normal file
@@ -0,0 +1,8 @@
|
||||
abbr __abbr1 'alpha beta gamma'
|
||||
abbr __abbr1 'alpha beta gamma'
|
||||
abbr __abbr1 'alpha beta gamma'
|
||||
abbr __abbr1 delta
|
||||
abbr __abbr1 delta
|
||||
abbr __abbr1 delta
|
||||
abbr '~__abbr2' '$xyz'
|
||||
abbr -- '--__abbr3' xyz
|
||||
1
tests/abbr.status
Normal file
1
tests/abbr.status
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -28,3 +28,6 @@ fish: echo ()[1]
|
||||
Invalid index value
|
||||
fish: echo ()[d]
|
||||
^
|
||||
$) is not a valid variable in fish.
|
||||
fish: echo $$paren
|
||||
^
|
||||
|
||||
@@ -81,6 +81,10 @@ echo $foo[d]
|
||||
echo ()[1]
|
||||
echo ()[d]
|
||||
|
||||
echo "Catch your breath"
|
||||
set paren ')'
|
||||
echo $$paren
|
||||
|
||||
# Test tilde expansion
|
||||
# On OS X, /tmp is symlinked to /private/tmp
|
||||
# $PWD is our best bet for resolving it
|
||||
|
||||
@@ -40,3 +40,4 @@
|
||||
0
|
||||
1
|
||||
0
|
||||
Catch your breath
|
||||
|
||||
@@ -227,6 +227,14 @@ else
|
||||
echo Test 16 fail
|
||||
end
|
||||
|
||||
# Test that shadowing with a non-exported variable works
|
||||
set -gx __fish_test_env17 UNSHADOWED
|
||||
env | sgrep __fish_test_env17
|
||||
function __fish_test_shadow
|
||||
set -l __fish_test_env17
|
||||
env | sgrep __fish_test_env17 ; or echo SHADOWED
|
||||
end
|
||||
__fish_test_shadow
|
||||
|
||||
# clear for other shells
|
||||
set -eU __fish_test_universal_variables_variable_foo
|
||||
|
||||
@@ -16,6 +16,8 @@ Test 15 pass
|
||||
Foo change detected
|
||||
Foo change detected
|
||||
Test 16 pass
|
||||
__fish_test_env17=UNSHADOWED
|
||||
SHADOWED
|
||||
Testing Universal Startup
|
||||
1
|
||||
1
|
||||
|
||||
@@ -23,3 +23,15 @@ switch $smurf
|
||||
case "?????"
|
||||
echo Test 3 pass
|
||||
end
|
||||
|
||||
# Verify that we can do wildcard expansion when we
|
||||
# don't have read access to some path components
|
||||
# See #2099
|
||||
set -l where /tmp/fish_wildcard_permissions_test/noaccess/yesaccess
|
||||
mkdir -p $where
|
||||
chmod 300 (dirname $where) # no read permissions
|
||||
mkdir -p $where
|
||||
touch $where/alpha.txt $where/beta.txt $where/delta.txt
|
||||
echo $where/*
|
||||
chmod 700 (dirname $where) # so we can delete it
|
||||
rm -rf /tmp/fish_wildcard_permissions_test
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
Test 1 pass
|
||||
Test 2 pass
|
||||
Test 3 pass
|
||||
/tmp/fish_wildcard_permissions_test/noaccess/yesaccess/alpha.txt /tmp/fish_wildcard_permissions_test/noaccess/yesaccess/beta.txt /tmp/fish_wildcard_permissions_test/noaccess/yesaccess/delta.txt
|
||||
|
||||
77
wildcard.cpp
77
wildcard.cpp
@@ -772,19 +772,12 @@ static int wildcard_expand_internal(const wchar_t *wc,
|
||||
std::set<wcstring> &completion_set,
|
||||
std::set<file_id_t> &visited_files)
|
||||
{
|
||||
|
||||
/* Variables for traversing a directory */
|
||||
DIR *dir;
|
||||
|
||||
/* The result returned */
|
||||
int res = 0;
|
||||
|
||||
/* Variables for testing for presense of recursive wildcards */
|
||||
const wchar_t *wc_recursive;
|
||||
bool is_recursive;
|
||||
|
||||
/* Slightly mangled version of base_dir */
|
||||
const wchar_t *dir_string;
|
||||
|
||||
// debug( 3, L"WILDCARD_EXPAND %ls in %ls", wc, base_dir );
|
||||
|
||||
@@ -800,45 +793,61 @@ static int wildcard_expand_internal(const wchar_t *wc,
|
||||
}
|
||||
|
||||
const size_t base_dir_len = wcslen(base_dir);
|
||||
const size_t wc_len = wcslen(wc);
|
||||
|
||||
if (flags & ACCEPT_INCOMPLETE)
|
||||
{
|
||||
/*
|
||||
Avoid excessive number of returned matches for wc ending with a *
|
||||
*/
|
||||
size_t len = wcslen(wc);
|
||||
if (len > 0 && (wc[len-1]==ANY_STRING))
|
||||
if (wc_len > 0 && (wc[wc_len-1]==ANY_STRING))
|
||||
{
|
||||
wchar_t * foo = wcsdup(wc);
|
||||
foo[len-1]=0;
|
||||
foo[wc_len-1]=0;
|
||||
int res = wildcard_expand_internal(foo, base_dir, flags, out, completion_set, visited_files);
|
||||
free(foo);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize various variables */
|
||||
/* Determine if we are the last segment */
|
||||
const wchar_t * const next_slash = wcschr(wc,L'/');
|
||||
const bool is_last_segment = (next_slash == NULL);
|
||||
const size_t wc_segment_len = next_slash ? next_slash - wc : wc_len;
|
||||
const wcstring wc_segment = wcstring(wc, wc_segment_len);
|
||||
|
||||
/* Maybe this segment has no wildcards at all. If this is not the last segment, and it has no wildcards, then we don't need to match against the directory contents, and in fact we don't want to match since we may not be able to read it anyways (#2099). Don't even open the directory! */
|
||||
const bool segment_has_wildcards = wildcard_has(wc_segment, true /* internal, i.e. look for ANY_CHAR instead of ? */);
|
||||
if (! segment_has_wildcards && ! is_last_segment)
|
||||
{
|
||||
wcstring new_base_dir = make_path(base_dir, wc_segment);
|
||||
new_base_dir.push_back(L'/');
|
||||
|
||||
/* Skip multiple separators */
|
||||
assert(next_slash != NULL);
|
||||
const wchar_t *new_wc = next_slash;
|
||||
while (*new_wc==L'/')
|
||||
{
|
||||
new_wc++;
|
||||
}
|
||||
/* Early out! */
|
||||
return wildcard_expand_internal(new_wc, new_base_dir.c_str(), flags, out, completion_set, visited_files);
|
||||
}
|
||||
|
||||
/* Test for recursive match string in current segment */
|
||||
const bool is_recursive = (wc_segment.find(ANY_STRING_RECURSIVE) != wcstring::npos);
|
||||
|
||||
|
||||
dir_string = (base_dir[0] == L'\0') ? L"." : base_dir;
|
||||
|
||||
if (!(dir = wopendir(dir_string)))
|
||||
const wchar_t *base_dir_or_cwd = (base_dir[0] == L'\0') ? L"." : base_dir;
|
||||
if (!(dir = wopendir(base_dir_or_cwd)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Points to the end of the current wildcard segment */
|
||||
const wchar_t * const wc_end = wcschr(wc,L'/');
|
||||
|
||||
/*
|
||||
Test for recursive match string in current segment
|
||||
*/
|
||||
wc_recursive = wcschr(wc, ANY_STRING_RECURSIVE);
|
||||
is_recursive = (wc_recursive && (!wc_end || wc_recursive < wc_end));
|
||||
|
||||
|
||||
/*
|
||||
Is this segment of the wildcard the last?
|
||||
*/
|
||||
if (!wc_end)
|
||||
if (is_last_segment)
|
||||
{
|
||||
/*
|
||||
Wildcard segment is the last segment,
|
||||
@@ -926,7 +935,7 @@ static int wildcard_expand_internal(const wchar_t *wc,
|
||||
}
|
||||
}
|
||||
|
||||
if (wc_end || is_recursive)
|
||||
if ((! is_last_segment) || is_recursive)
|
||||
{
|
||||
/*
|
||||
Wilcard segment is not the last segment. Recursively call
|
||||
@@ -939,12 +948,6 @@ static int wildcard_expand_internal(const wchar_t *wc,
|
||||
*/
|
||||
rewinddir(dir);
|
||||
|
||||
/*
|
||||
wc_str is the part of the wildcarded string from the
|
||||
beginning to the first slash
|
||||
*/
|
||||
const wcstring wc_str = wcstring(wc, wc_end ? wc_end - wc : wcslen(wc));
|
||||
|
||||
/* new_dir is a scratch area containing the full path to a file/directory we are iterating over */
|
||||
wcstring new_dir = base_dir;
|
||||
|
||||
@@ -955,8 +958,8 @@ static int wildcard_expand_internal(const wchar_t *wc,
|
||||
Test if the file/directory name matches the whole
|
||||
wildcard element, i.e. regular matching.
|
||||
*/
|
||||
int whole_match = wildcard_match(name_str, wc_str, true /* ignore leading dots */);
|
||||
int partial_match = 0;
|
||||
bool whole_match = wildcard_match(name_str, wc_segment, true /* ignore leading dots */);
|
||||
bool partial_match = false;
|
||||
|
||||
/*
|
||||
If we are doing recursive matching, also check if this
|
||||
@@ -999,11 +1002,11 @@ static int wildcard_expand_internal(const wchar_t *wc,
|
||||
if (whole_match)
|
||||
{
|
||||
const wchar_t *new_wc = L"";
|
||||
if (wc_end)
|
||||
if (next_slash)
|
||||
{
|
||||
new_wc=wc_end+1;
|
||||
new_wc=next_slash+1;
|
||||
/*
|
||||
Accept multiple '/' as a single direcotry separator
|
||||
Accept multiple '/' as a single directory separator
|
||||
*/
|
||||
while (*new_wc==L'/')
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user