Compare commits

...

20 Commits

Author SHA1 Message Date
ridiculousfish
e752ac3035 Further tweak the language about setting PATH in the tutorial 2015-07-03 12:46:59 -07:00
ridiculousfish
8ca21767fe Improve discussion of how to set PATH in the tutorial
Also fix a few broken anchors
2015-07-03 12:35:53 -07:00
David Adam
e60db8075c Open universal variable lock file read/write and ignore errors
Closes #2149.
2015-07-03 15:31:03 +08:00
David Adam
322a611872 Bump version for 2.2.0 2015-06-28 18:11:48 +08:00
ridiculousfish
ecb2da3142 Fix wildcard expansion in directories without read permissions
When performing wildcard expansion with a literal path segment,
instead of enumerating the files in the directory, simply apply the
path segment as if we found the directory and continue on. This
enables us to expand strings that contain unreadable directory
components (common with $HOME) and also improves performance, since
we don't waste time enumerating directories unnecessarily. Adds
a test too.

Fixes #2099
2015-06-25 19:22:15 -07:00
ridiculousfish
d79a72d722 Add abbreviation tests 2015-06-14 14:14:12 -07:00
ridiculousfish
781bbe217a Tweak and add tests for abbr
1. When run with no arguments, make abbr do the equivalent
   of `abbr --show`
2. Enable "implicit add", e.g. `abbr gco git checkout`
3. Teach `abbr --show` to not use quotes for simple cases
4. Teach abbr to output -- when the abbreviation has
   leading dashes

Add some basic tests to abbr too.
2015-06-14 14:13:33 -07:00
ridiculousfish
064ad7b981 Rework how the mode is reported in fish_vi_mode
Add a new function fish_mode_prompt which (if it is defined) has its output
prepended to the left prompt. Rather than replacing the prompt wholesale, make
fish_vi_mode enable this function by setting a variable __fish_vi_mode. This
enables vi mode to interoperate nicely with custom prompts. Users who want
to change how the mode is reported can either redefine this function or
erase it entirely. Fixes #1988.
2015-06-14 11:36:20 -07:00
ridiculousfish
6fbb3c9976 fish_config to select the proper tab when run with a tab name
`fish_config abbr` should show "abbreviations" selected
in the tab list.
2015-06-14 00:12:23 -07:00
ridiculousfish
7b34aaa432 Tweak the styling of the abbreviation editor
Removes the big white block of the input fields.
2015-06-14 00:12:23 -07:00
ridiculousfish
5c6143d8e9 Use --remove instead of -e when erasing abbreviations from fish_config
Updates fish_config to use the correct argument to abbr
2015-06-14 00:12:23 -07:00
ridiculousfish
ea407476d0 Correctly un-export an env var when it is shadowed
Prior to this fix, if you exported a variable in one scope
and then unexported it in the next, it would remain exported.
Example:

    set -gx VAR 1
    function foo; set -l VAR; env; end
    foo

Here 'VAR' would be exported to 'env' because we failed to
notice that the env var is shadowed by an unexported variable.
This occurred at env var computation time, not in env_set!

Fixes #2132
2015-06-12 16:11:45 -07:00
David Adam
b6b6de3304 vi bindings: clear commandline with Ctrl-C
Closes #2077.
2015-06-05 14:01:43 +08:00
ridiculousfish
79a6961793 Add some simple documentation for fish_vi_mode 2015-06-04 13:18:17 -07:00
ridiculousfish
6c53862ff1 Suppress uvar error messages due to permissions or file not found
su does not reset XDG_RUNTIME_DIR, which means that XDG_RUNTIME_DIR
may point to directories that the user does not have permission
to access. Similarly there is no guarantee that XDG_RUNTIME_DIR
points to a directory that actually exists. Rather than try to
handle these issues, we simply ignore them, effectively disabling
realtime uvar notifications. Fixes #1955.
2015-06-01 23:03:11 -07:00
David Adam
c0cf25cf0b abbr: rename --remove to --erase
for consistency with other fish commands

Closes #2071.
2015-05-22 09:48:39 +08:00
ridiculousfish
edf6a951ee Unescape the token returned by builtin_commandline
Fixes #2075
2015-05-22 08:46:23 +08:00
David Adam
1c99ef5b6e FAQ: shorter fish_title fix
[skip ci]
2015-05-21 12:05:21 +08:00
ridiculousfish
a83323705d Make fish_config work correctly when IPv6 is disabled in the kernel
Fixes #1754
2015-05-17 19:13:50 -07:00
ridiculousfish
49b49d7ed4 Pass the character index, not the character, to parse_util_expand_variable_error
Fixes #2067
2015-05-15 17:17:30 -07:00
33 changed files with 293 additions and 148 deletions

View File

@@ -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");
}

View File

@@ -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

View File

@@ -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
View 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.

View 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
View File

@@ -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())
{

View File

@@ -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
{

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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'

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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>

View File

@@ -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
View File

@@ -0,0 +1 @@
abbr: no such abbreviation 'NOT_AN_ABBR'

33
tests/abbr.in Normal file
View 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
View 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
View File

@@ -0,0 +1 @@
0

View File

@@ -28,3 +28,6 @@ fish: echo ()[1]
Invalid index value
fish: echo ()[d]
^
$) is not a valid variable in fish.
fish: echo $$paren
^

View File

@@ -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

View File

@@ -40,3 +40,4 @@
0
1
0
Catch your breath

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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'/')
{