mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
Merge branch 'master' into fish_config_angular
This commit is contained in:
commit
659541f4a5
76 changed files with 2848 additions and 2146 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -18,7 +18,6 @@ doc_src/commands.hdr
|
|||
doc_src/index.hdr
|
||||
po/*.gmo
|
||||
fish
|
||||
fish.spec
|
||||
fish_indent
|
||||
fish_pager
|
||||
fish_tests
|
||||
|
|
98
Makefile.in
98
Makefile.in
|
@ -1,4 +1,3 @@
|
|||
|
||||
# Copyright (C) 2005-2006 Axel Liljencrantz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -21,14 +20,7 @@
|
|||
|
||||
#
|
||||
# Makefile for the fish shell. Can build fish and associated
|
||||
# applications, install them, recalculate dependencies and also create
|
||||
# binary distributions in tar.bz2, tar.gz and rpm formats.
|
||||
#
|
||||
|
||||
#
|
||||
# The fish buildprocess is quite complex. Do not stare directly into
|
||||
# the Makefile. Doing so may cause nausea, dizziness and
|
||||
# hallucinations.
|
||||
# applications, install them, and recalculate dependencies.
|
||||
#
|
||||
|
||||
# Used by docdir
|
||||
|
@ -61,9 +53,9 @@ optbindirs = @optbindirs@
|
|||
# Various flags
|
||||
#
|
||||
|
||||
MACROS = -DLOCALEDIR=\"$(localedir)\" -DPREFIX=L\"$(prefix)\" -DDATADIR=L\"$(datadir)\" -DSYSCONFDIR=L\"$(sysconfdir)\" -DBINDIR=L\"$(bindir)\"
|
||||
MACROS = -DLOCALEDIR=\"$(localedir)\" -DPREFIX=L\"$(prefix)\" -DDATADIR=L\"$(datadir)\" -DSYSCONFDIR=L\"$(sysconfdir)\" -DBINDIR=L\"$(bindir)\" -DDOCDIR=L\"$(docdir)\"
|
||||
CXXFLAGS = @CXXFLAGS@ $(MACROS) $(EXTRA_CXXFLAGS)
|
||||
LDFLAGS = @LIBS@ @LDFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LDFLAGS_FISH = ${LDFLAGS} @LIBS_FISH@ @LDFLAGS_FISH@
|
||||
LDFLAGS_FISH_INDENT = ${LDFLAGS} @LIBS_FISH_INDENT@
|
||||
LDFLAGS_FISH_PAGER = ${LDFLAGS} @LIBS_FISH_PAGER@
|
||||
|
@ -168,11 +160,6 @@ HDR_FILES := $(HDR_FILES_SRC:.hdr.in=.hdr)
|
|||
# Use a pattern rule so that Make knows to only issue one invocation
|
||||
# per http://www.gnu.org/software/make/manual/make.html#Pattern-Intro
|
||||
|
||||
# Internalized scripts are currently disabled.
|
||||
# For now, we just generate empty arrays.
|
||||
# To generate them again, you would run this:
|
||||
# ./internalize_scripts.py share/functions/*.fish share/completions/*.fish
|
||||
|
||||
|
||||
#
|
||||
# Files containing documentation for external commands.
|
||||
|
@ -187,53 +174,11 @@ HELP_SRC := $(wildcard doc_src/*.txt)
|
|||
|
||||
TEST_IN := $(wildcard tests/test*.in)
|
||||
|
||||
|
||||
#
|
||||
# Files that should be added to the tar archives
|
||||
#
|
||||
|
||||
#
|
||||
# Files in ./doc_src/
|
||||
#
|
||||
|
||||
DOC_SRC_DIR_FILES := $(HDR_FILES_SRC) $(HELP_SRC)
|
||||
|
||||
|
||||
#
|
||||
# Files in ./
|
||||
#
|
||||
|
||||
MAIN_DIR_FILES_UNSORTED := Doxyfile Doxyfile.user Doxyfile.help \
|
||||
Makefile.in configure configure.ac config.h.in install-sh \
|
||||
key_reader.cpp $(MIME_OBJS:.o=.h) \
|
||||
$(MIME_OBJS:.o=.cpp) $(FISH_OBJS:.o=.h) $(BUILTIN_FILES) \
|
||||
$(COMMON_FILES) $(COMMON_FILES:.cpp=.h) $(FISH_OBJS:.o=.cpp) \
|
||||
fish.spec.in INSTALL README user_doc.head.html \
|
||||
ChangeLog config.sub config.guess fish_tests.cpp fish.cpp fish_pager.cpp \
|
||||
fishd.cpp make_vcs_completions.fish $(FISH_INDENT_OBJS:.o=.cpp)
|
||||
|
||||
#
|
||||
# The sorting is not meaningful in itself, but it has the side effect
|
||||
# of removing duplicates, which means there will be fewer warnings
|
||||
# during building.
|
||||
#
|
||||
|
||||
MAIN_DIR_FILES := $(sort $(MAIN_DIR_FILES_UNSORTED))
|
||||
|
||||
|
||||
#
|
||||
# Files in ./tests/
|
||||
#
|
||||
|
||||
TESTS_DIR_FILES := $(TEST_IN) $(TEST_IN:.in=.out) $(TEST_IN:.in=.err) \
|
||||
$(TEST_IN:.in=.status) tests/test.fish tests/gen_output.fish
|
||||
|
||||
|
||||
#
|
||||
# Files in ./share/completions/
|
||||
#
|
||||
|
||||
COMPLETIONS_DIR_FILES := $(wildcard share/completions/*.fish)
|
||||
COMPLETIONS_DIR_FILES := $(wildcard share/completions/*.fish) share/completions/..fish
|
||||
|
||||
|
||||
#
|
||||
|
@ -450,7 +395,7 @@ doc.h: $(HDR_FILES)
|
|||
#
|
||||
|
||||
%.po:messages.pot
|
||||
if test $(HAVE_GETTEXT) = 1;then \
|
||||
if test "$(HAVE_GETTEXT)" = 1;then \
|
||||
if test -f $*.po; then \
|
||||
msgmerge -U --backup=existing $*.po messages.pot;\
|
||||
else \
|
||||
|
@ -464,7 +409,7 @@ doc.h: $(HDR_FILES)
|
|||
#
|
||||
|
||||
messages.pot: *.cpp *.h share/completions/*.fish share/functions/*.fish
|
||||
if test $(HAVE_GETTEXT) = 1;then \
|
||||
if test "$(HAVE_GETTEXT)" = 1; then \
|
||||
xgettext -k_ -kN_ *.cpp *.h -o messages.pot; \
|
||||
if xgettext -j -k_ -kN_ -k--description -LShell share/completions/*.fish share/functions/*.fish -o messages.pot; then true; else \
|
||||
echo "Your xgettext version is too old to build the messages.pot file"\
|
||||
|
@ -509,7 +454,7 @@ share/man: $(HELP_SRC)
|
|||
-mkdir share/man
|
||||
touch share/man
|
||||
-rm -Rf share/man/man1
|
||||
./build_tools/build_documentation.sh Doxyfile.help ./doc_src ./share
|
||||
PROJECT_NUMBER=`echo $(FISH_BUILD_VERSION)| sed "s/-.*//"` ./build_tools/build_documentation.sh Doxyfile.help ./doc_src ./share
|
||||
|
||||
#
|
||||
# The build rules for installing/uninstalling fish
|
||||
|
@ -715,7 +660,7 @@ uninstall-legacy: uninstall
|
|||
.PHONY: uninstall-legacy
|
||||
|
||||
install-translations: $(TRANSLATIONS)
|
||||
if test $(HAVE_GETTEXT) = 1; then \
|
||||
if test "$(HAVE_GETTEXT)" = 1; then \
|
||||
for i in $(TRANSLATIONS); do \
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/locale/`basename $$i .gmo`/LC_MESSAGES; \
|
||||
$(INSTALL) -m 644 $$i $(DESTDIR)$(datadir)/locale/`basename $$i .gmo`/LC_MESSAGES/fish.mo; \
|
||||
|
@ -725,7 +670,7 @@ install-translations: $(TRANSLATIONS)
|
|||
.PHONY: install-translations
|
||||
|
||||
uninstall-translations:
|
||||
if test $(HAVE_GETTEXT) = 1; then \
|
||||
if test "$(HAVE_GETTEXT)" = 1; then \
|
||||
for i in $(TRANSLATIONS_SRC); do \
|
||||
rm -f $(DESTDIR)$(datadir)/locale/*/LC_MESSAGES/fish.mo; \
|
||||
done; \
|
||||
|
@ -742,7 +687,7 @@ uninstall-translations:
|
|||
#
|
||||
|
||||
fish: $(FISH_OBJS) fish.o
|
||||
$(CXX) $(FISH_OBJS) fish.o $(LDFLAGS_FISH) -o $@
|
||||
$(CXX) $(CXXFLAGS) $(FISH_OBJS) fish.o $(LDFLAGS_FISH) -o $@
|
||||
|
||||
|
||||
#
|
||||
|
@ -750,7 +695,7 @@ fish: $(FISH_OBJS) fish.o
|
|||
#
|
||||
|
||||
fish_pager: $(FISH_PAGER_OBJS)
|
||||
$(CXX) $(FISH_PAGER_OBJS) $(LDFLAGS_FISH_PAGER) -o $@
|
||||
$(CXX) $(CXXFLAGS) $(FISH_PAGER_OBJS) $(LDFLAGS_FISH_PAGER) -o $@
|
||||
|
||||
|
||||
#
|
||||
|
@ -758,7 +703,7 @@ fish_pager: $(FISH_PAGER_OBJS)
|
|||
#
|
||||
|
||||
fishd: $(FISHD_OBJS)
|
||||
$(CXX) $(FISHD_OBJS) $(LDFLAGS_FISHD) -o $@
|
||||
$(CXX) $(CXXFLAGS) $(FISHD_OBJS) $(LDFLAGS_FISHD) -o $@
|
||||
|
||||
|
||||
#
|
||||
|
@ -766,17 +711,15 @@ fishd: $(FISHD_OBJS)
|
|||
#
|
||||
|
||||
fish_tests: $(FISH_TESTS_OBJS)
|
||||
$(CXX) $(FISH_TESTS_OBJS) $(LDFLAGS_FISH) -o $@
|
||||
$(CXX) $(CXXFLAGS) $(FISH_TESTS_OBJS) $(LDFLAGS_FISH) -o $@
|
||||
|
||||
|
||||
#
|
||||
# Build the mimedb program.
|
||||
#
|
||||
# mimedb does not need any libraries, so we don't use LDFLAGS here.
|
||||
#
|
||||
|
||||
mimedb: $(MIME_OBJS)
|
||||
$(CXX) $(MIME_OBJS) $(LDFLAGS_MIMEDB) -o $@
|
||||
$(CXX) $(CXXFLAGS) $(MIME_OBJS) $(LDFLAGS_MIMEDB) -o $@
|
||||
|
||||
|
||||
#
|
||||
|
@ -784,7 +727,7 @@ mimedb: $(MIME_OBJS)
|
|||
#
|
||||
|
||||
fish_indent: $(FISH_INDENT_OBJS)
|
||||
$(CXX) $(FISH_INDENT_OBJS) $(LDFLAGS_FISH_INDENT) -o $@
|
||||
$(CXX) $(CXXFLAGS) $(FISH_INDENT_OBJS) $(LDFLAGS_FISH_INDENT) -o $@
|
||||
|
||||
|
||||
#
|
||||
|
@ -792,7 +735,7 @@ fish_indent: $(FISH_INDENT_OBJS)
|
|||
#
|
||||
|
||||
key_reader: key_reader.o input_common.o common.o env_universal.o env_universal_common.o wutil.o iothread.o
|
||||
$(CXX) key_reader.o input_common.o common.o env_universal.o env_universal_common.o wutil.o iothread.o $(LDFLAGS_FISH) -o $@
|
||||
$(CXX) $(CXXFLAGS) key_reader.o input_common.o common.o env_universal.o env_universal_common.o wutil.o iothread.o $(LDFLAGS_FISH) -o $@
|
||||
|
||||
|
||||
#
|
||||
|
@ -803,13 +746,6 @@ depend:
|
|||
./config.status
|
||||
.PHONY: depend
|
||||
|
||||
#
|
||||
# Build the RPM spec file.
|
||||
#
|
||||
|
||||
fish.spec: fish.spec.in
|
||||
./config.status
|
||||
|
||||
#
|
||||
# Cleanup targets
|
||||
#
|
||||
|
@ -819,7 +755,6 @@ fish.spec: fish.spec.in
|
|||
#
|
||||
|
||||
distclean: clean
|
||||
rm -f fish.spec
|
||||
rm -f config.status config.log config.h Makefile
|
||||
.PHONY: distclean
|
||||
|
||||
|
@ -835,7 +770,6 @@ distclean: clean
|
|||
|
||||
clean:
|
||||
rm -f *.o doc.h doc.tmp doc_src/*.doxygen doc_src/*.cpp doc_src/*.o doc_src/commands.hdr
|
||||
rm -f $(GENERATED_INTERN_SCRIPT_FILES)
|
||||
rm -f tests/tmp.err tests/tmp.out tests/tmp.status tests/foo.txt
|
||||
rm -f $(PROGRAMS) fish_tests key_reader
|
||||
rm -f command_list.txt command_list_toc.txt toc.txt
|
||||
|
|
|
@ -50,7 +50,7 @@ on RedHat, CentOS, or Amazon EC2:
|
|||
|
||||
## Packages for Linux
|
||||
|
||||
Nightly builds for several Linux distros can be downloaded from <http://download.opensuse.org/repositories/home:/siteshwar/>
|
||||
Instructions on how to find builds for several Linux distros are at <https://github.com/fish-shell/fish-shell/wiki/Nightly-builds>
|
||||
|
||||
## Switching to fish
|
||||
|
||||
|
@ -66,6 +66,12 @@ To switch your default shell back, you can run:
|
|||
|
||||
Substitute /bin/bash with /bin/tcsh or /bin/zsh as appropriate.
|
||||
|
||||
## Optional Dependencies
|
||||
|
||||
In order to generate completions from man pages compressed with either lzma or xz, you may need to install an extra Python package.
|
||||
|
||||
Python versions prior to 2.6 are not supported. For Python versions 2.6 to 3.2 you need to install the module `backports.lzma`. How to install it depends on your system and how you installed Python. Most Linux distributions should include it as a package named `backports-lzma` (or similar). From version 3.3 onwards, Python already includes the required module.
|
||||
|
||||
## Contact Us
|
||||
|
||||
Questions, comments, rants and raves can be posted to the official fish mailing list at <https://lists.sourceforge.net/lists/listinfo/fish-users> or join us on our IRC channel [#fish at irc.oftc.net](https://webchat.oftc.net/?channels=fish).
|
||||
|
|
|
@ -86,7 +86,7 @@ done
|
|||
# Input is kept as . because we cd to the input directory beforehand
|
||||
# This prevents doxygen from generating "documentation" for intermediate directories
|
||||
DOXYPARAMS=$(cat <<EOF
|
||||
PROJECT_NUMBER=2.0.0
|
||||
PROJECT_NUMBER=$PROJECT_NUMBER
|
||||
INPUT=.
|
||||
OUTPUT_DIRECTORY=$OUTPUTDIR
|
||||
QUIET=YES
|
||||
|
|
10
builtin.cpp
10
builtin.cpp
|
@ -1617,24 +1617,24 @@ static int builtin_echo(parser_t &parser, wchar_t **argv)
|
|||
{
|
||||
case L'n':
|
||||
print_newline = false;
|
||||
break;
|
||||
break;
|
||||
case L'e':
|
||||
interpret_special_chars = true;
|
||||
break;
|
||||
break;
|
||||
case L's':
|
||||
// fish-specific extension,
|
||||
// which we should try to nix
|
||||
print_spaces = false;
|
||||
break;
|
||||
break;
|
||||
case L'E':
|
||||
interpret_special_chars = false;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
invalid_echo_option:
|
||||
invalid_echo_option:
|
||||
break;
|
||||
}
|
||||
argv++;
|
||||
|
|
|
@ -169,7 +169,7 @@ static void write_part(const wchar_t *begin,
|
|||
out.push_back(L'\n');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
|
|
|
@ -423,8 +423,8 @@ static int builtin_complete(parser_t &parser, wchar_t **argv)
|
|||
case 'p':
|
||||
case 'c':
|
||||
{
|
||||
wcstring tmp = woptarg;
|
||||
if (unescape_string(tmp, 1))
|
||||
wcstring tmp;
|
||||
if (unescape_string(woptarg, &tmp, UNESCAPE_SPECIAL))
|
||||
{
|
||||
if (opt=='p')
|
||||
path.push_back(tmp);
|
||||
|
|
|
@ -123,7 +123,7 @@ static void builtin_jobs_print(const job_t *j, int mode, int header)
|
|||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
stdout_buffer.append(_(L"Procces\n"));
|
||||
stdout_buffer.append(_(L"Process\n"));
|
||||
}
|
||||
|
||||
for (p=j->first_process; p; p=p->next)
|
||||
|
|
|
@ -195,11 +195,6 @@ double C_STRTOD(wchar_t const *nptr, wchar_t **endptr)
|
|||
return r;
|
||||
}
|
||||
|
||||
static inline unsigned wchar_t to_uwchar_t(wchar_t ch)
|
||||
{
|
||||
return ch;
|
||||
}
|
||||
|
||||
void builtin_printf_state_t::fatal_error(const wchar_t *fmt, ...)
|
||||
{
|
||||
// Don't error twice
|
||||
|
@ -292,7 +287,7 @@ static T string_to_scalar_type(const wchar_t *s, builtin_printf_state_t *state)
|
|||
T val;
|
||||
if (*s == L'\"' || *s == L'\'')
|
||||
{
|
||||
unsigned wchar_t ch = *++s;
|
||||
wchar_t ch = *++s;
|
||||
val = ch;
|
||||
}
|
||||
else
|
||||
|
@ -632,7 +627,7 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
modify_allowed_format_specifiers(ok, "aAcdeEfFgGiosuxX", true);
|
||||
|
||||
for (;; f++, direc_length++)
|
||||
|
@ -736,8 +731,8 @@ no_more_flag_characters:
|
|||
++f;
|
||||
|
||||
{
|
||||
unsigned wchar_t conversion = *f;
|
||||
if (! ok[conversion])
|
||||
wchar_t conversion = *f;
|
||||
if (conversion > 0xFF || ! ok[conversion])
|
||||
{
|
||||
this->fatal_error(_(L"%.*ls: invalid conversion specification"), (int)(f + 1 - direc_start), direc_start);
|
||||
return 0;
|
||||
|
|
|
@ -698,7 +698,6 @@ static int builtin_set(parser_t &parser, wchar_t **argv)
|
|||
Slice mode
|
||||
*/
|
||||
size_t idx_count, val_count;
|
||||
wcstring_list_t values;
|
||||
std::vector<long> indexes;
|
||||
wcstring_list_t result;
|
||||
|
||||
|
|
974
common.cpp
974
common.cpp
File diff suppressed because it is too large
Load diff
34
common.h
34
common.h
|
@ -59,15 +59,19 @@ typedef std::vector<wcstring> wcstring_list_t;
|
|||
*/
|
||||
#define BYTE_MAX 0xffu
|
||||
|
||||
/**
|
||||
Escape special fish syntax characters like the semicolon
|
||||
*/
|
||||
#define UNESCAPE_SPECIAL 1
|
||||
/* Flags for unescape_string functions */
|
||||
enum
|
||||
{
|
||||
/* Default behavior */
|
||||
UNESCAPE_DEFAULT = 0,
|
||||
|
||||
/**
|
||||
Allow incomplete escape sequences
|
||||
*/
|
||||
#define UNESCAPE_INCOMPLETE 2
|
||||
/* Escape special fish syntax characters like the semicolon */
|
||||
UNESCAPE_SPECIAL = 1 << 0,
|
||||
|
||||
/* Allow incomplete escape sequences */
|
||||
UNESCAPE_INCOMPLETE = 1 << 1
|
||||
};
|
||||
typedef unsigned int unescape_flags_t;
|
||||
|
||||
/* Flags for the escape() and escape_string() functions */
|
||||
enum
|
||||
|
@ -715,16 +719,14 @@ wcstring escape_string(const wcstring &in, escape_flags_t flags);
|
|||
character and a few more into constants which are defined in a
|
||||
private use area of Unicode. This assumes wchar_t is a unicode
|
||||
character set.
|
||||
|
||||
The result must be free()d. The original string is not modified. If
|
||||
an invalid sequence is specified, 0 is returned.
|
||||
|
||||
*/
|
||||
wchar_t *unescape(const wchar_t * in,
|
||||
int escape_special);
|
||||
|
||||
bool unescape_string(wcstring &str,
|
||||
int escape_special);
|
||||
/** Unescapes a string in-place. A true result indicates the string was unescaped, a false result indicates the string was unmodified. */
|
||||
bool unescape_string_in_place(wcstring *str, unescape_flags_t escape_special);
|
||||
|
||||
/** Unescapes a string, returning the unescaped value by reference. On failure, the output is set to an empty string. */
|
||||
bool unescape_string(const wchar_t *input, wcstring *output, unescape_flags_t escape_special);
|
||||
bool unescape_string(const wcstring &input, wcstring *output, unescape_flags_t escape_special);
|
||||
|
||||
|
||||
/**
|
||||
|
|
57
complete.cpp
57
complete.cpp
|
@ -44,6 +44,7 @@
|
|||
#include "parser_keywords.h"
|
||||
#include "wutil.h"
|
||||
#include "path.h"
|
||||
#include "iothread.h"
|
||||
|
||||
/*
|
||||
Completion description strings, mostly for different types of files, such as sockets, block devices, etc.
|
||||
|
@ -341,7 +342,6 @@ class completer_t
|
|||
const completion_request_flags_t flags;
|
||||
const wcstring initial_cmd;
|
||||
std::vector<completion_t> completions;
|
||||
wcstring_list_t commands_to_load;
|
||||
|
||||
/** Table of completions conditions that have already been tested and the corresponding test results */
|
||||
typedef std::map<wcstring, bool> condition_cache_t;
|
||||
|
@ -430,7 +430,7 @@ public:
|
|||
/* Never do command substitution in autosuggestions. Sadly, we also can't yet do job expansion because it's not thread safe. */
|
||||
expand_flags_t result = 0;
|
||||
if (this->type() == COMPLETE_AUTOSUGGEST)
|
||||
result |= EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_JOBS;
|
||||
result |= EXPAND_SKIP_CMDSUBST;
|
||||
|
||||
/* Allow fuzzy matching */
|
||||
if (this->fuzzy())
|
||||
|
@ -438,18 +438,6 @@ public:
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
void get_commands_to_load(wcstring_list_t *lst)
|
||||
{
|
||||
if (lst)
|
||||
lst->insert(lst->end(), commands_to_load.begin(), commands_to_load.end());
|
||||
}
|
||||
|
||||
bool has_commands_to_load() const
|
||||
{
|
||||
return ! commands_to_load.empty();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* Autoloader for completions */
|
||||
|
@ -1350,6 +1338,15 @@ void complete_load(const wcstring &name, bool reload)
|
|||
completion_autoloader.load(name, reload);
|
||||
}
|
||||
|
||||
// Performed on main thread, from background thread. Return type is ignored.
|
||||
static int complete_load_no_reload(wcstring *name)
|
||||
{
|
||||
assert(name != NULL);
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
complete_load(*name, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Find completion for the argument str of command cmd_orig with
|
||||
previous option popt. Insert results into comp_out. Return 0 if file
|
||||
|
@ -1372,14 +1369,15 @@ bool completer_t::complete_param(const wcstring &scmd_orig, const wcstring &spop
|
|||
|
||||
if (this->type() == COMPLETE_DEFAULT)
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
complete_load(cmd, true);
|
||||
}
|
||||
else if (this->type() == COMPLETE_AUTOSUGGEST)
|
||||
{
|
||||
/* Maybe indicate we should try loading this on the main thread */
|
||||
if (! list_contains_string(this->commands_to_load, cmd) && ! completion_autoloader.has_tried_loading(cmd))
|
||||
/* Maybe load this command (on the main thread) */
|
||||
if (! completion_autoloader.has_tried_loading(cmd))
|
||||
{
|
||||
this->commands_to_load.push_back(cmd);
|
||||
iothread_perform_on_main(complete_load_no_reload, &cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1627,7 +1625,7 @@ void completer_t::complete_param_expand(const wcstring &sstr, bool do_file)
|
|||
|
||||
if (expand_string(comp_str,
|
||||
this->completions,
|
||||
flags ) == EXPAND_ERROR)
|
||||
flags) == EXPAND_ERROR)
|
||||
{
|
||||
debug(3, L"Error while expanding string '%ls'", comp_str);
|
||||
}
|
||||
|
@ -1790,7 +1788,7 @@ bool completer_t::try_complete_user(const wcstring &str)
|
|||
return res;
|
||||
}
|
||||
|
||||
void complete(const wcstring &cmd, std::vector<completion_t> &comps, completion_request_flags_t flags, wcstring_list_t *commands_to_load)
|
||||
void complete(const wcstring &cmd, std::vector<completion_t> &comps, completion_request_flags_t flags)
|
||||
{
|
||||
/* Make our completer */
|
||||
completer_t completer(cmd, flags);
|
||||
|
@ -1911,7 +1909,7 @@ void complete(const wcstring &cmd, std::vector<completion_t> &comps, completion_
|
|||
end_loop=1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
|
@ -1982,13 +1980,10 @@ void complete(const wcstring &cmd, std::vector<completion_t> &comps, completion_
|
|||
{
|
||||
bool do_file = false;
|
||||
|
||||
wcstring current_command_unescape = current_command;
|
||||
wcstring prev_token_unescape = prev_token;
|
||||
wcstring current_token_unescape = current_token;
|
||||
|
||||
if (unescape_string(current_command_unescape, 0) &&
|
||||
unescape_string(prev_token_unescape, 0) &&
|
||||
unescape_string(current_token_unescape, UNESCAPE_INCOMPLETE))
|
||||
wcstring current_command_unescape, prev_token_unescape, current_token_unescape;
|
||||
if (unescape_string(current_command, ¤t_command_unescape, UNESCAPE_DEFAULT) &&
|
||||
unescape_string(prev_token, &prev_token_unescape, UNESCAPE_DEFAULT) &&
|
||||
unescape_string(current_token, ¤t_token_unescape, UNESCAPE_INCOMPLETE))
|
||||
{
|
||||
do_file = completer.complete_param(current_command_unescape,
|
||||
prev_token_unescape,
|
||||
|
@ -2002,12 +1997,7 @@ void complete(const wcstring &cmd, std::vector<completion_t> &comps, completion_
|
|||
if (completer.empty())
|
||||
do_file = true;
|
||||
|
||||
/* But if we are planning on loading commands, don't do file completions.
|
||||
See https://github.com/fish-shell/fish-shell/issues/378 */
|
||||
if (commands_to_load != NULL && completer.has_commands_to_load())
|
||||
do_file = false;
|
||||
|
||||
/* And if we're autosuggesting, and the token is empty, don't do file suggestions */
|
||||
/* If we're autosuggesting, and the token is empty, don't do file suggestions */
|
||||
if ((flags & COMPLETION_REQUEST_AUTOSUGGESTION) && current_token_unescape.empty())
|
||||
do_file = false;
|
||||
|
||||
|
@ -2019,7 +2009,6 @@ void complete(const wcstring &cmd, std::vector<completion_t> &comps, completion_
|
|||
}
|
||||
|
||||
comps = completer.get_completions();
|
||||
completer.get_commands_to_load(commands_to_load);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ public:
|
|||
completion_t(const wcstring &comp, const wcstring &desc = L"", string_fuzzy_match_t match = string_fuzzy_match_t(fuzzy_match_exact), int flags_val = 0);
|
||||
completion_t(const completion_t &);
|
||||
completion_t &operator=(const completion_t &);
|
||||
|
||||
|
||||
/* Compare two completions. No operating overlaoding to make this always explicit (there's potentially multiple ways to compare completions). */
|
||||
static bool is_alphabetically_less_than(const completion_t &a, const completion_t &b);
|
||||
static bool is_alphabetically_equal_to(const completion_t &a, const completion_t &b);
|
||||
|
@ -216,14 +216,11 @@ void complete_remove(const wchar_t *cmd,
|
|||
const wchar_t *long_opt);
|
||||
|
||||
|
||||
/** Find all completions of the command cmd, insert them into out. If to_load is
|
||||
* not NULL, append all commands that we would autoload, but did not (presumably
|
||||
* because this is not the main thread)
|
||||
/** Find all completions of the command cmd, insert them into out.
|
||||
*/
|
||||
void complete(const wcstring &cmd,
|
||||
std::vector<completion_t> &comp,
|
||||
completion_request_flags_t flags,
|
||||
wcstring_list_t *to_load = NULL);
|
||||
completion_request_flags_t flags);
|
||||
|
||||
/**
|
||||
Print a list of all current completions into the string.
|
||||
|
|
94
configure.ac
94
configure.ac
|
@ -238,56 +238,24 @@ AS_IF([test "$use_doxygen" != "no"],
|
|||
|
||||
CXXFLAGS="$CXXFLAGS -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64"
|
||||
|
||||
|
||||
# fish does not use exceptions
|
||||
# Disabling exceptions saves about 20% (!) of the compiled code size
|
||||
CXXFLAGS="$CXXFLAGS -fno-exceptions"
|
||||
|
||||
|
||||
#
|
||||
# If we are using gcc, set some flags that increase the odds of the
|
||||
# compiler producing a working binary...
|
||||
# -Wall is there to keep me on my toes
|
||||
#
|
||||
|
||||
if test "$GCC" = yes; then
|
||||
CXXFLAGS="$CXXFLAGS -Wall"
|
||||
|
||||
#
|
||||
# -fno-optimize-sibling-calls seems to work around a bug where
|
||||
# sending a SIGWINCH to fish on NetBSD 3.0 causes fish to exit when
|
||||
# compiled with GCC 3.3.3. This is probably either a compiler bug
|
||||
# or a libc bug, but adding this flag seems to fix things for
|
||||
# now. Long term, the real problem should be tracked down and
|
||||
# truly fixed, at which point we can remove this silly flag. This
|
||||
# bug has been verified to not exist on Linux using GCC 3.3.3.
|
||||
#
|
||||
|
||||
GCC_VERSION=$($CC -dumpversion)
|
||||
GCC_VERSION_MAJOR=$(echo $GCC_VERSION | cut -d'.' -f1)
|
||||
GCC_VERSION_MINOR=$(echo $GCC_VERSION | cut -d'.' -f2)
|
||||
GCC_VERSION_PATCH=$(echo $GCC_VERSION | cut -d'.' -f3)
|
||||
|
||||
if test "$GCC_VERSION_MAJOR" -le 3; then
|
||||
if test 0"$GCC_VERSION_MINOR" -le 3; then
|
||||
if test 0"$GCC_VERSION_PATCH" -le 3; then
|
||||
CXXFLAGS="$CXXFLAGS -fno-optimize-sibling-calls"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# fish does not use exceptions
|
||||
# Disabling exceptions saves about 20% (!) of the compiled code size
|
||||
CXXFLAGS="$CXXFLAGS -fno-exceptions"
|
||||
|
||||
|
||||
#
|
||||
# -Wall is there to keep me on my toes
|
||||
#
|
||||
|
||||
# Some day...
|
||||
CXXFLAGS="$CXXFLAGS -Wall"
|
||||
|
||||
#
|
||||
# This is needed in order to get the really cool backtraces on Linux
|
||||
#
|
||||
|
||||
if test `uname` != "Darwin"; then
|
||||
LDFLAGS_FISH="$LDFLAGS_FISH -rdynamic"
|
||||
fi
|
||||
#
|
||||
# This is needed in order to get the really cool backtraces on Linux
|
||||
#
|
||||
|
||||
if test `uname` != "Darwin"; then
|
||||
LDFLAGS_FISH="$LDFLAGS_FISH -rdynamic"
|
||||
fi
|
||||
|
||||
|
||||
|
@ -475,82 +443,58 @@ AC_DEFINE(
|
|||
#
|
||||
|
||||
# Check for os dependant libraries for all binaries.
|
||||
LIBS_COMMON=$LIBS
|
||||
LIBS=""
|
||||
AC_SEARCH_LIBS( connect, socket, , [AC_MSG_ERROR([Cannot find the socket library, needed to build this package.] )] )
|
||||
AC_SEARCH_LIBS( nanosleep, rt, , [AC_MSG_ERROR([Cannot find the rt library, needed to build this package.] )] )
|
||||
AC_SEARCH_LIBS( pthread_create, pthread, , [AC_MSG_ERROR([Cannot find the pthread library, needed to build this package.] )] )
|
||||
AC_SEARCH_LIBS( setupterm, [ncurses curses], , [AC_MSG_ERROR([Could not find a curses implementation, needed to build fish. If this is Linux, try running 'sudo apt-get install libncurses5-dev' or 'sudo yum install ncurses-devel'])] )
|
||||
AC_SEARCH_LIBS( [nan], [m], [AC_DEFINE( [HAVE_NAN], [1], [Define to 1 if you have the nan function])] )
|
||||
|
||||
if test x$local_gettext != xno; then
|
||||
AC_SEARCH_LIBS( gettext, intl,,)
|
||||
fi
|
||||
|
||||
LIBS_SHARED=$LIBS
|
||||
LIBS=$LIBS_COMMON
|
||||
|
||||
#
|
||||
# Check for libraries needed by fish.
|
||||
#
|
||||
|
||||
LIBS_COMMON=$LIBS
|
||||
LIBS="$LIBS_SHARED"
|
||||
if test x$local_gettext != xno; then
|
||||
AC_SEARCH_LIBS( gettext, intl,,)
|
||||
fi
|
||||
|
||||
# Check for libiconv_open if we can't find iconv_open. Silly OS X does
|
||||
# weird macro magic for the sole purpose of amusing me.
|
||||
AC_SEARCH_LIBS( iconv_open, iconv, , [AC_SEARCH_LIBS( libiconv_open, iconv, , [AC_MSG_ERROR([Could not find an iconv implementation, needed to build fish])] )] )
|
||||
|
||||
LIBS_FISH=$LIBS
|
||||
LIBS=$LIBS_COMMON
|
||||
|
||||
#
|
||||
# Check for libraries needed by fish_indent.
|
||||
#
|
||||
|
||||
LIBS_COMMON=$LIBS
|
||||
LIBS="$LIBS_SHARED"
|
||||
if test x$local_gettext != xno; then
|
||||
AC_SEARCH_LIBS( gettext, intl,,)
|
||||
fi
|
||||
LIBS_FISH_INDENT=$LIBS
|
||||
LIBS=$LIBS_COMMON
|
||||
|
||||
#
|
||||
# Check for libraries needed by fish_pager.
|
||||
#
|
||||
|
||||
LIBS_COMMON=$LIBS
|
||||
LIBS="$LIBS_SHARED"
|
||||
if test x$local_gettext != xno; then
|
||||
AC_SEARCH_LIBS( gettext, intl,,)
|
||||
fi
|
||||
AC_SEARCH_LIBS( iconv_open, iconv, , [AC_SEARCH_LIBS( libiconv_open, iconv, , [AC_MSG_ERROR([Could not find an iconv implementation, needed to build fish])] )] )
|
||||
LIBS_FISH_PAGER=$LIBS
|
||||
LIBS=$LIBS_COMMON
|
||||
|
||||
#
|
||||
# Check for libraries needed by fishd.
|
||||
#
|
||||
|
||||
LIBS_COMMON=$LIBS
|
||||
LIBS="$LIBS_SHARED"
|
||||
if test x$local_gettext != xno; then
|
||||
AC_SEARCH_LIBS( gettext, intl,,)
|
||||
fi
|
||||
AC_SEARCH_LIBS( iconv_open, iconv, , [AC_SEARCH_LIBS( libiconv_open, iconv, , [AC_MSG_ERROR([Could not find an iconv implementation, needed to build fish])] )] )
|
||||
LIBS_FISHD=$LIBS
|
||||
LIBS=$LIBS_COMMON
|
||||
|
||||
#
|
||||
# Check for libraries needed by mimedb.
|
||||
#
|
||||
|
||||
LIBS_COMMON=$LIBS
|
||||
LIBS="$LIBS_SHARED"
|
||||
if test x$local_gettext != xno; then
|
||||
AC_SEARCH_LIBS( gettext, intl,,)
|
||||
fi
|
||||
LIBS_MIMEDB=$LIBS
|
||||
LIBS=$LIBS_COMMON
|
||||
|
||||
|
||||
#
|
||||
|
@ -929,7 +873,7 @@ case $target_os in
|
|||
esac
|
||||
|
||||
# Tell the world what we know
|
||||
AC_CONFIG_FILES([Makefile fish.spec])
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
if test ! x$local_found_posix_switch = xyes; then
|
||||
|
|
|
@ -1139,6 +1139,7 @@ Here are some of the commands available in the editor:
|
|||
- Alt-P adds the string <code>'| less;'</code> to the end of the job under the cursor. The result is that the output of the command will be paged.
|
||||
- Alt-C capitalizes the current word.
|
||||
- Alt-U makes the current word uppercase.
|
||||
- F1 shows the manual page for the current command, if one exists.
|
||||
|
||||
You can change these key bindings using the
|
||||
<a href="commands.html#bind">bind</a> builtin command.
|
||||
|
|
|
@ -20,6 +20,10 @@ The return status of \c source is the return status of the last job to
|
|||
execute. If something goes wrong while opening or reading the file,
|
||||
\c source exits with a non-zero status.
|
||||
|
||||
\c . (a single period) is an alias for the \c source command. The use of \c .
|
||||
is deprecated in favour of \c source, and \c . will be removed in a future
|
||||
version of fish.
|
||||
|
||||
\subsection source-example Example
|
||||
|
||||
<tt>source ~/.config/fish/config.fish</tt> causes fish to re-read its initialization file.
|
||||
|
|
|
@ -721,7 +721,7 @@ function fish_prompt
|
|||
end
|
||||
</pre>
|
||||
|
||||
<p>See the documentation for <a href="docs/current/commands.html#funced">funced</a> and <a href="docs/current/commands.html#funcsave">funcsave</a> for ways to create these files automatically.
|
||||
<p>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.
|
||||
|
||||
<h3>Universal Variables</h2>
|
||||
|
||||
|
@ -740,7 +740,7 @@ vim
|
|||
|
||||
<h3>Ready for more?</h2>
|
||||
|
||||
<p>If you want to learn more about fish, there is <a href="docs/current/">lots of detailed documentation</a>, an <a href="https://lists.sourceforge.net/lists/listinfo/fish-users">official mailing list</a>, the IRC channel <tt>#fish</tt> on <tt>irc.oftc.net</tt>, and the <a href="http://github.com/fish-shell/fish-shell/">github page</a>.
|
||||
<p>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 <tt>#fish</tt> on <tt>irc.oftc.net</tt>, and the <a href="http://github.com/fish-shell/fish-shell/">github page</a>.
|
||||
|
||||
</div>
|
||||
\endhtmlonly
|
||||
|
|
|
@ -123,7 +123,7 @@ static int try_get_socket_once(void)
|
|||
|
||||
free(dir);
|
||||
|
||||
debug(3, L"Connect to socket %s at fd %2", name.c_str(), s);
|
||||
debug(3, L"Connect to socket %s at fd %d", name.c_str(), s);
|
||||
|
||||
struct sockaddr_un local = {};
|
||||
local.sun_family = AF_UNIX;
|
||||
|
@ -132,6 +132,12 @@ static int try_get_socket_once(void)
|
|||
if (connect(s, (struct sockaddr *)&local, sizeof local) == -1)
|
||||
{
|
||||
close(s);
|
||||
|
||||
/* If it fails on first try, it's probably no serious error, but fishd hasn't been launched yet.
|
||||
This happens (at least) on the first concurrent session. */
|
||||
if (get_socket_count > 1)
|
||||
wperror(L"connect");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -398,6 +398,9 @@ start_conversion:
|
|||
{
|
||||
debug(0, L"%d %d", in_len, out_len);
|
||||
debug(0, L"Error while converting from to string");
|
||||
|
||||
/* Terminate the output string. */
|
||||
free(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -598,16 +601,13 @@ static void parse_message(wchar_t *msg,
|
|||
tmp = wcschr(name, L':');
|
||||
if (tmp)
|
||||
{
|
||||
wchar_t *val;
|
||||
const wcstring key(name, tmp - name);
|
||||
|
||||
val = tmp+1;
|
||||
val = unescape(val, 0);
|
||||
|
||||
if (val != NULL)
|
||||
env_universal_common_set(key.c_str(), val, exportv);
|
||||
|
||||
free(val);
|
||||
wcstring val;
|
||||
if (unescape_string(tmp + 1, &val, 0))
|
||||
{
|
||||
env_universal_common_set(key.c_str(), val.c_str(), exportv);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
24
exec.cpp
24
exec.cpp
|
@ -188,7 +188,7 @@ void print_open_fds(void)
|
|||
{
|
||||
if (open_fds.at(i))
|
||||
{
|
||||
fprintf(stderr, "fd %lu\n", i);
|
||||
fprintf(stderr, "fd %lu\n", (unsigned long) i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -551,7 +551,7 @@ static bool can_use_posix_spawn_for_job(const job_t *job, const process_t *proce
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Now see if we have a redirection involving a file. The only one we allow is /dev/null, which we assume will not fail. */
|
||||
bool result = true;
|
||||
if (chain_contains_redirection_to_real_file(job->block_io_chain()) || chain_contains_redirection_to_real_file(process->io_chain()))
|
||||
|
@ -790,11 +790,11 @@ void exec_job(parser_t &parser, job_t *j)
|
|||
echo alpha | cat < beta.txt
|
||||
|
||||
Should cat output alpha or beta? bash and ksh output 'beta', tcsh gets it right and complains about ambiguity, and zsh outputs both (!). No shells appear to output 'alpha', so we match bash here. That would mean putting the pipe first, so that it gets trumped by the file redirection.
|
||||
|
||||
|
||||
However, eval does this:
|
||||
|
||||
|
||||
echo "begin; $argv "\n" ;end eval2_inner <&3 3<&-" | source 3<&0
|
||||
|
||||
|
||||
which depends on the redirection being evaluated before the pipe. So the write end of the pipe comes first, the read pipe of the pipe comes last. See issue #966.
|
||||
*/
|
||||
|
||||
|
@ -811,7 +811,7 @@ void exec_job(parser_t &parser, job_t *j)
|
|||
|
||||
/* The explicit IO redirections associated with the process */
|
||||
process_net_io_chain.append(p->io_chain());
|
||||
|
||||
|
||||
/* Read pipe goes last */
|
||||
if (p != j->first_process)
|
||||
{
|
||||
|
@ -820,7 +820,7 @@ void exec_job(parser_t &parser, job_t *j)
|
|||
pipe_read->pipe_fd[0] = pipe_current_read;
|
||||
process_net_io_chain.push_back(pipe_read);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
This call is used so the global environment variable array
|
||||
|
@ -1241,16 +1241,16 @@ void exec_job(parser_t &parser, job_t *j)
|
|||
forking is expensive, fish tries to avoid it when
|
||||
possible.
|
||||
*/
|
||||
|
||||
|
||||
bool fork_was_skipped = false;
|
||||
|
||||
|
||||
const shared_ptr<io_data_t> stdout_io = process_net_io_chain.get_io_for_fd(STDOUT_FILENO);
|
||||
const shared_ptr<io_data_t> stderr_io = process_net_io_chain.get_io_for_fd(STDERR_FILENO);
|
||||
|
||||
|
||||
/* If we are outputting to a file, we have to actually do it, even if we have no output, so that we can truncate the file. Does not apply to /dev/null. */
|
||||
bool must_fork = redirection_is_to_real_file(stdout_io.get()) || redirection_is_to_real_file(stderr_io.get());
|
||||
if (! must_fork)
|
||||
{
|
||||
{
|
||||
if (p->next == NULL)
|
||||
{
|
||||
const bool stdout_is_to_buffer = stdout_io && stdout_io->io_mode == IO_BUFFER;
|
||||
|
@ -1299,7 +1299,7 @@ void exec_job(parser_t &parser, job_t *j)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (fork_was_skipped)
|
||||
{
|
||||
|
|
337
expand.cpp
337
expand.cpp
|
@ -49,6 +49,7 @@ parameter expansion.
|
|||
#include "signal.h"
|
||||
#include "tokenizer.h"
|
||||
#include "complete.h"
|
||||
#include "iothread.h"
|
||||
|
||||
#include "parse_util.h"
|
||||
|
||||
|
@ -560,6 +561,166 @@ std::vector<wcstring> expand_get_all_process_names(void)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Helper function to do a job search. */
|
||||
struct find_job_data_t
|
||||
{
|
||||
const wchar_t *proc; /* The process to search for - possibly numeric, possibly a name */
|
||||
expand_flags_t flags;
|
||||
std::vector<completion_t> *completions;
|
||||
};
|
||||
|
||||
/* The following function is invoked on the main thread, because the job list is not thread safe. It should search the job list for something matching the given proc, and then return 1 to stop the search, 0 to continue it */
|
||||
static int find_job(const struct find_job_data_t *info)
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
|
||||
const wchar_t * const proc = info->proc;
|
||||
const expand_flags_t flags = info->flags;
|
||||
std::vector<completion_t> &completions = *info->completions;
|
||||
|
||||
const job_t *j;
|
||||
int found = 0;
|
||||
// do the empty param check first, because an empty string passes our 'numeric' check
|
||||
if (wcslen(proc)==0)
|
||||
{
|
||||
/*
|
||||
This is an empty job expansion: '%'
|
||||
It expands to the last job backgrounded.
|
||||
*/
|
||||
job_iterator_t jobs;
|
||||
while ((j = jobs.next()))
|
||||
{
|
||||
if (!j->command_is_empty())
|
||||
{
|
||||
append_completion(completions, to_string<long>(j->pgid));
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
You don't *really* want to flip a coin between killing
|
||||
the last process backgrounded and all processes, do you?
|
||||
Let's not try other match methods with the solo '%' syntax.
|
||||
*/
|
||||
found = 1;
|
||||
}
|
||||
else if (iswnumeric(proc))
|
||||
{
|
||||
/*
|
||||
This is a numeric job string, like '%2'
|
||||
*/
|
||||
|
||||
if (flags & ACCEPT_INCOMPLETE)
|
||||
{
|
||||
job_iterator_t jobs;
|
||||
while ((j = jobs.next()))
|
||||
{
|
||||
wchar_t jid[16];
|
||||
if (j->command_is_empty())
|
||||
continue;
|
||||
|
||||
swprintf(jid, 16, L"%d", j->job_id);
|
||||
|
||||
if (wcsncmp(proc, jid, wcslen(proc))==0)
|
||||
{
|
||||
wcstring desc_buff = format_string(COMPLETE_JOB_DESC_VAL, j->command_wcstr());
|
||||
append_completion(completions,
|
||||
jid+wcslen(proc),
|
||||
desc_buff,
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int jid;
|
||||
wchar_t *end;
|
||||
|
||||
errno = 0;
|
||||
jid = fish_wcstoi(proc, &end, 10);
|
||||
if (jid > 0 && !errno && !*end)
|
||||
{
|
||||
j = job_get(jid);
|
||||
if ((j != 0) && (j->command_wcstr() != 0) && (!j->command_is_empty()))
|
||||
{
|
||||
append_completion(completions, to_string<long>(j->pgid));
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Stop here so you can't match a random process name
|
||||
when you're just trying to use job control.
|
||||
*/
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (! found)
|
||||
{
|
||||
job_iterator_t jobs;
|
||||
while ((j = jobs.next()))
|
||||
{
|
||||
|
||||
if (j->command_is_empty())
|
||||
continue;
|
||||
|
||||
size_t offset;
|
||||
if (match_pid(j->command(), proc, flags, &offset))
|
||||
{
|
||||
if (flags & ACCEPT_INCOMPLETE)
|
||||
{
|
||||
append_completion(completions,
|
||||
j->command_wcstr() + offset + wcslen(proc),
|
||||
COMPLETE_JOB_DESC,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
append_completion(completions, to_string<long>(j->pgid));
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! found)
|
||||
{
|
||||
jobs.reset();
|
||||
while ((j = jobs.next()))
|
||||
{
|
||||
process_t *p;
|
||||
if (j->command_is_empty())
|
||||
continue;
|
||||
for (p=j->first_process; p; p=p->next)
|
||||
{
|
||||
if (p->actual_cmd.empty())
|
||||
continue;
|
||||
|
||||
size_t offset;
|
||||
if (match_pid(p->actual_cmd, proc, flags, &offset))
|
||||
{
|
||||
if (flags & ACCEPT_INCOMPLETE)
|
||||
{
|
||||
append_completion(completions,
|
||||
wcstring(p->actual_cmd, offset + wcslen(proc)),
|
||||
COMPLETE_CHILD_PROCESS_DESC,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
append_completion(completions,
|
||||
to_string<long>(p->pid),
|
||||
L"",
|
||||
0);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Searches for a job with the specified job id, or a job or process
|
||||
which has the string \c proc as a prefix of its commandline.
|
||||
|
@ -582,146 +743,8 @@ static int find_process(const wchar_t *proc,
|
|||
|
||||
if (!(flags & EXPAND_SKIP_JOBS))
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
const job_t *j;
|
||||
|
||||
// do the empty param check first, because an empty string passes our 'numeric' check
|
||||
if (wcslen(proc)==0)
|
||||
{
|
||||
/*
|
||||
This is an empty job expansion: '%'
|
||||
It expands to the last job backgrounded.
|
||||
*/
|
||||
job_iterator_t jobs;
|
||||
while ((j = jobs.next()))
|
||||
{
|
||||
if (!j->command_is_empty())
|
||||
{
|
||||
append_completion(out, to_string<long>(j->pgid));
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
You don't *really* want to flip a coin between killing
|
||||
the last process backgrounded and all processes, do you?
|
||||
Let's not try other match methods with the solo '%' syntax.
|
||||
*/
|
||||
found = 1;
|
||||
}
|
||||
else if (iswnumeric(proc))
|
||||
{
|
||||
/*
|
||||
This is a numeric job string, like '%2'
|
||||
*/
|
||||
|
||||
if (flags & ACCEPT_INCOMPLETE)
|
||||
{
|
||||
job_iterator_t jobs;
|
||||
while ((j = jobs.next()))
|
||||
{
|
||||
wchar_t jid[16];
|
||||
if (j->command_is_empty())
|
||||
continue;
|
||||
|
||||
swprintf(jid, 16, L"%d", j->job_id);
|
||||
|
||||
if (wcsncmp(proc, jid, wcslen(proc))==0)
|
||||
{
|
||||
wcstring desc_buff = format_string(COMPLETE_JOB_DESC_VAL, j->command_wcstr());
|
||||
append_completion(out,
|
||||
jid+wcslen(proc),
|
||||
desc_buff,
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int jid;
|
||||
wchar_t *end;
|
||||
|
||||
errno = 0;
|
||||
jid = fish_wcstoi(proc, &end, 10);
|
||||
if (jid > 0 && !errno && !*end)
|
||||
{
|
||||
j = job_get(jid);
|
||||
if ((j != 0) && (j->command_wcstr() != 0) && (!j->command_is_empty()))
|
||||
{
|
||||
append_completion(out, to_string<long>(j->pgid));
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Stop here so you can't match a random process name
|
||||
when you're just trying to use job control.
|
||||
*/
|
||||
found = 1;
|
||||
}
|
||||
if (found)
|
||||
return 1;
|
||||
|
||||
job_iterator_t jobs;
|
||||
while ((j = jobs.next()))
|
||||
{
|
||||
|
||||
if (j->command_is_empty())
|
||||
continue;
|
||||
|
||||
size_t offset;
|
||||
if (match_pid(j->command(), proc, flags, &offset))
|
||||
{
|
||||
if (flags & ACCEPT_INCOMPLETE)
|
||||
{
|
||||
append_completion(out,
|
||||
j->command_wcstr() + offset + wcslen(proc),
|
||||
COMPLETE_JOB_DESC,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
append_completion(out, to_string<long>(j->pgid));
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
jobs.reset();
|
||||
while ((j = jobs.next()))
|
||||
{
|
||||
process_t *p;
|
||||
if (j->command_is_empty())
|
||||
continue;
|
||||
for (p=j->first_process; p; p=p->next)
|
||||
{
|
||||
if (p->actual_cmd.empty())
|
||||
continue;
|
||||
|
||||
size_t offset;
|
||||
if (match_pid(p->actual_cmd, proc, flags, &offset))
|
||||
{
|
||||
if (flags & ACCEPT_INCOMPLETE)
|
||||
{
|
||||
append_completion(out,
|
||||
wcstring(p->actual_cmd, offset + wcslen(proc)),
|
||||
COMPLETE_CHILD_PROCESS_DESC,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
append_completion(out,
|
||||
to_string<long>(p->pid),
|
||||
L"",
|
||||
0);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const struct find_job_data_t data = {proc, flags, &out};
|
||||
found = iothread_perform_on_main(find_job, &data);
|
||||
|
||||
if (found)
|
||||
{
|
||||
|
@ -828,7 +851,7 @@ static int expand_pid(const wcstring &instr_with_sep,
|
|||
}
|
||||
|
||||
|
||||
void expand_variable_error(parser_t &parser, const wchar_t *token, size_t token_pos, int error_pos)
|
||||
void expand_variable_error(parser_t &parser, const wcstring &token, size_t token_pos, int error_pos)
|
||||
{
|
||||
size_t stop_pos = token_pos+1;
|
||||
|
||||
|
@ -836,7 +859,7 @@ void expand_variable_error(parser_t &parser, const wchar_t *token, size_t token_
|
|||
{
|
||||
case BRACKET_BEGIN:
|
||||
{
|
||||
wchar_t *cpy = wcsdup(token);
|
||||
wchar_t *cpy = wcsdup(token.c_str());
|
||||
*(cpy+token_pos)=0;
|
||||
wchar_t *name = &cpy[stop_pos+1];
|
||||
wchar_t *end = wcschr(name, BRACKET_END);
|
||||
|
@ -1465,26 +1488,6 @@ static int expand_cmdsubst(parser_t &parser, const wcstring &input, std::vector<
|
|||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
Wrapper around unescape funtion. Issues an error() on failiure.
|
||||
*/
|
||||
__attribute__((unused))
|
||||
static wchar_t *expand_unescape(parser_t &parser, const wchar_t * in, int escape_special)
|
||||
{
|
||||
wchar_t *res = unescape(in, escape_special);
|
||||
if (!res)
|
||||
parser.error(SYNTAX_ERROR, -1, L"Unexpected end of string");
|
||||
return res;
|
||||
}
|
||||
|
||||
static wcstring expand_unescape_string(const wcstring &in, int escape_special)
|
||||
{
|
||||
wcstring tmp = in;
|
||||
unescape_string(tmp, escape_special);
|
||||
/* Need to detect error here */
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* Given that input[0] is HOME_DIRECTORY or tilde (ugh), return the user's name. Return the empty string if it is just a tilde. Also return by reference the index of the first character of the remaining part of the string (e.g. the subsequent slash) */
|
||||
static wcstring get_home_directory_name(const wcstring &input, size_t *out_tail_idx)
|
||||
{
|
||||
|
@ -1669,8 +1672,8 @@ int expand_string(const wcstring &input, std::vector<completion_t> &output, expa
|
|||
expand_string to expand incomplete strings from the
|
||||
commandline.
|
||||
*/
|
||||
int unescape_flags = UNESCAPE_SPECIAL | UNESCAPE_INCOMPLETE;
|
||||
wcstring next = expand_unescape_string(in->at(i).completion, unescape_flags);
|
||||
wcstring next;
|
||||
unescape_string(in->at(i).completion, &next, UNESCAPE_SPECIAL | UNESCAPE_INCOMPLETE);
|
||||
|
||||
if (EXPAND_SKIP_VARIABLES & flags)
|
||||
{
|
||||
|
@ -1752,15 +1755,15 @@ int expand_string(const wcstring &input, std::vector<completion_t> &output, expa
|
|||
|
||||
remove_internal_separator(next_str, (EXPAND_SKIP_WILDCARDS & flags) ? true : false);
|
||||
const wchar_t *next = next_str.c_str();
|
||||
|
||||
|
||||
const bool has_wildcard = wildcard_has(next, 1);
|
||||
|
||||
|
||||
if (has_wildcard && (flags & EXECUTABLES_ONLY))
|
||||
{
|
||||
// Don't do wildcard expansion for executables. See #785. So do nothing here.
|
||||
}
|
||||
else if (((flags & ACCEPT_INCOMPLETE) && (!(flags & EXPAND_SKIP_WILDCARDS))) ||
|
||||
has_wildcard)
|
||||
has_wildcard)
|
||||
{
|
||||
const wchar_t *start, *rest;
|
||||
|
||||
|
|
2
expand.h
2
expand.h
|
@ -199,7 +199,7 @@ int expand_is_clean(const wchar_t *in);
|
|||
\param token_pos The position where the expansion begins
|
||||
\param error_pos The position on the line to report to the error function.
|
||||
*/
|
||||
void expand_variable_error(parser_t &parser, const wchar_t *token, size_t token_pos, int error_pos);
|
||||
void expand_variable_error(parser_t &parser, const wcstring &token, size_t token_pos, int error_pos);
|
||||
|
||||
/**
|
||||
Testing function for getting all process names.
|
||||
|
|
|
@ -98,8 +98,6 @@ char *tparm_solaris_kludge(char *str, ...)
|
|||
|| (enter_reverse_mode && ! strcmp(str, enter_reverse_mode))
|
||||
|| (enter_shadow_mode && ! strcmp(str, enter_shadow_mode))
|
||||
|| (exit_shadow_mode && ! strcmp(str, exit_shadow_mode))
|
||||
|| (enter_standout_mode && ! strcmp(str, enter_standout_mode))
|
||||
|| (exit_standout_mode && ! strcmp(str, exit_standout_mode))
|
||||
|| (enter_secure_mode && ! strcmp(str, enter_secure_mode))
|
||||
|| (enter_bold_mode && ! strcmp(str, enter_bold_mode)))
|
||||
{
|
||||
|
@ -1508,7 +1506,7 @@ static int mk_wcswidth(const wchar_t *pwcs, size_t n)
|
|||
{
|
||||
if (pwcs[i] == L'\0')
|
||||
break;
|
||||
|
||||
|
||||
int w = mk_wcwidth(pwcs[i]);
|
||||
if (w < 0)
|
||||
{
|
||||
|
|
34
fish.cpp
34
fish.cpp
|
@ -189,7 +189,8 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
|
|||
paths.bin = base_path + L"/bin";
|
||||
|
||||
struct stat buf;
|
||||
if (0 == wstat(paths.data, &buf) && 0 == wstat(paths.sysconf, &buf))
|
||||
if (0 == wstat(paths.data, &buf) && 0 == wstat(paths.sysconf, &buf) &&
|
||||
0 == wstat(paths.doc, &buf))
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
|
@ -202,7 +203,7 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
|
|||
/* Fall back to what got compiled in. */
|
||||
paths.data = L"" DATADIR "/fish";
|
||||
paths.sysconf = L"" SYSCONFDIR "/fish";
|
||||
paths.doc = L"" DATADIR "/doc/fish";
|
||||
paths.doc = L"" DOCDIR;
|
||||
paths.bin = L"" BINDIR;
|
||||
|
||||
done = true;
|
||||
|
@ -365,18 +366,15 @@ static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *out_c
|
|||
|
||||
is_login |= (strcmp(argv[0], "-fish") == 0);
|
||||
|
||||
/*
|
||||
We are an interactive session if we have not been given an
|
||||
explicit command to execute, _and_ stdin is a tty.
|
||||
*/
|
||||
is_interactive_session &= ! has_cmd;
|
||||
is_interactive_session &= (my_optind == argc);
|
||||
is_interactive_session &= isatty(STDIN_FILENO);
|
||||
|
||||
/*
|
||||
We are also an interactive session if we have are forced-
|
||||
*/
|
||||
is_interactive_session |= force_interactive;
|
||||
/* We are an interactive session if we are either forced, or have not been given an explicit command to execute and stdin is a tty. */
|
||||
if (force_interactive)
|
||||
{
|
||||
is_interactive_session = true;
|
||||
}
|
||||
else if (is_interactive_session)
|
||||
{
|
||||
is_interactive_session = ! has_cmd && (my_optind == argc) && isatty(STDIN_FILENO);
|
||||
}
|
||||
|
||||
return my_optind;
|
||||
}
|
||||
|
@ -389,7 +387,6 @@ int main(int argc, char **argv)
|
|||
|
||||
set_main_thread();
|
||||
setup_fork_guards();
|
||||
save_term_foreground_process_group();
|
||||
|
||||
wsetlocale(LC_ALL, L"");
|
||||
is_interactive_session=1;
|
||||
|
@ -410,6 +407,12 @@ int main(int argc, char **argv)
|
|||
no_exec = 0;
|
||||
}
|
||||
|
||||
/* Only save (and therefore restore) the fg process group if we are interactive. See #197, #1002 */
|
||||
if (is_interactive_session)
|
||||
{
|
||||
save_term_foreground_process_group();
|
||||
}
|
||||
|
||||
const struct config_paths_t paths = determine_config_directory_paths(argv[0]);
|
||||
|
||||
proc_init();
|
||||
|
@ -511,6 +514,7 @@ int main(int argc, char **argv)
|
|||
|
||||
proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, getpid(), res);
|
||||
|
||||
restore_term_mode();
|
||||
restore_term_foreground_process_group();
|
||||
history_destroy();
|
||||
proc_destroy();
|
||||
|
|
221
fish.spec.in
221
fish.spec.in
|
@ -1,221 +0,0 @@
|
|||
Summary: A friendly interactive shell
|
||||
Name: @PACKAGE_NAME@
|
||||
|
||||
Version: @PACKAGE_VERSION@
|
||||
Release: 0%{?dist}
|
||||
|
||||
License: GPL
|
||||
Group: System Environment/Shells
|
||||
URL: http://fishshell.com/
|
||||
|
||||
Source0: http://ridiculousfish.com/shell/files/%{version}/%{name}-%{version}.tar.bz2
|
||||
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildRequires: ncurses-devel gettext groff
|
||||
|
||||
|
||||
# Locate correct build time-dependencies for providing X headers
|
||||
%if "%fedora" >= "5"
|
||||
|
||||
# Modern Fedora version, has modular X.org
|
||||
BuildRequires: xorg-x11-proto-devel libX11-devel libXt-devel libXext-devel
|
||||
|
||||
%endif
|
||||
|
||||
%if "%fedora" < "5"
|
||||
%if "%fedora" >= "3"
|
||||
|
||||
# Semi-old Fedora version, has non-modular X.org
|
||||
BuildRequires: xorg-x11-devel
|
||||
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora}
|
||||
%if "%fedora" < "3"
|
||||
|
||||
# Ancient Fedora version, has XFree86
|
||||
BuildRequires: XFree86-devel
|
||||
|
||||
%endif
|
||||
%else
|
||||
|
||||
# The %fedora variable has not been correctly defined, or this is is
|
||||
# not a Fedora system, try guessing BuildRequires by looking at the
|
||||
# directory structure
|
||||
%define xinclude /usr%(if [ -d /usr/X11R6/include ]; then echo /X11R6; fi)/include
|
||||
BuildRequires: %{xinclude}/X11/StringDefs.h, %{xinclude}/X11/Xlib.h
|
||||
BuildRequires: %{xinclude}/X11/Intrinsic.h, %{xinclude}/X11/Xatom.h
|
||||
|
||||
%endif
|
||||
|
||||
|
||||
%description
|
||||
|
||||
fish is a shell geared towards interactive use. Its features are
|
||||
focused on user friendliness and discoverability. The language syntax
|
||||
is simple but incompatible with other shell languages.
|
||||
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
|
||||
|
||||
|
||||
%build
|
||||
# The docdir argument is to make the name of the cosumantation
|
||||
# directory 'fish-VERSION', instead of the default, which is simply
|
||||
# 'fish'.
|
||||
%configure docdir=%_datadir/doc/%{name}-%{version}
|
||||
make %{?_smp_mflags}
|
||||
|
||||
|
||||
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
make install DESTDIR="$RPM_BUILD_ROOT"
|
||||
|
||||
# Find translation files
|
||||
%find_lang %{name}.\*
|
||||
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
|
||||
|
||||
|
||||
%post
|
||||
# Add fish to the list of allowed shells in /etc/shells
|
||||
if ! grep %_bindir/fish %_sysconfdir/shells >/dev/null; then
|
||||
echo %_bindir/fish >>%_sysconfdir/shells
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
%postun
|
||||
# Remove fish from the list of allowed shells in /etc/shells
|
||||
if [ "$1" = 0 ]; then
|
||||
grep -v %_bindir/fish %_sysconfdir/shells >%_sysconfdir/fish.tmp
|
||||
mv %_sysconfdir/fish.tmp %_sysconfdir/shells
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
%files -f %{name}.\*.lang
|
||||
|
||||
%defattr(-,root,root,-)
|
||||
|
||||
# The documentation directory
|
||||
%doc %_datadir/doc/%{name}-%{version}
|
||||
|
||||
# man files
|
||||
%_mandir/man1/fish.1*
|
||||
%_mandir/man1/fish_pager.1*
|
||||
%_mandir/man1/fish_indent.1*
|
||||
%_mandir/man1/fishd.1*
|
||||
%_mandir/man1/mimedb.1*
|
||||
%_mandir/man1/set_color.1*
|
||||
|
||||
# The program binaries
|
||||
%attr(0755,root,root) %_bindir/fish
|
||||
%attr(0755,root,root) %_bindir/fish_indent
|
||||
%attr(0755,root,root) %_bindir/fish_pager
|
||||
%attr(0755,root,root) %_bindir/fishd
|
||||
%attr(0755,root,root) %_bindir/mimedb
|
||||
%attr(0755,root,root) %_bindir/set_color
|
||||
|
||||
# Configuration files
|
||||
%config %_sysconfdir/fish/config.fish
|
||||
%dir %_sysconfdir/fish
|
||||
|
||||
# Non-configuration initialization files
|
||||
%dir %_datadir/fish
|
||||
%_datadir/fish/config.fish
|
||||
|
||||
# Program specific tab-completions
|
||||
%dir %_datadir/fish/completions
|
||||
%_datadir/fish/completions/*.fish
|
||||
|
||||
# Dynamically loaded shellscript functions
|
||||
%dir %_datadir/fish/functions
|
||||
%_datadir/fish/functions/*.fish
|
||||
|
||||
# Documentation for builtins and shellscript functions
|
||||
%dir %_datadir/fish/man
|
||||
%_datadir/fish/man/*.1
|
||||
|
||||
|
||||
|
||||
%changelog
|
||||
* Sat Apr 21 2007 Axel Liljencrantz<axel@liljencrantz.se> 1.23.0-0
|
||||
- Add fish_indent command
|
||||
|
||||
* Thu Feb 8 2007 Axel Liljencrantz<axel@liljencrantz.se> 1.22.3-0
|
||||
- Tell rpm about the help pages in %_datadir/fish/man/
|
||||
|
||||
* Sat Oct 14 2006 Axel Liljencrantz<axel@liljencrantz.se> 1.22.0-0
|
||||
- Update names of various configuration files
|
||||
|
||||
* Fri Aug 4 2006 Axel Liljencrantz<axel@liljencrantz.se> 1.21.10-4
|
||||
- Add better translation finding code from fedora spec to main spec. Thank you to Michael Schwendt.
|
||||
- Add missing dependency libXext-devel.
|
||||
- Remove one nesting level from dependency checking code.
|
||||
|
||||
* Tue Aug 1 2006 Axel Liljencrantz<axel@liljencrantz.se> 1.21.10-1
|
||||
- Improved the dependency check for X headers. Thank you to Michael Schwendt for pointers on how to do this
|
||||
|
||||
* Mon Jul 31 2006 Axel Liljencrantz<axel@liljencrantz.se> 1.21.10-1
|
||||
- Fixed spelling and punctuation as a per patch from Paul Howarth
|
||||
- Fixed dependencies as per patch from Paul Howarth
|
||||
|
||||
* Tue Nov 29 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.17.0-0
|
||||
- 1.17.0
|
||||
|
||||
* Sat Sep 24 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.14.0-0
|
||||
- 1.14.0
|
||||
|
||||
* Mon Sep 12 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.13.4-0
|
||||
- 1.13.4
|
||||
|
||||
* Wed Sep 07 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.13.3-0
|
||||
- 1.13.3
|
||||
|
||||
* Tue Sep 06 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.13.2-0
|
||||
- 1.13.2
|
||||
|
||||
* Fri Aug 30 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.13.1-0
|
||||
- 1.13.1
|
||||
|
||||
* Sun Aug 28 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.13.0-0
|
||||
- 1.13.0
|
||||
|
||||
* Sat Aug 13 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.13.0-0
|
||||
- Add completions subdirectory
|
||||
|
||||
* Thu Jul 28 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.12.1-0
|
||||
- 1.12.1
|
||||
|
||||
* Fri Jul 15 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.12.0-1
|
||||
- 1.12.0
|
||||
|
||||
* Thu Jun 30 2005 Michael Schwendt <mschwendt@users.sf.net> 1.11.1-9
|
||||
- Set CFLAGS the proper way
|
||||
|
||||
* Thu Jun 30 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.11.1-8
|
||||
- Fix revision number in changelog
|
||||
|
||||
* Wed Jun 29 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.11.1-7
|
||||
- Send post-script output to /dev/null
|
||||
|
||||
* Wed Jun 29 2005 Axel Liljencrantz <axel@liljencrantz.se> 1.11.1-6
|
||||
- Add changelog section to spec file
|
||||
- Add macros to source tags
|
||||
- Add smp_mflags to 'make all'
|
||||
- Fix typo in post install scriptlet test
|
||||
- Set CFLAGS from spec file
|
|
@ -1190,6 +1190,7 @@
|
|||
"DATADIR=L\\\"/usr/local/share\\\"",
|
||||
"SYSCONFDIR=L\\\"/usr/local/etc\\\"",
|
||||
"BINDIR=L\\\"/usr/local/bin\\\"",
|
||||
"DOCDIR=L\\\"/usr/local/share/doc\\\"",
|
||||
"FISH_BUILD_VERSION=\\\"2.1.0\\\"",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
|
@ -1342,6 +1343,7 @@
|
|||
"DATADIR=L\\\"/usr/local/share\\\"",
|
||||
"SYSCONFDIR=L\\\"/usr/local/etc\\\"",
|
||||
"BINDIR=L\\\"/usr/local/bin\\\"",
|
||||
"DOCDIR=L\\\"/usr/local/share/doc\\\"",
|
||||
"FISH_BUILD_VERSION=\\\"2.1.0\\\"",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
|
@ -1370,6 +1372,7 @@
|
|||
"DATADIR=L\\\"/usr/local/share\\\"",
|
||||
"SYSCONFDIR=L\\\"/usr/local/etc\\\"",
|
||||
"BINDIR=L\\\"/usr/local/bin\\\"",
|
||||
"DOCDIR=L\\\"/usr/local/share/doc\\\"",
|
||||
"FISH_BUILD_VERSION=\\\"2.1.0\\\"",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
|
|
|
@ -106,8 +106,8 @@ static int indent(wcstring &out, const wcstring &in, int flags)
|
|||
int next_indent = indent;
|
||||
is_command = 0;
|
||||
|
||||
wcstring unesc = last;
|
||||
unescape_string(unesc, UNESCAPE_SPECIAL);
|
||||
wcstring unesc;
|
||||
unescape_string(last, &unesc, UNESCAPE_SPECIAL);
|
||||
|
||||
if (parser_keywords_is_block(unesc))
|
||||
{
|
||||
|
|
|
@ -1146,7 +1146,7 @@ static void read_array(FILE* file, wcstring_list_t &comp)
|
|||
{
|
||||
buffer.push_back(0);
|
||||
wcstring wcs = str2wcstring(&buffer.at(0));
|
||||
if (unescape_string(wcs, false))
|
||||
if (unescape_string_in_place(&wcs, false))
|
||||
{
|
||||
comp.push_back(wcs);
|
||||
}
|
||||
|
|
149
fish_tests.cpp
149
fish_tests.cpp
|
@ -65,8 +65,7 @@
|
|||
/**
|
||||
The number of tests to run
|
||||
*/
|
||||
//#define ESCAPE_TEST_COUNT 1000000
|
||||
#define ESCAPE_TEST_COUNT 10000
|
||||
#define ESCAPE_TEST_COUNT 100000
|
||||
/**
|
||||
The average length of strings to unescape
|
||||
*/
|
||||
|
@ -118,45 +117,81 @@ static void err(const wchar_t *blah, ...)
|
|||
wprintf(L"\n");
|
||||
}
|
||||
|
||||
/* Test sane escapes */
|
||||
static void test_unescape_sane()
|
||||
{
|
||||
const struct test_t {const wchar_t * input; const wchar_t * expected;} tests[] =
|
||||
{
|
||||
{L"abcd", L"abcd"},
|
||||
{L"'abcd'", L"abcd"},
|
||||
{L"'abcd\\n'", L"abcd\\n"},
|
||||
{L"\"abcd\\n\"", L"abcd\\n"},
|
||||
{L"\"abcd\\n\"", L"abcd\\n"},
|
||||
{L"\\143", L"c"},
|
||||
{L"'\\143'", L"\\143"},
|
||||
{L"\\n", L"\n"} // \n normally becomes newline
|
||||
};
|
||||
wcstring output;
|
||||
for (size_t i=0; i < sizeof tests / sizeof *tests; i++)
|
||||
{
|
||||
bool ret = unescape_string(tests[i].input, &output, UNESCAPE_DEFAULT);
|
||||
if (! ret)
|
||||
{
|
||||
err(L"Failed to unescape '%ls'\n", tests[i].input);
|
||||
}
|
||||
else if (output != tests[i].expected)
|
||||
{
|
||||
err(L"In unescaping '%ls', expected '%ls' but got '%ls'\n", tests[i].input, tests[i].expected, output.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// test for overflow
|
||||
if (unescape_string(L"echo \\UFFFFFF", &output, UNESCAPE_DEFAULT))
|
||||
{
|
||||
err(L"Should not have been able to unescape \\UFFFFFF\n");
|
||||
}
|
||||
if (unescape_string(L"echo \\U110000", &output, UNESCAPE_DEFAULT))
|
||||
{
|
||||
err(L"Should not have been able to unescape \\U110000\n");
|
||||
}
|
||||
if (! unescape_string(L"echo \\U10FFFF", &output, UNESCAPE_DEFAULT))
|
||||
{
|
||||
err(L"Should have been able to unescape \\U10FFFF\n");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Test the escaping/unescaping code by escaping/unescaping random
|
||||
strings and verifying that the original string comes back.
|
||||
*/
|
||||
static void test_escape()
|
||||
|
||||
static void test_escape_crazy()
|
||||
{
|
||||
int i;
|
||||
wcstring sb;
|
||||
|
||||
say(L"Testing escaping and unescaping");
|
||||
|
||||
for (i=0; i<ESCAPE_TEST_COUNT; i++)
|
||||
wcstring random_string;
|
||||
wcstring escaped_string;
|
||||
wcstring unescaped_string;
|
||||
for (size_t i=0; i<ESCAPE_TEST_COUNT; i++)
|
||||
{
|
||||
const wchar_t *o, *e, *u;
|
||||
|
||||
sb.clear();
|
||||
random_string.clear();
|
||||
while (rand() % ESCAPE_TEST_LENGTH)
|
||||
{
|
||||
sb.push_back((rand() %ESCAPE_TEST_CHAR) +1);
|
||||
random_string.push_back((rand() % ESCAPE_TEST_CHAR) +1);
|
||||
}
|
||||
o = (const wchar_t *)sb.c_str();
|
||||
e = escape(o, 1);
|
||||
u = unescape(e, 0);
|
||||
if (!o || !e || !u)
|
||||
|
||||
escaped_string = escape_string(random_string, ESCAPE_ALL);
|
||||
bool unescaped_success = unescape_string(escaped_string, &unescaped_string, UNESCAPE_DEFAULT);
|
||||
|
||||
if (! unescaped_success)
|
||||
{
|
||||
err(L"Escaping cycle of string %ls produced null pointer on %ls", o, e?L"unescaping":L"escaping");
|
||||
|
||||
err(L"Failed to unescape string <%ls>", escaped_string.c_str());
|
||||
}
|
||||
|
||||
|
||||
if (wcscmp(o, u))
|
||||
else if (unescaped_string != random_string)
|
||||
{
|
||||
err(L"Escaping cycle of string %ls produced different string %ls", o, u);
|
||||
|
||||
|
||||
err(L"Escaped and then unescaped string '%ls', but got back a different string '%ls'", random_string.c_str(), unescaped_string.c_str());
|
||||
}
|
||||
free((void *)e);
|
||||
free((void *)u);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,7 +433,7 @@ static void test_fork(void)
|
|||
size_t i, max = 100;
|
||||
for (i=0; i < 100; i++)
|
||||
{
|
||||
printf("%lu / %lu\n", i+1, max);
|
||||
printf("%lu / %lu\n", (unsigned long)(i+1), (unsigned long) max);
|
||||
/* Do something horrible to try to trigger an error */
|
||||
#define THREAD_COUNT 8
|
||||
#define FORK_COUNT 10
|
||||
|
@ -454,6 +489,50 @@ static void test_fork(void)
|
|||
#undef FORK_COUNT
|
||||
}
|
||||
|
||||
// Little function that runs in the main thread
|
||||
static int test_iothread_main_call(int *addr)
|
||||
{
|
||||
*addr += 1;
|
||||
return *addr;
|
||||
}
|
||||
|
||||
// Little function that runs in a background thread, bouncing to the main
|
||||
static int test_iothread_thread_call(int *addr)
|
||||
{
|
||||
int before = *addr;
|
||||
iothread_perform_on_main(test_iothread_main_call, addr);
|
||||
int after = *addr;
|
||||
|
||||
// Must have incremented it at least once
|
||||
if (before >= after)
|
||||
{
|
||||
err(L"Failed to increment from background thread");
|
||||
}
|
||||
return after;
|
||||
}
|
||||
|
||||
static void test_iothread(void)
|
||||
{
|
||||
say(L"Testing iothreads");
|
||||
int *int_ptr = new int(0);
|
||||
int iterations = 1000;
|
||||
for (int i=0; i < iterations; i++)
|
||||
{
|
||||
iothread_perform(test_iothread_thread_call, (void (*)(int *, int))NULL, int_ptr);
|
||||
}
|
||||
|
||||
// Now wait until we're done
|
||||
iothread_drain_all();
|
||||
|
||||
// Should have incremented it once per thread
|
||||
if (*int_ptr != iterations)
|
||||
{
|
||||
say(L"Expected int to be %d, but instead it was %d", iterations, *int_ptr);
|
||||
}
|
||||
|
||||
delete int_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
Test the parser
|
||||
*/
|
||||
|
@ -532,7 +611,7 @@ static void test_utils()
|
|||
{
|
||||
say(L"Testing utils");
|
||||
const wchar_t *a = L"echo (echo (echo hi";
|
||||
|
||||
|
||||
const wchar_t *begin = NULL, *end = NULL;
|
||||
parse_util_cmdsubst_extent(a, 0, &begin, &end);
|
||||
if (begin != a || end != begin + wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
|
||||
|
@ -542,7 +621,7 @@ static void test_utils()
|
|||
if (begin != a || end != begin + wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
|
||||
parse_util_cmdsubst_extent(a, 3, &begin, &end);
|
||||
if (begin != a || end != begin + wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
|
||||
|
||||
|
||||
parse_util_cmdsubst_extent(a, 8, &begin, &end);
|
||||
if (begin != a + wcslen(L"echo (")) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
|
||||
|
||||
|
@ -788,7 +867,7 @@ static void test_path()
|
|||
{
|
||||
err(L"Bug in canonical PATH code");
|
||||
}
|
||||
|
||||
|
||||
if (paths_are_equivalent(L"/foo/bar/baz", L"foo/bar/baz")) err(L"Bug in canonical PATH code on line %ld", (long)__LINE__);
|
||||
if (! paths_are_equivalent(L"///foo///bar/baz", L"/foo/bar////baz//")) err(L"Bug in canonical PATH code on line %ld", (long)__LINE__);
|
||||
if (! paths_are_equivalent(L"/foo/bar/baz", L"/foo/bar/baz")) err(L"Bug in canonical PATH code on line %ld", (long)__LINE__);
|
||||
|
@ -1279,7 +1358,7 @@ void perf_complete()
|
|||
str[0]=c;
|
||||
reader_set_buffer(str, 0);
|
||||
|
||||
complete(str, out, COMPLETION_REQUEST_DEFAULT, NULL);
|
||||
complete(str, out, COMPLETION_REQUEST_DEFAULT);
|
||||
|
||||
matches += out.size();
|
||||
out.clear();
|
||||
|
@ -1299,7 +1378,7 @@ void perf_complete()
|
|||
|
||||
reader_set_buffer(str, 0);
|
||||
|
||||
complete(str, out, COMPLETION_REQUEST_DEFAULT, NULL);
|
||||
complete(str, out, COMPLETION_REQUEST_DEFAULT);
|
||||
|
||||
matches += out.size();
|
||||
out.clear();
|
||||
|
@ -1836,12 +1915,14 @@ int main(int argc, char **argv)
|
|||
reader_init();
|
||||
env_init();
|
||||
|
||||
test_unescape_sane();
|
||||
test_escape_crazy();
|
||||
test_format();
|
||||
test_escape();
|
||||
test_convert();
|
||||
test_convert_nulls();
|
||||
test_tok();
|
||||
test_fork();
|
||||
test_iothread();
|
||||
test_parser();
|
||||
test_utils();
|
||||
test_escape_sequences();
|
||||
|
|
|
@ -694,7 +694,7 @@ static void daemonize()
|
|||
}
|
||||
|
||||
/*
|
||||
Put ourself in out own processing group
|
||||
Put ourself in our own process group
|
||||
*/
|
||||
setsid();
|
||||
|
||||
|
|
|
@ -710,7 +710,7 @@ static bool autosuggest_parse_command(const wcstring &str, wcstring *out_command
|
|||
{
|
||||
/* Command. First check that the command actually exists. */
|
||||
wcstring local_cmd = tok_last(&tok);
|
||||
bool expanded = expand_one(cmd, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_VARIABLES);
|
||||
bool expanded = expand_one(cmd, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_VARIABLES | EXPAND_SKIP_JOBS);
|
||||
if (! expanded || has_expand_reserved(cmd.c_str()))
|
||||
{
|
||||
/* We can't expand this cmd, ignore it */
|
||||
|
@ -826,8 +826,8 @@ bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_di
|
|||
outSuggestion.clear();
|
||||
|
||||
/* Unescape the parameter */
|
||||
wcstring unescaped_dir = escaped_dir;
|
||||
bool unescaped = unescape_string(unescaped_dir, UNESCAPE_INCOMPLETE);
|
||||
wcstring unescaped_dir;
|
||||
bool unescaped = unescape_string(escaped_dir, &unescaped_dir, UNESCAPE_INCOMPLETE);
|
||||
|
||||
/* Determine the quote type we got from the input directory. */
|
||||
wchar_t quote = L'\0';
|
||||
|
@ -1404,12 +1404,13 @@ void highlight_shell(const wcstring &buff, std::vector<int> &color, size_t pos,
|
|||
if (tok_begin && tok_end)
|
||||
{
|
||||
wcstring token(tok_begin, tok_end-tok_begin);
|
||||
const wcstring_list_t working_directory_list(1, working_directory);
|
||||
if (unescape_string(token, 1))
|
||||
if (unescape_string_in_place(&token, UNESCAPE_SPECIAL))
|
||||
{
|
||||
/* Big hack: is_potential_path expects a tilde, but unescape_string gives us HOME_DIRECTORY. Put it back. */
|
||||
if (! token.empty() && token.at(0) == HOME_DIRECTORY)
|
||||
token.at(0) = L'~';
|
||||
|
||||
const wcstring_list_t working_directory_list(1, working_directory);
|
||||
if (is_potential_path(token, working_directory_list, PATH_EXPAND_TILDE))
|
||||
{
|
||||
for (ptrdiff_t i=tok_begin-cbuff; i < (tok_end-cbuff); i++)
|
||||
|
|
26
history.cpp
26
history.cpp
|
@ -286,7 +286,7 @@ static void append_yaml_to_buffer(const wcstring &wcmd, time_t timestamp, const
|
|||
buffer->append("- cmd: ", cmd.c_str(), "\n");
|
||||
|
||||
char timestamp_str[96];
|
||||
snprintf(timestamp_str, sizeof timestamp_str, "%ld", timestamp);
|
||||
snprintf(timestamp_str, sizeof timestamp_str, "%ld", (long) timestamp);
|
||||
buffer->append(" when: ", timestamp_str, "\n");
|
||||
|
||||
if (! required_paths.empty())
|
||||
|
@ -413,6 +413,13 @@ static size_t offset_of_next_item_fish_2_0(const char *begin, size_t mmap_length
|
|||
bool has_timestamp = false;
|
||||
time_t timestamp;
|
||||
const char *interior_line;
|
||||
|
||||
/*
|
||||
* Ensure the loop is processed at least once. Otherwise,
|
||||
* timestamp is unitialized.
|
||||
*/
|
||||
bool processed_once = false;
|
||||
|
||||
for (interior_line = next_line(line_start, end - line_start);
|
||||
interior_line != NULL && ! has_timestamp;
|
||||
interior_line = next_line(interior_line, end - interior_line))
|
||||
|
@ -427,8 +434,12 @@ static size_t offset_of_next_item_fish_2_0(const char *begin, size_t mmap_length
|
|||
|
||||
/* Try parsing a timestamp from this line. If we succeed, the loop will break. */
|
||||
has_timestamp = parse_timestamp(interior_line, ×tamp);
|
||||
|
||||
processed_once = true;
|
||||
}
|
||||
|
||||
assert(processed_once);
|
||||
|
||||
/* Skip this item if the timestamp is past our cutoff. */
|
||||
if (has_timestamp && timestamp > cutoff_timestamp)
|
||||
{
|
||||
|
@ -629,7 +640,7 @@ void history_t::get_string_representation(wcstring &result, const wcstring &sepa
|
|||
scoped_lock locker(lock);
|
||||
|
||||
bool first = true;
|
||||
|
||||
|
||||
std::set<wcstring> seen;
|
||||
|
||||
/* Append new items. Note that in principle we could use const_reverse_iterator, but we do not because reverse_iterator is not convertible to const_reverse_iterator ( http://github.com/fish-shell/fish-shell/issues/431 ) */
|
||||
|
@ -638,7 +649,7 @@ void history_t::get_string_representation(wcstring &result, const wcstring &sepa
|
|||
/* Skip duplicates */
|
||||
if (! seen.insert(iter->str()).second)
|
||||
continue;
|
||||
|
||||
|
||||
if (! first)
|
||||
result.append(separator);
|
||||
result.append(iter->str());
|
||||
|
@ -651,11 +662,11 @@ void history_t::get_string_representation(wcstring &result, const wcstring &sepa
|
|||
{
|
||||
size_t offset = *iter;
|
||||
const history_item_t item = history_t::decode_item(mmap_start + offset, mmap_length - offset, mmap_type);
|
||||
|
||||
|
||||
/* Skip duplicates */
|
||||
if (! seen.insert(item.str()).second)
|
||||
continue;
|
||||
|
||||
|
||||
if (! first)
|
||||
result.append(separator);
|
||||
result.append(item.str());
|
||||
|
@ -1731,8 +1742,9 @@ void history_t::add_with_file_detection(const wcstring &str)
|
|||
const wchar_t *token_cstr = tok_last(&tokenizer);
|
||||
if (token_cstr)
|
||||
{
|
||||
wcstring potential_path = token_cstr;
|
||||
if (unescape_string(potential_path, false) && string_could_be_path(potential_path))
|
||||
wcstring potential_path;
|
||||
bool unescaped = unescape_string(token_cstr, &potential_path, UNESCAPE_DEFAULT);
|
||||
if (unescaped && string_could_be_path(potential_path))
|
||||
{
|
||||
potential_paths.push_back(potential_path);
|
||||
|
||||
|
|
22
input.cpp
22
input.cpp
|
@ -60,6 +60,8 @@
|
|||
#include "intern.h"
|
||||
#include <vector>
|
||||
|
||||
#define DEFAULT_TERM L"ansi"
|
||||
|
||||
/**
|
||||
Struct representing a keybinding. Returned by input_get_mappings.
|
||||
*/
|
||||
|
@ -346,13 +348,29 @@ int input_init()
|
|||
|
||||
input_common_init(&interrupt_handler);
|
||||
|
||||
const env_var_t term = env_get_string(L"TERM");
|
||||
int errret;
|
||||
if (setupterm(0, STDOUT_FILENO, &errret) == ERR)
|
||||
{
|
||||
debug(0, _(L"Could not set up terminal"));
|
||||
exit_without_destructors(1);
|
||||
if (errret == 0)
|
||||
{
|
||||
debug(0, _(L"Check that your terminal type, '%ls', is supported on this system"),
|
||||
term.c_str());
|
||||
debug(0, _(L"Attempting to use '%ls' instead"), DEFAULT_TERM);
|
||||
env_set(L"TERM", DEFAULT_TERM, ENV_GLOBAL | ENV_EXPORT);
|
||||
const std::string default_term = wcs2string(DEFAULT_TERM);
|
||||
if (setupterm(const_cast<char *>(default_term.c_str()), STDOUT_FILENO, &errret) == ERR)
|
||||
{
|
||||
debug(0, _(L"Could not set up terminal"));
|
||||
exit_without_destructors(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
exit_without_destructors(1);
|
||||
}
|
||||
}
|
||||
const env_var_t term = env_get_string(L"TERM");
|
||||
assert(! term.missing());
|
||||
output_set_term(term);
|
||||
|
||||
|
|
2
io.cpp
2
io.cpp
|
@ -71,7 +71,7 @@ void io_pipe_t::print() const
|
|||
void io_buffer_t::print() const
|
||||
{
|
||||
fprintf(stderr, "buffer %p (input: %s, size %lu)\n", out_buffer_ptr(),
|
||||
is_input ? "yes" : "no", out_buffer_size());
|
||||
is_input ? "yes" : "no", (unsigned long) out_buffer_size());
|
||||
}
|
||||
|
||||
void io_buffer_t::read()
|
||||
|
|
175
iothread.cpp
175
iothread.cpp
|
@ -22,6 +22,11 @@
|
|||
#define IO_MAX_THREADS 64
|
||||
#endif
|
||||
|
||||
/* A special "thread index" that means service main thread requests */
|
||||
#define IO_SERVICE_MAIN_THREAD_REQUEST_QUEUE 99
|
||||
|
||||
static void iothread_service_main_thread_requests(void);
|
||||
|
||||
static int s_active_thread_count;
|
||||
|
||||
typedef unsigned char ThreadIndex_t;
|
||||
|
@ -32,16 +37,22 @@ static struct WorkerThread_t
|
|||
pthread_t thread;
|
||||
} threads[IO_MAX_THREADS];
|
||||
|
||||
struct ThreadedRequest_t
|
||||
struct SpawnRequest_t
|
||||
{
|
||||
int sequenceNumber;
|
||||
|
||||
int (*handler)(void *);
|
||||
void (*completionCallback)(void *, int);
|
||||
void *context;
|
||||
int handlerResult;
|
||||
};
|
||||
|
||||
struct MainThreadRequest_t
|
||||
{
|
||||
int (*handler)(void *);
|
||||
void *context;
|
||||
volatile int handlerResult;
|
||||
volatile bool done;
|
||||
};
|
||||
|
||||
static struct WorkerThread_t *next_vacant_thread_slot(void)
|
||||
{
|
||||
for (ThreadIndex_t i=0; i < IO_MAX_THREADS; i++)
|
||||
|
@ -51,9 +62,17 @@ static struct WorkerThread_t *next_vacant_thread_slot(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static pthread_mutex_t s_request_queue_lock;
|
||||
static std::queue<ThreadedRequest_t *> s_request_queue;
|
||||
static int s_last_sequence_number;
|
||||
/* Spawn support */
|
||||
static pthread_mutex_t s_spawn_queue_lock;
|
||||
static std::queue<SpawnRequest_t *> s_request_queue;
|
||||
|
||||
/* "Do on main thread" support */
|
||||
static pthread_mutex_t s_main_thread_performer_lock; // protects the main thread requests
|
||||
static pthread_cond_t s_main_thread_performer_condition; //protects the main thread requests
|
||||
static pthread_mutex_t s_main_thread_request_queue_lock; // protects the queue
|
||||
static std::queue<MainThreadRequest_t *> s_main_thread_request_queue;
|
||||
|
||||
/* Notifying pipes */
|
||||
static int s_read_pipe, s_write_pipe;
|
||||
|
||||
static void iothread_init(void)
|
||||
|
@ -63,8 +82,11 @@ static void iothread_init(void)
|
|||
{
|
||||
inited = true;
|
||||
|
||||
/* Initialize the queue lock */
|
||||
VOMIT_ON_FAILURE(pthread_mutex_init(&s_request_queue_lock, NULL));
|
||||
/* Initialize some locks */
|
||||
VOMIT_ON_FAILURE(pthread_mutex_init(&s_spawn_queue_lock, NULL));
|
||||
VOMIT_ON_FAILURE(pthread_mutex_init(&s_main_thread_request_queue_lock, NULL));
|
||||
VOMIT_ON_FAILURE(pthread_mutex_init(&s_main_thread_performer_lock, NULL));
|
||||
VOMIT_ON_FAILURE(pthread_cond_init(&s_main_thread_performer_condition, NULL));
|
||||
|
||||
/* Initialize the completion pipes */
|
||||
int pipes[2] = {0, 0};
|
||||
|
@ -84,16 +106,16 @@ static void iothread_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void add_to_queue(struct ThreadedRequest_t *req)
|
||||
static void add_to_queue(struct SpawnRequest_t *req)
|
||||
{
|
||||
ASSERT_IS_LOCKED(s_request_queue_lock);
|
||||
ASSERT_IS_LOCKED(s_spawn_queue_lock);
|
||||
s_request_queue.push(req);
|
||||
}
|
||||
|
||||
static ThreadedRequest_t *dequeue_request(void)
|
||||
static SpawnRequest_t *dequeue_spawn_request(void)
|
||||
{
|
||||
ThreadedRequest_t *result = NULL;
|
||||
scoped_lock lock(s_request_queue_lock);
|
||||
SpawnRequest_t *result = NULL;
|
||||
scoped_lock lock(s_spawn_queue_lock);
|
||||
if (! s_request_queue.empty())
|
||||
{
|
||||
result = s_request_queue.front();
|
||||
|
@ -109,7 +131,7 @@ static void *iothread_worker(void *threadPtr)
|
|||
struct WorkerThread_t *thread = (struct WorkerThread_t *)threadPtr;
|
||||
|
||||
/* Grab a request off of the queue */
|
||||
struct ThreadedRequest_t *req = dequeue_request();
|
||||
struct SpawnRequest_t *req = dequeue_spawn_request();
|
||||
|
||||
/* Run the handler and store the result */
|
||||
if (req)
|
||||
|
@ -127,7 +149,7 @@ static void *iothread_worker(void *threadPtr)
|
|||
/* Spawn another thread if there's work to be done. */
|
||||
static void iothread_spawn_if_needed(void)
|
||||
{
|
||||
ASSERT_IS_LOCKED(s_request_queue_lock);
|
||||
ASSERT_IS_LOCKED(s_spawn_queue_lock);
|
||||
if (! s_request_queue.empty() && s_active_thread_count < IO_MAX_THREADS)
|
||||
{
|
||||
struct WorkerThread_t *thread = next_vacant_thread_slot();
|
||||
|
@ -168,14 +190,13 @@ int iothread_perform_base(int (*handler)(void *), void (*completionCallback)(voi
|
|||
iothread_init();
|
||||
|
||||
/* Create and initialize a request. */
|
||||
struct ThreadedRequest_t *req = new ThreadedRequest_t();
|
||||
struct SpawnRequest_t *req = new SpawnRequest_t();
|
||||
req->handler = handler;
|
||||
req->completionCallback = completionCallback;
|
||||
req->context = context;
|
||||
req->sequenceNumber = ++s_last_sequence_number;
|
||||
|
||||
/* Take our lock */
|
||||
scoped_lock lock(s_request_queue_lock);
|
||||
scoped_lock lock(s_spawn_queue_lock);
|
||||
|
||||
/* Add to the queue */
|
||||
add_to_queue(req);
|
||||
|
@ -196,31 +217,38 @@ void iothread_service_completion(void)
|
|||
ASSERT_IS_MAIN_THREAD();
|
||||
ThreadIndex_t threadIdx = (ThreadIndex_t)-1;
|
||||
VOMIT_ON_FAILURE(1 != read_loop(iothread_port(), &threadIdx, sizeof threadIdx));
|
||||
assert(threadIdx < IO_MAX_THREADS);
|
||||
|
||||
struct WorkerThread_t *thread = &threads[threadIdx];
|
||||
assert(thread->thread != 0);
|
||||
|
||||
struct ThreadedRequest_t *req = NULL;
|
||||
VOMIT_ON_FAILURE(pthread_join(thread->thread, (void **)&req));
|
||||
|
||||
/* Free up this thread */
|
||||
thread->thread = 0;
|
||||
assert(s_active_thread_count > 0);
|
||||
s_active_thread_count -= 1;
|
||||
|
||||
/* Handle the request */
|
||||
if (req)
|
||||
if (threadIdx == IO_SERVICE_MAIN_THREAD_REQUEST_QUEUE)
|
||||
{
|
||||
if (req->completionCallback)
|
||||
req->completionCallback(req->context, req->handlerResult);
|
||||
delete req;
|
||||
iothread_service_main_thread_requests();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(threadIdx < IO_MAX_THREADS);
|
||||
|
||||
/* Maybe spawn another thread, if there's more work to be done. */
|
||||
VOMIT_ON_FAILURE(pthread_mutex_lock(&s_request_queue_lock));
|
||||
iothread_spawn_if_needed();
|
||||
VOMIT_ON_FAILURE(pthread_mutex_unlock(&s_request_queue_lock));
|
||||
struct WorkerThread_t *thread = &threads[threadIdx];
|
||||
assert(thread->thread != 0);
|
||||
|
||||
struct SpawnRequest_t *req = NULL;
|
||||
VOMIT_ON_FAILURE(pthread_join(thread->thread, (void **)&req));
|
||||
|
||||
/* Free up this thread */
|
||||
thread->thread = 0;
|
||||
assert(s_active_thread_count > 0);
|
||||
s_active_thread_count -= 1;
|
||||
|
||||
/* Handle the request */
|
||||
if (req)
|
||||
{
|
||||
if (req->completionCallback)
|
||||
req->completionCallback(req->context, req->handlerResult);
|
||||
delete req;
|
||||
}
|
||||
|
||||
/* Maybe spawn another thread, if there's more work to be done. */
|
||||
scoped_lock locker(s_spawn_queue_lock);
|
||||
iothread_spawn_if_needed();
|
||||
}
|
||||
}
|
||||
|
||||
void iothread_drain_all(void)
|
||||
|
@ -243,3 +271,72 @@ void iothread_drain_all(void)
|
|||
printf("(Waited %.02f msec for %d thread(s) to drain)\n", 1000 * (after - now), thread_count);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* "Do on main thread" support */
|
||||
|
||||
static void iothread_service_main_thread_requests(void)
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
|
||||
// Move the queue to a local variable
|
||||
std::queue<MainThreadRequest_t *> request_queue;
|
||||
{
|
||||
scoped_lock queue_lock(s_main_thread_request_queue_lock);
|
||||
std::swap(request_queue, s_main_thread_request_queue);
|
||||
}
|
||||
|
||||
if (! request_queue.empty())
|
||||
{
|
||||
// Perform each of the functions
|
||||
// Note we are NOT responsible for deleting these. They are stack allocated in their respective threads!
|
||||
scoped_lock cond_lock(s_main_thread_performer_lock);
|
||||
while (! request_queue.empty())
|
||||
{
|
||||
MainThreadRequest_t *req = request_queue.front();
|
||||
request_queue.pop();
|
||||
req->handlerResult = req->handler(req->context);
|
||||
req->done = true;
|
||||
}
|
||||
|
||||
// Ok, we've handled everybody. Announce the good news, and allow ourselves to be unlocked
|
||||
VOMIT_ON_FAILURE(pthread_cond_broadcast(&s_main_thread_performer_condition));
|
||||
}
|
||||
}
|
||||
|
||||
int iothread_perform_on_main_base(int (*handler)(void *), void *context)
|
||||
{
|
||||
// If this is the main thread, just do it
|
||||
if (is_main_thread())
|
||||
{
|
||||
return handler(context);
|
||||
}
|
||||
|
||||
// Make a new request. Note we are synchronous, so this can be stack allocated!
|
||||
MainThreadRequest_t req;
|
||||
req.handler = handler;
|
||||
req.context = context;
|
||||
req.handlerResult = 0;
|
||||
req.done = false;
|
||||
|
||||
// Append it
|
||||
{
|
||||
scoped_lock queue_lock(s_main_thread_request_queue_lock);
|
||||
s_main_thread_request_queue.push(&req);
|
||||
}
|
||||
|
||||
// Tell the pipe
|
||||
const ThreadIndex_t idx = IO_SERVICE_MAIN_THREAD_REQUEST_QUEUE;
|
||||
VOMIT_ON_FAILURE(! write_loop(s_write_pipe, (const char *)&idx, sizeof idx));
|
||||
|
||||
// Wait on the condition, until we're done
|
||||
scoped_lock perform_lock(s_main_thread_performer_lock);
|
||||
while (! req.done)
|
||||
{
|
||||
// It would be nice to support checking for cancellation here, but the clients need a deterministic way to clean up to avoid leaks
|
||||
VOMIT_ON_FAILURE(pthread_cond_wait(&s_main_thread_performer_condition, &s_main_thread_performer_lock));
|
||||
}
|
||||
|
||||
// Ok, the request must now be done
|
||||
assert(req.done);
|
||||
return req.handlerResult;
|
||||
}
|
||||
|
|
13
iothread.h
13
iothread.h
|
@ -28,11 +28,22 @@ void iothread_service_completion(void);
|
|||
/** Waits for all iothreads to terminate. */
|
||||
void iothread_drain_all(void);
|
||||
|
||||
/** Helper template */
|
||||
/** Performs a function on the main thread, blocking until it completes */
|
||||
int iothread_perform_on_main_base(int (*handler)(void *), void *context);
|
||||
|
||||
/** Helper templates */
|
||||
template<typename T>
|
||||
int iothread_perform(int (*handler)(T *), void (*completionCallback)(T *, int), T *context)
|
||||
{
|
||||
return iothread_perform_base((int (*)(void *))handler, (void (*)(void *, int))completionCallback, static_cast<void *>(context));
|
||||
}
|
||||
|
||||
/** Helper templates */
|
||||
template<typename T>
|
||||
int iothread_perform_on_main(int (*handler)(T *), T *context)
|
||||
{
|
||||
return iothread_perform_on_main_base((int (*)(void *))handler, (void *)(context));
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -245,10 +245,10 @@ void parse_util_cmdsubst_extent(const wchar_t *buff, size_t cursor_pos, const wc
|
|||
const wchar_t * const cursor = buff + cursor_pos;
|
||||
|
||||
CHECK(buff,);
|
||||
|
||||
|
||||
const size_t bufflen = wcslen(buff);
|
||||
assert(cursor_pos <= bufflen);
|
||||
|
||||
|
||||
/* ap and bp are the beginning and end of the tightest command substitition found so far */
|
||||
const wchar_t *ap = buff, *bp = buff + bufflen;
|
||||
const wchar_t *pos = buff;
|
||||
|
@ -265,7 +265,7 @@ void parse_util_cmdsubst_extent(const wchar_t *buff, size_t cursor_pos, const wc
|
|||
{
|
||||
end = const_cast<wchar_t *>(buff) + bufflen;
|
||||
}
|
||||
|
||||
|
||||
if (begin < cursor && end >= cursor)
|
||||
{
|
||||
/* This command substitution surrounds the cursor, so it's a tighter fit */
|
||||
|
@ -290,7 +290,7 @@ void parse_util_cmdsubst_extent(const wchar_t *buff, size_t cursor_pos, const wc
|
|||
assert(pos <= buff + bufflen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (a != NULL) *a = ap;
|
||||
if (b != NULL) *b = bp;
|
||||
}
|
||||
|
@ -383,7 +383,7 @@ static void job_or_process_extent(const wchar_t *buff,
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
|
|
36
parser.cpp
36
parser.cpp
|
@ -2013,7 +2013,7 @@ int parser_t::parse_job(process_t *p,
|
|||
{
|
||||
|
||||
const wchar_t *cmd = args.at(0).completion.c_str();
|
||||
|
||||
|
||||
/*
|
||||
We couldn't find the specified command.
|
||||
|
||||
|
@ -2036,20 +2036,20 @@ int parser_t::parse_job(process_t *p,
|
|||
if (equals_ptr != NULL)
|
||||
{
|
||||
/* Try to figure out if this is a pure variable assignment (foo=bar), or if this appears to be running a command (foo=bar ruby...) */
|
||||
|
||||
|
||||
const wcstring name_str = wcstring(cmd, equals_ptr - cmd); //variable name, up to the =
|
||||
const wcstring val_str = wcstring(equals_ptr + 1); //variable value, past the =
|
||||
|
||||
|
||||
wcstring next_str;
|
||||
if (tok_peek_next(tok, &next_str) == TOK_STRING && ! next_str.empty())
|
||||
{
|
||||
wcstring ellipsis_str = wcstring(1, ellipsis_char);
|
||||
if (ellipsis_str == L"$")
|
||||
ellipsis_str = L"...";
|
||||
|
||||
|
||||
/* Looks like a command */
|
||||
debug(0,
|
||||
_( L"Unknown command '%ls'. Did you mean to run %ls with a modified environment? Try 'env %ls=%ls %ls%ls'. See the help section on the set command by typing 'help set'."),
|
||||
_(L"Unknown command '%ls'. Did you mean to run %ls with a modified environment? Try 'env %ls=%ls %ls%ls'. See the help section on the set command by typing 'help set'."),
|
||||
cmd,
|
||||
next_str.c_str(),
|
||||
name_str.c_str(),
|
||||
|
@ -2728,8 +2728,6 @@ const wchar_t *parser_get_block_command(int type)
|
|||
*/
|
||||
int parser_t::parser_test_argument(const wchar_t *arg, wcstring *out, const wchar_t *prefix, int offset)
|
||||
{
|
||||
wchar_t *unesc;
|
||||
wchar_t *pos;
|
||||
int err=0;
|
||||
|
||||
wchar_t *paran_begin, *paran_end;
|
||||
|
@ -2791,8 +2789,8 @@ int parser_t::parser_test_argument(const wchar_t *arg, wcstring *out, const wcha
|
|||
}
|
||||
}
|
||||
|
||||
unesc = unescape(arg_cpy, 1);
|
||||
if (!unesc)
|
||||
wcstring unesc;
|
||||
if (! unescape_string(arg_cpy, &unesc, UNESCAPE_SPECIAL))
|
||||
{
|
||||
if (out)
|
||||
{
|
||||
|
@ -2805,26 +2803,25 @@ int parser_t::parser_test_argument(const wchar_t *arg, wcstring *out, const wcha
|
|||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Check for invalid variable expansions
|
||||
*/
|
||||
for (pos = unesc; *pos; pos++)
|
||||
/* Check for invalid variable expansions */
|
||||
const size_t unesc_size = unesc.size();
|
||||
for (size_t idx = 0; idx < unesc_size; idx++)
|
||||
{
|
||||
switch (*pos)
|
||||
switch (unesc.at(idx))
|
||||
{
|
||||
case VARIABLE_EXPAND:
|
||||
case VARIABLE_EXPAND_SINGLE:
|
||||
{
|
||||
wchar_t n = *(pos+1);
|
||||
wchar_t next_char = (idx + 1 < unesc_size ? unesc.at(idx + 1) : L'\0');
|
||||
|
||||
if (n != VARIABLE_EXPAND &&
|
||||
n != VARIABLE_EXPAND_SINGLE &&
|
||||
!wcsvarchr(n))
|
||||
if (next_char != VARIABLE_EXPAND &&
|
||||
next_char != VARIABLE_EXPAND_SINGLE &&
|
||||
! wcsvarchr(next_char))
|
||||
{
|
||||
err=1;
|
||||
if (out)
|
||||
{
|
||||
expand_variable_error(*this, unesc, pos-unesc, offset);
|
||||
expand_variable_error(*this, unesc, idx, offset);
|
||||
print_errors(*out, prefix);
|
||||
}
|
||||
}
|
||||
|
@ -2837,7 +2834,6 @@ int parser_t::parser_test_argument(const wchar_t *arg, wcstring *out, const wcha
|
|||
|
||||
free(arg_cpy);
|
||||
|
||||
free(unesc);
|
||||
return err;
|
||||
|
||||
}
|
||||
|
|
16
path.cpp
16
path.cpp
|
@ -400,7 +400,7 @@ void path_make_canonical(wcstring &path)
|
|||
path.at(trailing++) = c;
|
||||
}
|
||||
prev_was_slash = is_slash;
|
||||
}
|
||||
}
|
||||
assert(trailing <= len);
|
||||
if (trailing < len)
|
||||
path.resize(trailing);
|
||||
|
@ -410,32 +410,32 @@ bool paths_are_equivalent(const wcstring &p1, const wcstring &p2)
|
|||
{
|
||||
if (p1 == p2)
|
||||
return true;
|
||||
|
||||
|
||||
size_t len1 = p1.size(), len2 = p2.size();
|
||||
|
||||
|
||||
// Ignore trailing slashes after the first character
|
||||
while (len1 > 1 && p1.at(len1 - 1) == L'/') len1--;
|
||||
while (len2 > 1 && p2.at(len2 - 1) == L'/') len2--;
|
||||
|
||||
|
||||
// Start walking
|
||||
size_t idx1 = 0, idx2 = 0;
|
||||
while (idx1 < len1 && idx2 < len2)
|
||||
{
|
||||
wchar_t c1 = p1.at(idx1), c2 = p2.at(idx2);
|
||||
|
||||
|
||||
// If the characters are different, the strings are not equivalent
|
||||
if (c1 != c2)
|
||||
break;
|
||||
|
||||
|
||||
idx1++;
|
||||
idx2++;
|
||||
|
||||
|
||||
// If the character was a slash, walk forwards until we hit the end of the string, or a non-slash
|
||||
// Note the first condition is invariant within the loop
|
||||
while (c1 == L'/' && idx1 < len1 && p1.at(idx1) == L'/') idx1++;
|
||||
while (c2 == L'/' && idx2 < len2 && p2.at(idx2) == L'/') idx2++;
|
||||
}
|
||||
|
||||
|
||||
// We matched if we consumed all of the characters in both strings
|
||||
return idx1 == len1 && idx2 == len2;
|
||||
}
|
||||
|
|
1
proc.cpp
1
proc.cpp
|
@ -106,6 +106,7 @@ job_iterator_t::job_iterator_t(job_list_t &jobs) : job_list(&jobs)
|
|||
|
||||
job_iterator_t::job_iterator_t() : job_list(&parser_t::principal_parser().job_list())
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
this->reset();
|
||||
}
|
||||
|
||||
|
|
5
proc.h
5
proc.h
|
@ -373,7 +373,10 @@ public:
|
|||
unsigned int flags;
|
||||
|
||||
/* Returns the block IO redirections associated with the job. These are things like the IO redirections associated with the begin...end statement. */
|
||||
const io_chain_t &block_io_chain() const { return this->block_io; }
|
||||
const io_chain_t &block_io_chain() const
|
||||
{
|
||||
return this->block_io;
|
||||
}
|
||||
|
||||
/* Fetch all the IO redirections associated with the job */
|
||||
io_chain_t all_io_redirections() const;
|
||||
|
|
58
reader.cpp
58
reader.cpp
|
@ -984,19 +984,27 @@ void reader_init()
|
|||
// PCA disable VDSUSP (typically control-Y), which is a funny job control
|
||||
// function available only on OS X and BSD systems
|
||||
// This lets us use control-Y for yank instead
|
||||
#ifdef VDSUSP
|
||||
#ifdef VDSUSP
|
||||
shell_modes.c_cc[VDSUSP] = _POSIX_VDISABLE;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void reader_destroy()
|
||||
{
|
||||
tcsetattr(0, TCSANOW, &terminal_mode_on_startup);
|
||||
pthread_key_delete(generation_count_key);
|
||||
}
|
||||
|
||||
void restore_term_mode()
|
||||
{
|
||||
// Restore the term mode if we own the terminal
|
||||
// It's important we do this before restore_foreground_process_group, otherwise we won't think we own the terminal
|
||||
if (getpid() == tcgetpgrp(STDIN_FILENO))
|
||||
{
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &terminal_mode_on_startup);
|
||||
}
|
||||
}
|
||||
|
||||
void reader_exit(int do_exit, int forced)
|
||||
{
|
||||
|
@ -1402,12 +1410,8 @@ struct autosuggestion_context_t
|
|||
file_detection_context_t detector;
|
||||
const wcstring working_directory;
|
||||
const env_vars_snapshot_t vars;
|
||||
wcstring_list_t commands_to_load;
|
||||
const unsigned int generation_count;
|
||||
|
||||
// don't reload more than once
|
||||
bool has_tried_reloading;
|
||||
|
||||
autosuggestion_context_t(history_t *history, const wcstring &term, size_t pos) :
|
||||
search_string(term),
|
||||
cursor_pos(pos),
|
||||
|
@ -1415,8 +1419,7 @@ struct autosuggestion_context_t
|
|||
detector(history, term),
|
||||
working_directory(env_get_pwd_slash()),
|
||||
vars(env_vars_snapshot_t::highlighting_keys),
|
||||
generation_count(s_generation_count),
|
||||
has_tried_reloading(false)
|
||||
generation_count(s_generation_count)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1486,7 +1489,7 @@ struct autosuggestion_context_t
|
|||
|
||||
/* Try normal completions */
|
||||
std::vector<completion_t> completions;
|
||||
complete(search_string, completions, COMPLETION_REQUEST_AUTOSUGGESTION, &this->commands_to_load);
|
||||
complete(search_string, completions, COMPLETION_REQUEST_AUTOSUGGESTION);
|
||||
if (! completions.empty())
|
||||
{
|
||||
const completion_t &comp = completions.at(0);
|
||||
|
@ -1515,23 +1518,6 @@ static bool can_autosuggest(void)
|
|||
|
||||
static void autosuggest_completed(autosuggestion_context_t *ctx, int result)
|
||||
{
|
||||
|
||||
/* Extract the commands to load */
|
||||
wcstring_list_t commands_to_load;
|
||||
ctx->commands_to_load.swap(commands_to_load);
|
||||
|
||||
/* If we have autosuggestions to load, load them and try again */
|
||||
if (! result && ! commands_to_load.empty() && ! ctx->has_tried_reloading)
|
||||
{
|
||||
ctx->has_tried_reloading = true;
|
||||
for (wcstring_list_t::const_iterator iter = commands_to_load.begin(); iter != commands_to_load.end(); ++iter)
|
||||
{
|
||||
complete_load(*iter, false);
|
||||
}
|
||||
iothread_perform(threaded_autosuggest, autosuggest_completed, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result &&
|
||||
can_autosuggest() &&
|
||||
ctx->search_string == data->command_line &&
|
||||
|
@ -1715,7 +1701,7 @@ static const completion_t *cycle_competions(const std::vector<completion_t> &com
|
|||
// note start_idx will be set to -1 initially, so that when it gets incremented we start at 0
|
||||
const size_t start_idx = *inout_idx;
|
||||
size_t idx = start_idx;
|
||||
|
||||
|
||||
const completion_t *result = NULL;
|
||||
size_t remaining = comp.size();
|
||||
while (remaining--)
|
||||
|
@ -2332,7 +2318,7 @@ static void handle_token_history(int forward, int reset)
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
|
@ -3263,7 +3249,7 @@ const wchar_t *reader_readline(void)
|
|||
const wcstring buffcpy = wcstring(cmdsub_begin, token_end);
|
||||
|
||||
//fprintf(stderr, "Complete (%ls)\n", buffcpy.c_str());
|
||||
data->complete_func(buffcpy, comp, COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_DESCRIPTIONS | COMPLETION_REQUEST_FUZZY_MATCH, NULL);
|
||||
data->complete_func(buffcpy, comp, COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_DESCRIPTIONS | COMPLETION_REQUEST_FUZZY_MATCH);
|
||||
|
||||
/* Munge our completions */
|
||||
sort_and_make_unique(comp);
|
||||
|
@ -3806,34 +3792,34 @@ const wchar_t *reader_readline(void)
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case R_UPCASE_WORD:
|
||||
case R_DOWNCASE_WORD:
|
||||
case R_CAPITALIZE_WORD:
|
||||
{
|
||||
// For capitalize_word, whether we've capitalized a character so far
|
||||
bool capitalized_first = false;
|
||||
|
||||
|
||||
// We apply the operation from the current location to the end of the word
|
||||
size_t pos = data->buff_pos;
|
||||
move_word(MOVE_DIR_RIGHT, false, move_word_style_punctuation, false);
|
||||
for (; pos < data->buff_pos; pos++)
|
||||
{
|
||||
wchar_t chr = data->command_line.at(pos);
|
||||
|
||||
|
||||
// We always change the case; this decides whether we go uppercase (true) or lowercase (false)
|
||||
bool make_uppercase;
|
||||
if (c == R_CAPITALIZE_WORD)
|
||||
make_uppercase = ! capitalized_first && iswalnum(chr);
|
||||
else
|
||||
make_uppercase = (c == R_UPCASE_WORD);
|
||||
|
||||
|
||||
// Apply the operation and then record what we did
|
||||
if (make_uppercase)
|
||||
chr = towupper(chr);
|
||||
else
|
||||
chr = towlower(chr);
|
||||
|
||||
|
||||
data->command_line.at(pos) = chr;
|
||||
capitalized_first = capitalized_first || make_uppercase;
|
||||
}
|
||||
|
@ -3842,7 +3828,7 @@ const wchar_t *reader_readline(void)
|
|||
reader_repaint();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Other, if a normal character, we add it to the command */
|
||||
default:
|
||||
{
|
||||
|
|
5
reader.h
5
reader.h
|
@ -46,6 +46,9 @@ void reader_init();
|
|||
*/
|
||||
void reader_destroy();
|
||||
|
||||
/** Restore the term mode at startup */
|
||||
void restore_term_mode();
|
||||
|
||||
/**
|
||||
Returns the filename of the file currently read
|
||||
*/
|
||||
|
@ -163,7 +166,7 @@ void reader_pop();
|
|||
- The command to be completed as a null terminated array of wchar_t
|
||||
- An array_list_t in which completions will be inserted.
|
||||
*/
|
||||
typedef void (*complete_function_t)(const wcstring &, std::vector<completion_t> &, completion_request_flags_t, wcstring_list_t * lst);
|
||||
typedef void (*complete_function_t)(const wcstring &, std::vector<completion_t> &, completion_request_flags_t);
|
||||
void reader_set_complete_function(complete_function_t);
|
||||
|
||||
/**
|
||||
|
|
49
screen.cpp
49
screen.cpp
|
@ -137,14 +137,14 @@ static bool allow_soft_wrap(void)
|
|||
size_t escape_code_length(const wchar_t *code)
|
||||
{
|
||||
assert(code != NULL);
|
||||
|
||||
|
||||
/* The only escape codes we recognize start with \x1b */
|
||||
if (code[0] != L'\x1b')
|
||||
return 0;
|
||||
|
||||
|
||||
size_t resulting_length = 0;
|
||||
bool found = false;
|
||||
|
||||
|
||||
if (cur_term != NULL)
|
||||
{
|
||||
/*
|
||||
|
@ -158,12 +158,12 @@ size_t escape_code_length(const wchar_t *code)
|
|||
set_foreground,
|
||||
set_background,
|
||||
};
|
||||
|
||||
|
||||
for (size_t p=0; p < sizeof esc / sizeof *esc && !found; p++)
|
||||
{
|
||||
if (!esc[p])
|
||||
continue;
|
||||
|
||||
|
||||
for (size_t k=0; k<8; k++)
|
||||
{
|
||||
size_t len = try_sequence(tparm(esc[p],k), code);
|
||||
|
@ -176,7 +176,7 @@ size_t escape_code_length(const wchar_t *code)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (cur_term != NULL)
|
||||
{
|
||||
/*
|
||||
|
@ -206,9 +206,9 @@ size_t escape_code_length(const wchar_t *code)
|
|||
exit_standout_mode,
|
||||
enter_secure_mode
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for (size_t p=0; p < sizeof esc2 / sizeof *esc2 && !found; p++)
|
||||
{
|
||||
if (!esc2[p])
|
||||
|
@ -226,7 +226,7 @@ size_t escape_code_length(const wchar_t *code)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if (code[1] == L'k')
|
||||
|
@ -251,7 +251,7 @@ size_t escape_code_length(const wchar_t *code)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (! found)
|
||||
{
|
||||
/* Generic VT100 one byte sequence: CSI followed by something in the range @ through _ */
|
||||
|
@ -261,7 +261,7 @@ size_t escape_code_length(const wchar_t *code)
|
|||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (! found)
|
||||
{
|
||||
/* Generic VT100 CSI-style sequence. <esc>, followed by zero or more ASCII characters NOT in the range [@,_], followed by one character in that range */
|
||||
|
@ -273,11 +273,11 @@ size_t escape_code_length(const wchar_t *code)
|
|||
{
|
||||
/* Consume a sequence of ASCII characters not in the range [@, ~] */
|
||||
wchar_t c = code[cursor];
|
||||
|
||||
|
||||
/* If we're not in ASCII, just stop */
|
||||
if (c > 127)
|
||||
break;
|
||||
|
||||
|
||||
/* If we're the end character, then consume it and then stop */
|
||||
if (c >= L'@' && c <= L'~')
|
||||
{
|
||||
|
@ -290,7 +290,7 @@ size_t escape_code_length(const wchar_t *code)
|
|||
resulting_length = cursor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (! found)
|
||||
{
|
||||
/* Generic VT100 two byte sequence: <esc> followed by something in the range @ through _ */
|
||||
|
@ -300,7 +300,7 @@ size_t escape_code_length(const wchar_t *code)
|
|||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return resulting_length;
|
||||
}
|
||||
|
||||
|
@ -537,10 +537,6 @@ static void s_desired_append_char(screen_t *s,
|
|||
s->desired.add_line();
|
||||
s->desired.cursor.y++;
|
||||
s->desired.cursor.x=0;
|
||||
for (size_t i=0; i < prompt_width; i++)
|
||||
{
|
||||
s_desired_append_char(s, L' ', 0, indent, prompt_width);
|
||||
}
|
||||
}
|
||||
|
||||
line_t &line = s->desired.line(line_no);
|
||||
|
@ -1060,7 +1056,7 @@ struct screen_layout_t
|
|||
wcstring autosuggestion;
|
||||
|
||||
/* Whether the prompts get their own line or not */
|
||||
bool prompts_get_own_line;
|
||||
bool prompts_get_own_line;
|
||||
};
|
||||
|
||||
/* Given a vector whose indexes are offsets and whose values are the widths of the string if truncated at that offset, return the offset that fits in the given width. Returns width_by_offset.size() - 1 if they all fit. The first value in width_by_offset is assumed to be 0. */
|
||||
|
@ -1098,7 +1094,7 @@ static screen_layout_t compute_layout(screen_t *s,
|
|||
size_t left_prompt_width = left_prompt_layout.last_line_width;
|
||||
size_t right_prompt_width = right_prompt_layout.last_line_width;
|
||||
|
||||
if (left_prompt_layout.max_line_width >= screen_width)
|
||||
if (left_prompt_layout.max_line_width > screen_width)
|
||||
{
|
||||
/* If we have a multi-line prompt, see if the longest line fits; if not neuter the whole left prompt */
|
||||
left_prompt = L"> ";
|
||||
|
@ -1215,7 +1211,14 @@ static screen_layout_t compute_layout(screen_t *s,
|
|||
result.left_prompt_space = left_prompt_width;
|
||||
// See remark about for why we can't use the right prompt here
|
||||
//result.right_prompt = right_prompt;
|
||||
result.prompts_get_own_line = true;
|
||||
|
||||
// If the command wraps, and the prompt is not short, place the command on its own line.
|
||||
// A short prompt is 33% or less of the terminal's width.
|
||||
const size_t prompt_percent_width = (100 * left_prompt_width) / screen_width;
|
||||
if (left_prompt_width + first_command_line_width + 1 > screen_width && prompt_percent_width > 33) {
|
||||
result.prompts_get_own_line = true;
|
||||
}
|
||||
|
||||
done = true;
|
||||
}
|
||||
|
||||
|
|
4
screen.h
4
screen.h
|
@ -140,7 +140,7 @@ public:
|
|||
|
||||
/** If we support soft wrapping, we can output to this location without any cursor motion. */
|
||||
screen_data_t::cursor_t soft_wrap_location;
|
||||
|
||||
|
||||
/** Whether the last-drawn autosuggestion (if any) is truncated, or hidden entirely */
|
||||
bool autosuggestion_is_truncated;
|
||||
|
||||
|
@ -158,7 +158,7 @@ public:
|
|||
|
||||
/** If we need to clear, this is how many lines the actual screen had, before we reset it. This is used when resizing the window larger: if the cursor jumps to the line above, we need to remember to clear the subsequent lines. */
|
||||
size_t actual_lines_before_reset;
|
||||
|
||||
|
||||
/**
|
||||
These status buffers are used to check if any output has occurred
|
||||
other than from fish's main loop, in which case we need to redraw.
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
complete -c . -x -a "(__fish_complete_suffix .fish)"
|
1
share/completions/..fish
Symbolic link
1
share/completions/..fish
Symbolic link
|
@ -0,0 +1 @@
|
|||
source.fish
|
140
share/completions/adb.fish
Normal file
140
share/completions/adb.fish
Normal file
|
@ -0,0 +1,140 @@
|
|||
# Completions for Android adb command
|
||||
|
||||
function __fish_adb_no_subcommand --description 'Test if adb has yet to be given the subcommand'
|
||||
for i in (commandline -opc)
|
||||
if contains -- $i connect disconnect devices push pull sync shell emu logcat install uninstall jdwp forward bugreport backup restore version help wait-for-device start-server kill-server remount reboot get-state get-serialno get-devpath status-window root usb tcpip ppp
|
||||
return 1
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function __fish_adb_get_devices --description 'Run adb devices and parse output'
|
||||
# This seems reasonably portable for all the platforms adb runs on
|
||||
set -l count (ps x | grep -c adb)
|
||||
set -l TAB \t
|
||||
# Don't run adb devices unless the server is already started - it takes a while to init
|
||||
if [ $count -gt 1 ]
|
||||
# The tail is to strip the header line, the sed is to massage the -l format
|
||||
# into a simple "identifier <TAB> modelname" format which is what we want for complete
|
||||
adb devices -l | tail -n +2 | sed -E -e "s/([^ ]+) +./\1$TAB/" -e "s/$TAB.*model:([^ ]+).*/$TAB\1/"
|
||||
end
|
||||
end
|
||||
|
||||
function __fish_adb_run_command --description 'Runs adb with any -s parameters already given on the command line'
|
||||
set -l sopt
|
||||
set -l sopt_is_next
|
||||
set -l cmd (commandline -poc)
|
||||
set -e cmd[1]
|
||||
for i in $cmd
|
||||
if test $sopt_is_next
|
||||
set sopt -s $i
|
||||
break
|
||||
else
|
||||
switch $i
|
||||
case -s
|
||||
set sopt_is_next 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# If no -s option, see if there's a -d or -e instead
|
||||
if test -z "$sopt"
|
||||
if contains -- -d $cmd
|
||||
set sopt '-d'
|
||||
else if contains -- -e $cmd
|
||||
set sopt '-e'
|
||||
end
|
||||
end
|
||||
|
||||
# adb returns CRLF (seemingly) so strip CRs
|
||||
adb $sopt shell $argv | sed s/\r//
|
||||
end
|
||||
|
||||
function __fish_adb_list_packages
|
||||
__fish_adb_run_command pm list packages | sed s/package://
|
||||
end
|
||||
|
||||
|
||||
function __fish_adb_list_uninstallable_packages
|
||||
# -3 doesn't exactly mean show uninstallable, but it's the closest you can get to with pm list
|
||||
__fish_adb_run_command pm list packages -3 | sed s/package://
|
||||
end
|
||||
|
||||
# Generic options, must come before command
|
||||
complete -n '__fish_adb_no_subcommand' -c adb -s s -x -a "(__fish_adb_get_devices)" -d 'Device to communicate with'
|
||||
complete -n '__fish_adb_no_subcommand' -c adb -s d -d 'Communicate with first USB device'
|
||||
complete -n '__fish_adb_no_subcommand' -c adb -s e -d 'Communicate with emulator'
|
||||
|
||||
# Commands
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'connect' -d 'Connect to device'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'disconnect' -d 'Disconnect from device'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'devices' -d 'List all connected devices'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'push' -d 'Copy file to device'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'pull' -d 'Copy file from device'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'sync' -d 'Copy host->device only if changed'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'shell' -d 'Run remote shell [command]'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'emu' -d 'Run emulator console command'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'logcat' -d 'View device log'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'install' -d 'Install package'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'uninstall' -d 'Uninstall package'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'jdwp' -d 'List PIDs of processes hosting a JDWP transport'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'forward' -d 'Port forwarding'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'bugreport' -d 'Return bugreport information'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'backup' -d 'Perform device backup'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'restore' -d 'Restore device from backup'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'version' -d 'Show adb version'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'help' -d 'Show adb help'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'wait-for-device' -d 'Block until device is online'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'start-server' -d 'Ensure that there is a server running'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'kill-server' -d 'Kill the server if it is running'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'remount' -d 'Remounts the /system partition on the device read-write'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'reboot' -d 'Reboots the device, optionally into the bootloader or recovery program'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'get-state' -d 'Prints state of the device'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'get-serialno' -d 'Prints serial number of the device'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'get-devpath' -d 'Prints device path'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'status-window' -d 'Continuously print the device status'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'root' -d 'Restart the adbd daemon with root permissions'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'usb' -d 'Restart the adbd daemon listening on USB'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'tcpip' -d 'Restart the adbd daemon listening on TCP'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'ppp' -d 'Run PPP over USB'
|
||||
|
||||
# install options
|
||||
complete -n '__fish_seen_subcommand_from install' -c adb -s l -d 'Forward-lock the app'
|
||||
complete -n '__fish_seen_subcommand_from install' -c adb -s r -d 'Reinstall the app keeping its data'
|
||||
complete -n '__fish_seen_subcommand_from install' -c adb -s s -d 'Install on SD card instead of internal storage'
|
||||
complete -n '__fish_seen_subcommand_from install' -c adb -l 'algo' -d 'Algorithm name'
|
||||
complete -n '__fish_seen_subcommand_from install' -c adb -l 'key' -d 'Hex-encoded key'
|
||||
complete -n '__fish_seen_subcommand_from install' -c adb -l 'iv' -d 'Hex-encoded iv'
|
||||
|
||||
# uninstall
|
||||
complete -n '__fish_seen_subcommand_from uninstall' -c adb -s k -d 'Keep the data and cache directories'
|
||||
complete -n '__fish_seen_subcommand_from uninstall' -c adb -f -u -a "(__fish_adb_list_uninstallable_packages)"
|
||||
|
||||
# devices
|
||||
complete -n '__fish_seen_subcommand_from devices' -c adb -s l -d 'Also list device qualifiers'
|
||||
|
||||
# disconnect
|
||||
complete -n '__fish_seen_subcommand_from disconnect' -c adb -x -a "(__fish_adb_get_devices)" -d 'Device to disconnect'
|
||||
|
||||
# backup
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -s f -d 'File to write backup data to'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'apk' -d 'Enable backup of the .apks themselves'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'noapk' -d 'Disable backup of the .apks themselves (default)'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'obb' -d 'Enable backup of any installed apk expansion'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'noobb' -d 'Disable backup of any installed apk expansion (default)'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'shared' -d 'Enable backup of the device\'s shared storage / SD card contents'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'noshared' -d 'Disable backup of the device\'s shared storage / SD card contents (default)'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'all' -d 'Back up all installed applications'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'system' -d 'Include system applications in -all (default)'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'nosystem' -d 'Exclude system applications in -all'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -f -a "(__fish_adb_list_packages)" -d 'Package(s) to backup'
|
||||
|
||||
# reboot
|
||||
complete -n '__fish_seen_subcommand_from reboot' -c adb -x -a 'bootloader recovery'
|
||||
|
||||
# forward
|
||||
complete -n '__fish_seen_subcommand_from forward' -c adb -l 'list' -d 'List all forward socket connections'
|
||||
complete -n '__fish_seen_subcommand_from forward' -c adb -l 'no-rebind' -d 'Fails the forward if local is already forwarded'
|
||||
complete -n '__fish_seen_subcommand_from forward' -c adb -l 'remove' -d 'Remove a specific forward socket connection'
|
||||
complete -n '__fish_seen_subcommand_from forward' -c adb -l 'remove-all' -d 'Remove all forward socket connections'
|
|
@ -30,6 +30,14 @@ function __fish_brew_outdated_formulas
|
|||
brew outdated
|
||||
end
|
||||
|
||||
function __fish_brew_pinned_formulas
|
||||
brew list --pinned
|
||||
end
|
||||
|
||||
function __fish_brew_taps
|
||||
brew tap
|
||||
end
|
||||
|
||||
|
||||
############
|
||||
# commands #
|
||||
|
@ -39,6 +47,15 @@ end
|
|||
complete -f -c brew -n '__fish_brew_needs_command' -a audit -d 'Check formula'
|
||||
complete -f -c brew -n '__fish_brew_using_command audit' -a '(__fish_brew_formulae)'
|
||||
|
||||
# bottle
|
||||
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a bottle -d 'Create a binary package'
|
||||
complete -f -c brew -n '__fish_brew_using_command bottle' -l 'homebrew-developer' -d 'Output developer debug information'
|
||||
complete -f -c brew -n '__fish_brew_using_command bottle' -l 'no-revision' -d 'Do not bump the bottle revision number'
|
||||
complete -f -c brew -n '__fish_brew_using_command bottle' -l 'rb' -d 'Write bottle block to a Ruby source file'
|
||||
complete -f -c brew -n '__fish_brew_using_command bottle' -l 'write' -d 'Write bottle block to formula file'
|
||||
complete -f -c brew -n '__fish_brew_using_command bottle' -l 'merge' -d 'Merge multiple bottle outputs'
|
||||
|
||||
# cat
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a cat -d 'Display formula'
|
||||
complete -f -c brew -n '__fish_brew_using_command cat' -a '(__fish_brew_formulae)'
|
||||
|
@ -46,8 +63,9 @@ complete -f -c brew -n '__fish_brew_using_command cat' -a '(__fish_brew_formulae
|
|||
# cleanup
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a cleanup -d 'Remove old installed versions'
|
||||
complete -f -c brew -n '__fish_brew_using_command cleanup' -l force -d 'Remove out-of-date keg-only brews as well'
|
||||
complete -f -c brew -n '__fish_brew_using_command cleanup' -s n -d 'Dry run'
|
||||
complete -f -c brew -n '__fish_brew_using_command cleanup' -s s -d 'Scrubs the cache'
|
||||
complete -f -c brew -n '__fish_brew_using_command cleanup' -l dry-run -d 'Show what files would be removed'
|
||||
complete -f -c brew -n '__fish_brew_using_command cleanup' -s n -d 'Show what files would be removed'
|
||||
complete -f -c brew -n '__fish_brew_using_command cleanup' -s s -d 'Scrub the cache'
|
||||
complete -f -c brew -n '__fish_brew_using_command cleanup' -a '(__fish_brew_installed_formulas)'
|
||||
|
||||
# create
|
||||
|
@ -55,6 +73,8 @@ complete -f -c brew -n '__fish_brew_needs_command' -a create -d 'Create new form
|
|||
complete -f -c brew -n '__fish_brew_using_command create' -l cmake -d 'Use template for CMake-style build'
|
||||
complete -f -c brew -n '__fish_brew_using_command create' -l autotools -d 'Use template for Autotools-style build'
|
||||
complete -f -c brew -n '__fish_brew_using_command create' -l no-fetch -d 'Don\'t download URL'
|
||||
complete -f -c brew -n '__fish_brew_using_command create' -l set-name -d 'Override name autodetection'
|
||||
complete -f -c brew -n '__fish_brew_using_command create' -l set-version -d 'Override version autodetection'
|
||||
|
||||
# deps
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a deps -d 'Show a formula\'s dependencies'
|
||||
|
@ -62,6 +82,7 @@ complete -f -c brew -n '__fish_brew_using_command deps' -l 1 -d 'Show only 1 lev
|
|||
complete -f -c brew -n '__fish_brew_using_command deps' -s n -d 'Show in topological order'
|
||||
complete -f -c brew -n '__fish_brew_using_command deps' -l tree -d 'Show dependencies as tree'
|
||||
complete -f -c brew -n '__fish_brew_using_command deps' -l all -d 'Show dependencies for all formulae'
|
||||
complete -f -c brew -n '__fish_brew_using_command deps' -l installed -d 'Show dependencies for installed formulae'
|
||||
complete -f -c brew -n '__fish_brew_using_command deps' -a '(__fish_brew_formulae)'
|
||||
|
||||
# diy
|
||||
|
@ -70,7 +91,10 @@ complete -f -c brew -n '__fish_brew_using_command diy' -l set-name -d 'Set name
|
|||
complete -f -c brew -n '__fish_brew_using_command diy' -l set-version -d 'Set version of package'
|
||||
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a 'doctor' -d 'Check your system for problems'
|
||||
|
||||
# edit
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a 'edit' -d 'Open brew/formula for editing'
|
||||
complete -f -c brew -n '__fish_brew_using_command edit' -a '(__fish_brew_formulae)'
|
||||
|
||||
# fetch
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a fetch -d 'Download source for formula'
|
||||
|
@ -78,6 +102,7 @@ complete -f -c brew -n '__fish_brew_using_command fetch' -l force -d 'Remove a p
|
|||
complete -f -c brew -n '__fish_brew_using_command fetch' -l HEAD -d 'Download the HEAD version from a VCS'
|
||||
complete -f -c brew -n '__fish_brew_using_command fetch' -l deps -d 'Also download dependencies'
|
||||
complete -f -c brew -n '__fish_brew_using_command fetch' -s v -d 'Make HEAD checkout verbose'
|
||||
complete -f -c brew -n '__fish_brew_using_command fetch' -l build-from-source -d 'Fetch source package instead of bottle'
|
||||
complete -f -c brew -n '__fish_brew_using_command fetch' -a '(__fish_brew_formulae)'
|
||||
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a 'help' -d 'Display help'
|
||||
|
@ -101,25 +126,42 @@ complete -f -c brew -n '__fish_brew_using_command install' -l fresh -d 'Don\'t r
|
|||
complete -f -c brew -n '__fish_brew_using_command install' -l use-clang -d 'Attempt to compile using clang'
|
||||
complete -f -c brew -n '__fish_brew_using_command install' -l use-gcc -d 'Attempt to compile using GCC'
|
||||
complete -f -c brew -n '__fish_brew_using_command install' -l use-llvm -d 'Attempt to compile using the LLVM'
|
||||
complete -f -c brew -n '__fish_brew_using_command install' -l cc -a "clang gcc-4.0 gcc-4.2 gcc-4.3 gcc-4.4 gcc-4.5 gcc-4.6 gcc-4.7 gcc-4.8 gcc-4.9 llvm-gcc" -d 'Attempt to compile using the specified compiler'
|
||||
complete -f -c brew -n '__fish_brew_using_command install' -l build-from-source -d 'Compile from source even if a bottle is provided'
|
||||
complete -f -c brew -n '__fish_brew_using_command install' -l devel -d 'Install the development version of formula'
|
||||
complete -f -c brew -n '__fish_brew_using_command install' -l HEAD -d 'Install the HEAD version from VCS'
|
||||
complete -f -c brew -n '__fish_brew_using_command install' -l interactive -d 'Download and patch formula, then open a shell'
|
||||
complete -f -c brew -n '__fish_brew_using_command install' -l env -a "std super" -d 'Force the specified build environment'
|
||||
complete -f -c brew -n '__fish_brew_using_command install' -l build-bottle -d 'Optimize for a generic CPU architecture'
|
||||
complete -f -c brew -n '__fish_brew_using_command install' -l bottle-arch -a 'core core2 penryn g3 g4 g4e g5' -d 'Optimize for the specified CPU architecture'
|
||||
complete -c brew -n '__fish_brew_using_command install' -a '(__fish_brew_formulae)'
|
||||
|
||||
# link
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a 'link ln' -d 'Symlink installed formula'
|
||||
complete -f -c brew -n '__fish_brew_using_command link' -l overwrite -d 'Overwrite existing files'
|
||||
complete -f -c brew -n '__fish_brew_using_command ln' -l overwrite -d 'Overwrite existing files'
|
||||
complete -f -c brew -n '__fish_brew_using_command link' -l dry-run -d 'Show what files would be linked or overwritten'
|
||||
complete -f -c brew -n '__fish_brew_using_command ln' -l dry-run -d 'Show what files would be linked or overwritten'
|
||||
complete -f -c brew -n '__fish_brew_using_command link' -l force -d 'Allow keg-only formulae to be linked'
|
||||
complete -f -c brew -n '__fish_brew_using_command ln' -l force -d 'Allow keg-only formulae to be linked'
|
||||
complete -f -c brew -n '__fish_brew_using_command link' -a '(__fish_brew_installed_formulas)'
|
||||
complete -f -c brew -n '__fish_brew_using_command ln' -a '(__fish_brew_installed_formulas)'
|
||||
|
||||
# linkapps
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a linkapps -d 'Symlink .app bundles into /Applications'
|
||||
complete -f -c brew -n '__fish_brew_using_command linkapps' -l local -d 'Link .app bundles into ~/Applications instead'
|
||||
|
||||
# list
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a 'list ls' -d 'List all installed formula'
|
||||
complete -f -c brew -n '__fish_brew_using_command list' -l unbrewed -d 'List all files in the Homebrew prefix not installed by brew'
|
||||
complete -f -c brew -n '__fish_brew_using_command list' -l versions -d 'Show the version number'
|
||||
complete -f -c brew -n '__fish_brew_using_command list' -l pinned -d 'Show the versions of pinned formulae'
|
||||
complete -c brew -n '__fish_brew_using_command list' -a '(__fish_brew_formulae)'
|
||||
|
||||
#ls
|
||||
complete -f -c brew -n '__fish_brew_using_command ls' -l unbrewed -d 'List all files in the Homebrew prefix not installed by brew'
|
||||
complete -f -c brew -n '__fish_brew_using_command ls' -l versions -d 'Show the version number'
|
||||
complete -f -c brew -n '__fish_brew_using_command ls' -l pinned -d 'Show the versions of pinned formulae'
|
||||
complete -c brew -n '__fish_brew_using_command ls' -a '(__fish_brew_formulae)'
|
||||
|
||||
# log
|
||||
|
@ -132,12 +174,19 @@ complete -c brew -n '__fish_brew_using_command missing' -a '(__fish_brew_formula
|
|||
|
||||
# options
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a options -d 'Display install options for formula'
|
||||
complete -f -c brew -n '__fish_brew_using_command options' -l compact -d 'Show all options as a space-delimited list'
|
||||
complete -f -c brew -n '__fish_brew_using_command options' -l all -d 'Show options for all formulae'
|
||||
complete -f -c brew -n '__fish_brew_using_command options' -l installed -d 'Show options for all installed formulae'
|
||||
complete -c brew -n '__fish_brew_using_command options' -a '(__fish_brew_formulae)' -d 'formula'
|
||||
|
||||
# outdated
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a outdated -d 'Show formula that have updated versions'
|
||||
complete -f -c brew -n '__fish_brew_using_command outdated' -l quiet -d 'Display only names'
|
||||
|
||||
# pin
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a pin -d 'Pin the specified formulae to their current versions'
|
||||
complete -f -c brew -n '__fish_brew_using_command pin' -a '(__fish_brew_installed_formulas)' -d 'formula'
|
||||
|
||||
# prune
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a prune -d 'Remove dead symlinks'
|
||||
|
||||
|
@ -148,12 +197,17 @@ complete -f -c brew -n '__fish_brew_using_command search' -l fink -d 'Search on
|
|||
complete -f -c brew -n '__fish_brew_using_command -S' -l macports -d 'Search on MacPorts'
|
||||
complete -f -c brew -n '__fish_brew_using_command -S' -l fink -d 'Search on Fink'
|
||||
|
||||
# sh
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a sh -d 'Instantiate a Homebrew build enviornment'
|
||||
complete -f -c brew -n '__fish_brew_using_command sh' -l env=std -d 'Use stdenv instead of superenv'
|
||||
|
||||
# tap
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a tap -d 'Tap a new formula repository on GitHub'
|
||||
complete -f -c brew -n '__fish_brew_using_command tap' -l repair -d 'Create and prune tap symlinks as appropriate'
|
||||
|
||||
# test
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a test -d 'Run tests for formula'
|
||||
complete -c brew -n '__fish_brew_using_command test' -a '(__fish_brew_formulae)' -d 'formula'
|
||||
complete -f -c brew -n '__fish_brew_using_command test' -a '(__fish_brew_installed_formulas)' -d 'formula'
|
||||
|
||||
# uninstall
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a 'uninstall remove rm' -d 'Uninstall formula'
|
||||
|
@ -166,10 +220,19 @@ complete -f -c brew -n '__fish_brew_using_command rm' -l force -d 'Delete all in
|
|||
|
||||
# unlink
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a unlink -d 'Unlink formula'
|
||||
complete -c brew -n '__fish_brew_using_command unlink' -a '(__fish_brew_installed_formulas)'
|
||||
complete -f -c brew -n '__fish_brew_using_command unlink' -a '(__fish_brew_installed_formulas)'
|
||||
|
||||
# unlinkapps
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a unlinkapps -d 'Remove links created by brew linkapps'
|
||||
complete -f -c brew -n '__fish_brew_using_command unlinkapps' -l local -d 'Remove links from ~/Applications created by brew linkapps'
|
||||
|
||||
# unpin
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a unpin -d 'Unpin specified formulae'
|
||||
complete -f -c brew -n '__fish_brew_using_command unpin' -a '(__fish_brew_pinned_formulas)'
|
||||
|
||||
# untap
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a untap -d 'Remove a tapped repository'
|
||||
complete -f -c brew -n '__fish_brew_using_command untap' -a '(__fish_brew_taps)'
|
||||
|
||||
# update
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a update -d 'Fetch newest version of Homebrew and formulas'
|
||||
|
@ -182,6 +245,7 @@ complete -f -c brew -n '__fish_brew_using_command upgrade' -a '(__fish_brew_outd
|
|||
# uses
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a uses -d 'Show formulas that depend on specified formula'
|
||||
complete -f -c brew -n '__fish_brew_using_command uses' -l installed -d 'List only installed formulae'
|
||||
complete -f -c brew -n '__fish_brew_using_command uses' -l recursive -d 'Resolve more than one level of dependencies'
|
||||
complete -c brew -n '__fish_brew_using_command uses' -a '(__fish_brew_formulae)'
|
||||
|
||||
# versions
|
||||
|
@ -194,6 +258,7 @@ complete -c brew -n '__fish_brew_using_command versions' -a '(__fish_brew_formul
|
|||
# switches #
|
||||
############
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -a '-v --version' -d 'Print version number of brew'
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -l env -x -d 'Show Homebrew a summary of the build environment'
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -l repository -x -d 'Display where Homebrew\'s .git directory is located'
|
||||
complete -f -c brew -n '__fish_brew_needs_command' -l config -x -d 'Show Homebrew and system configuration'
|
||||
|
||||
|
|
74
share/completions/eselect.fish
Normal file
74
share/completions/eselect.fish
Normal file
|
@ -0,0 +1,74 @@
|
|||
function __fish_eselect_cmd
|
||||
eselect --brief --colour=no $argv
|
||||
end
|
||||
|
||||
function __fish_complete_eselect_modules
|
||||
set -l sedregexp 's/^ ([a-zA-Z0-9_-]*)[ ]*/\1\t/g'
|
||||
__fish_eselect_cmd modules list | sgrep '^ ' | sed -r $sedregexp
|
||||
end
|
||||
|
||||
function __fish_complete_eselect_actions
|
||||
set -l sedregexp 's/^ ([a-zA-Z0-9_-]*)[ ]*/\1\t/g'
|
||||
set -l cmdl (commandline -poc)
|
||||
__fish_eselect_cmd $cmdl[2..-1] usage | sgrep '^ [^ -]' | sed -r $sedregexp
|
||||
end
|
||||
|
||||
function __fish_complete_eselect_action_options
|
||||
set -l parseregexp 's/^ ([a-zA-Z0-9_-]*)[ ]*/\1\t/g'
|
||||
set -l cmdl (commandline -poc)
|
||||
|
||||
# Disable further php completion
|
||||
if [ (__fish_print_cmd_args_without_options)[2] = 'php' ]
|
||||
return
|
||||
end
|
||||
|
||||
switch $cmdl[-1]
|
||||
case -'*'
|
||||
return
|
||||
end
|
||||
|
||||
set -l findregexp '/^ '$cmdl[-1]'/,/^ [^ ]/p'
|
||||
|
||||
set cmdl[-1] usage
|
||||
__fish_eselect_cmd $cmdl[2..-1] | sed -n -re $findregexp | sgrep '^ --' | sed -re $parseregexp
|
||||
end
|
||||
|
||||
function __fish_complete_eselect_targets
|
||||
set -l sedregexp 's/^ \[([0-9]+)\][ ]*/\1\t/g'
|
||||
set -l cmdl (commandline -poc)
|
||||
|
||||
# Disable further php completion
|
||||
# https://github.com/fish-shell/fish-shell/pull/1131
|
||||
if [ (__fish_print_cmd_args_without_options)[2] = 'php' ]
|
||||
return
|
||||
end
|
||||
|
||||
switch $cmdl[-1]
|
||||
case -'*'
|
||||
set cmdl[-2] list
|
||||
case '*'
|
||||
set cmdl[-1] list
|
||||
end
|
||||
|
||||
eselect --colour=no $cmdl[2..-1] | sgrep '^ [^ -]' | sed -r $sedregexp
|
||||
end
|
||||
|
||||
complete -c eselect -n "test (__fish_number_of_cmd_args_wo_opts) = 1" \
|
||||
-xa '(__fish_complete_eselect_modules)'
|
||||
|
||||
complete -c eselect -n "test (__fish_number_of_cmd_args_wo_opts) = 1" \
|
||||
-l brief -d 'Make output shorter'
|
||||
|
||||
complete -c eselect -n "test (__fish_number_of_cmd_args_wo_opts) = 1" \
|
||||
-l colour \
|
||||
-d "=<yes|no|auto> Enable or disable colour output (default 'auto')"
|
||||
|
||||
complete -c eselect -n "test (__fish_number_of_cmd_args_wo_opts) = 2" \
|
||||
-xa '(__fish_complete_eselect_actions)'
|
||||
|
||||
complete -c eselect -n "test (__fish_number_of_cmd_args_wo_opts) = 3" \
|
||||
-xa '(__fish_complete_eselect_targets)'
|
||||
|
||||
complete -c eselect -n "test (__fish_number_of_cmd_args_wo_opts) = 3" \
|
||||
-xa '(__fish_complete_eselect_action_options)'
|
||||
|
|
@ -19,7 +19,11 @@ function __fish_git_remotes
|
|||
end
|
||||
|
||||
function __fish_git_modified_files
|
||||
command git status -s | grep -e "^ M" | sed "s/^ M //"
|
||||
command git ls-files -m --exclude-standard ^/dev/null
|
||||
end
|
||||
|
||||
function __fish_git_add_files
|
||||
command git ls-files -mo --exclude-standard ^/dev/null
|
||||
end
|
||||
|
||||
function __fish_git_ranges
|
||||
|
@ -110,12 +114,14 @@ complete -c git -n '__fish_git_using_command add' -l refresh -d "Don't add the f
|
|||
complete -c git -n '__fish_git_using_command add' -l ignore-errors -d 'Ignore errors'
|
||||
complete -c git -n '__fish_git_using_command add' -l ignore-missing -d 'Check if any of the given files would be ignored'
|
||||
complete -f -c git -n '__fish_git_using_command add; and __fish_contains_opt -s p patch' -a '(__fish_git_modified_files)'
|
||||
complete -f -c git -n '__fish_git_using_command add' -a '(__fish_git_add_files)'
|
||||
# TODO options
|
||||
|
||||
### checkout
|
||||
complete -f -c git -n '__fish_git_needs_command' -a checkout -d 'Checkout and switch to a branch'
|
||||
complete -f -c git -n '__fish_git_using_command checkout' -a '(__fish_git_branches)' --description 'Branch'
|
||||
complete -f -c git -n '__fish_git_using_command checkout' -a '(__fish_git_tags)' --description 'Tag'
|
||||
complete -f -c git -n '__fish_git_using_command checkout' -a '(__fish_git_modified_files)' --description 'File'
|
||||
complete -f -c git -n '__fish_git_using_command checkout' -s b -d 'Create a new branch'
|
||||
complete -f -c git -n '__fish_git_using_command checkout' -s t -l track -d 'Track a new branch'
|
||||
# TODO options
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# Completions for the modprobe command
|
||||
#
|
||||
|
||||
complete -c modprobe -d Module -a "(/sbin/modprobe -l | sed -e 's/\/.*\/\([^\/.]*\).*/\1/')"
|
||||
complete -c modprobe --no-files -d Module -a "(find /lib/modules/(uname -r)/kernel -type f | sed -e 's/\/.*\/\([^\/.]*\).*/\1/')"
|
||||
complete -c modprobe -s v -l verbose --description "Print messages about what the program is doing"
|
||||
complete -c modprobe -s C -l config --description "Configuration file" -r
|
||||
complete -c modprobe -s c -l showconfig --description "Dump configuration file"
|
||||
|
|
|
@ -2,7 +2,7 @@ begin
|
|||
set -l unicode 'commandline | sgrep -qe "-[a-zA-Z]*C[a-zA-Z]*\$"'
|
||||
set -l noopt 'commandline | not sgrep -qe "-[a-zA-Z]*C[a-zA-Z]*\$"'
|
||||
set -l modules "(find (perl -lE'print for @INC') -name '*.pm' -printf '%P\n' \
|
||||
| awk '{ gsub(\"/\", \"::\") } !/-/' RS=.pm\n | sort | uniq)"
|
||||
| awk '{ gsub(\"/\", \"::\") } /[^-.]/' RS=.pm\n | sort | uniq)"
|
||||
complete -c perl -s 0 -n $noopt --description 'Specify record separator'
|
||||
complete -c perl -s a -n $noopt --description 'Turn on autosplit mode'
|
||||
complete -c perl -s c -n $noopt --description 'Check syntax'
|
||||
|
|
20
share/completions/rc-service.fish
Normal file
20
share/completions/rc-service.fish
Normal file
|
@ -0,0 +1,20 @@
|
|||
# First argument is the names of the service, i.e. a file in /etc/init.d
|
||||
complete -c rc-service -n "test (__fish_number_of_cmd_args_wo_opts) = 1" \
|
||||
-xa "(__fish_print_service_names)" --description "Service name"
|
||||
|
||||
# The second argument is what action to take with the service
|
||||
complete -c rc-service -n "test (__fish_number_of_cmd_args_wo_opts) -gt 1" \
|
||||
-xa "(__fish_complete_service_actions)"
|
||||
|
||||
# Complete rc-service the options
|
||||
complete -c rc-service -s e -l exists -d 'Tests if the service exists or not'
|
||||
complete -c rc-service -s i -l ifexists \
|
||||
-d 'If the service exists, then run the command'
|
||||
complete -c rc-service -s l -l list -d 'List all available services'
|
||||
complete -c rc-service -s r -l resolve \
|
||||
-d 'Resolve the service name to an init script'
|
||||
complete -c rc-service -s h -l help -d 'Display the help output'
|
||||
complete -c rc-service -s C -l nocolor -d 'Disable color output'
|
||||
complete -c rc-service -s V -l version -d 'Display software version'
|
||||
complete -c rc-service -s v -l verbose -d 'Run verbosely'
|
||||
complete -c rc-service -s q -l quiet -d 'Run quietly (Does not affect errors)'
|
33
share/completions/rc-update.fish
Normal file
33
share/completions/rc-update.fish
Normal file
|
@ -0,0 +1,33 @@
|
|||
function __fish_complete_rc-update_actions
|
||||
set -l actions add \
|
||||
'Add the service to the runlevel or the current one if non given'
|
||||
set -l actions $actions del \
|
||||
'Delete the service from the runlevel or the current one if non given'
|
||||
set -l actions $actions show \
|
||||
'Show all enabled services and the runlevels they belong to'
|
||||
printf "%s\t%s\n" $actions
|
||||
end
|
||||
|
||||
function __fish_complete_rc-update_runlevels
|
||||
set -l levels sysinit \
|
||||
'First startup runlevel' \
|
||||
boot \
|
||||
'Second startup runlevel' \
|
||||
default \
|
||||
'Last startup runlevel' \
|
||||
shutdown \
|
||||
'Runlevel for stutting down'
|
||||
printf "%s\t%s\n" $levels
|
||||
end
|
||||
|
||||
# The first argument is what action to take with the service
|
||||
complete -c rc-update -n "test (__fish_number_of_cmd_args_wo_opts) = 1" \
|
||||
-xa "(__fish_complete_rc-update_actions)"
|
||||
|
||||
# The second argument is the names of the service, i.e. a file in /etc/init.d
|
||||
complete -c rc-update -n "test (__fish_number_of_cmd_args_wo_opts) = 2" \
|
||||
-xa "(__fish_print_service_names)" --description "Service name"
|
||||
|
||||
# The third argument is the names of the service, i.e. a file in /etc/init.d
|
||||
complete -c rc-update -n "test (__fish_number_of_cmd_args_wo_opts) = 3" \
|
||||
-xa "(__fish_complete_rc-update_runlevels)"
|
|
@ -31,7 +31,7 @@ complete -c scp -d "Remote Path" -n "commandline -ct|sgrep -o '.*:'" -a "
|
|||
commandline -ct|sgrep -o '.*:'
|
||||
)(
|
||||
#Get the list of remote files from the specified ssh server
|
||||
ssh -o \"BatchMode yes\" (commandline -ct|sed -ne 's/\(.*\):.*/\1/p') ls\ -dp\ (commandline -ct|sed -ne 's/.*://p')\* 2> /dev/null
|
||||
ssh (commandline -c|sgrep -o '\-P [0-9]*'|tr P p) -o \"BatchMode yes\" (commandline -ct|sed -ne 's/\(.*\):.*/\1/p') ls\ -dp\ (commandline -ct|sed -ne 's/.*://p')\* 2> /dev/null
|
||||
)
|
||||
|
||||
"
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
function __fish_service_print_names
|
||||
if type -f systemctl >/dev/null
|
||||
command systemctl list-units -t service | cut -d ' ' -f 1 | grep '\.service$' | sed -e 's/\.service$//'
|
||||
end
|
||||
|
||||
command ls /etc/init.d
|
||||
end
|
||||
|
||||
# Fist argument is the names of the service, i.e. a file in /etc/init.d
|
||||
complete -c service -n "test (count (commandline -poc)) = 1" -xa "(__fish_service_print_names)" --description "Service name"
|
||||
complete -c service -n "test (count (commandline -poc)) = 1" -xa "(__fish_print_service_names)" --description "Service name"
|
||||
|
||||
#The second argument is what action to take with the service
|
||||
complete -c service -n "test (count (commandline -poc)) -gt 1" -xa '$__fish_service_commands'
|
||||
|
|
1
share/completions/source.fish
Normal file
1
share/completions/source.fish
Normal file
|
@ -0,0 +1 @@
|
|||
complete -c . -x -a "(__fish_complete_suffix .fish)"
|
|
@ -30,9 +30,13 @@ function __fish_complete_cd -d "Completions for the cd command"
|
|||
for i in $mycdpath
|
||||
# Move to the initial directory first,
|
||||
# in case the CDPATH directory is relative
|
||||
|
||||
builtin cd $wd
|
||||
builtin cd $i
|
||||
builtin cd $wd ^/dev/null
|
||||
builtin cd $i ^/dev/null
|
||||
|
||||
if test $status -ne 0
|
||||
# directory does not exists or missing permission
|
||||
continue
|
||||
end
|
||||
|
||||
# What we would really like to do is skip descriptions if all
|
||||
# valid paths are in the same directory, but we don't know how to
|
||||
|
@ -45,5 +49,5 @@ function __fish_complete_cd -d "Completions for the cd command"
|
|||
end
|
||||
end
|
||||
|
||||
builtin cd $wd
|
||||
builtin cd $wd ^/dev/null
|
||||
end
|
||||
|
|
|
@ -21,7 +21,33 @@ function __fish_complete_man
|
|||
set section $section"[^)]*"
|
||||
|
||||
# Do the actual search
|
||||
apropos (commandline -ct) ^/dev/null | sgrep \^(commandline -ct) | sed -n -e 's/\([^ ]*\).*(\('$section'\)) *- */\1'\t'\2: /p'
|
||||
apropos (commandline -ct) ^/dev/null | awk '
|
||||
BEGIN { FS="[\t ]- "; OFS="\t"; }
|
||||
# BSD/Darwin
|
||||
/^[^( \t]+\('$section'\)/ {
|
||||
split($1, pages, ", ");
|
||||
for (i in pages) {
|
||||
page = pages[i];
|
||||
sub(/[ \t]+/, "", page);
|
||||
paren = index(page, "(");
|
||||
name = substr(page, 1, paren - 1);
|
||||
sect = substr(page, paren + 1, length(page) - paren - 1);
|
||||
print name, sect ": " $2;
|
||||
}
|
||||
}
|
||||
# Linux
|
||||
/^[^( \t]+ \('$section'\)/ {
|
||||
split($1, t, " ");
|
||||
sect = substr(t[2], 2, length(t[2]) - 2);
|
||||
print t[1], sect ": " $2;
|
||||
}
|
||||
# Solaris
|
||||
/^[^( \t]+\t+[^\(\t]/ {
|
||||
split($1, t, " ");
|
||||
sect = substr(t[3], 2, length(t[3]) - 2);
|
||||
print t[2], sect ": " $2;
|
||||
}
|
||||
'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
7
share/functions/__fish_complete_service_actions.fish
Normal file
7
share/functions/__fish_complete_service_actions.fish
Normal file
|
@ -0,0 +1,7 @@
|
|||
function __fish_complete_service_actions -d "Print a list of all basic service \
|
||||
actions"
|
||||
set -l actions start 'Start the service'
|
||||
set -l actions $actions stop 'Stop the service'
|
||||
set -l actions $actions restart 'Restart the service'
|
||||
printf "%s\t%s\n" $actions
|
||||
end
|
|
@ -137,6 +137,15 @@ function __fish_config_interactive -d "Initializations that should be performed
|
|||
|
||||
end
|
||||
|
||||
#
|
||||
# Generate man page completions if not present
|
||||
#
|
||||
|
||||
if not test -d $configdir/fish/generated_completions
|
||||
#fish_update_completions is a function, so it can not be directly run in background.
|
||||
eval "$__fish_bin_dir/fish -c 'fish_update_completions > /dev/null ^/dev/null' &"
|
||||
end
|
||||
|
||||
#
|
||||
# Print a greeting
|
||||
#
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# Written by Kevin Ballard <kevin@sb.org>
|
||||
# Updated by Brian Gernhardt <brian@gernhardtsoftware.com>
|
||||
#
|
||||
#
|
||||
# This is heavily based off of the git-prompt.bash script that ships with
|
||||
# git, which is Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>.
|
||||
# The act of porting the code, along with any new code, are Copyright (C) 2012
|
||||
|
@ -51,6 +51,7 @@
|
|||
# __fish_git_prompt_showupstream to a space-separated list of values:
|
||||
#
|
||||
# verbose show number of commits ahead/behind (+/-) upstream
|
||||
# name if verbose, then also show the upstream abbrev name
|
||||
# informative similar to verbose, but shows nothing when equal (fish only)
|
||||
# legacy don't use the '--count' option available in recent versions
|
||||
# of git-rev-list
|
||||
|
@ -155,7 +156,8 @@
|
|||
#
|
||||
# The separator before the upstream information can be customized via
|
||||
# __fish_git_prompt_char_upstream_prefix. It is colored like the rest of
|
||||
# the upstream information. It defaults to nothing ().
|
||||
# the upstream information. It normally defaults to nothing () and defaults
|
||||
# to a space ( ) when __fish_git_prompt_showupstream contains verbose.
|
||||
#
|
||||
#
|
||||
# Turning on __fish_git_prompt_showcolorhints changes the colors as follows to
|
||||
|
@ -178,6 +180,7 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
|
|||
set -l upstream git
|
||||
set -l legacy
|
||||
set -l verbose
|
||||
set -l name
|
||||
|
||||
# Default to informative if show_informative_status is set
|
||||
if test -n "$__fish_git_prompt_show_informative_status"
|
||||
|
@ -202,7 +205,7 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
|
|||
set upstream svn+git # default upstream is SVN if available, else git
|
||||
|
||||
# Save the config key (without .url) for later use
|
||||
set -l remote_prefix (/bin/sh -c 'echo "${1%.url}"' -- $key)
|
||||
set -l remote_prefix (echo $key | sed 's/\.url$//')
|
||||
set svn_prefix $svn_prefix $remote_prefix
|
||||
end
|
||||
end
|
||||
|
@ -222,6 +225,8 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
|
|||
case legacy
|
||||
set legacy 1
|
||||
set -e informative
|
||||
case name
|
||||
set name 1
|
||||
case none
|
||||
return
|
||||
end
|
||||
|
@ -237,11 +242,11 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
|
|||
set -l svn_upstream (git log --first-parent -1 --grep="^git-svn-id: \($svn_url_pattern\)" ^/dev/null)
|
||||
if test (count $svn_upstream) -ne 0
|
||||
echo $svn_upstream[-1] | read -l _ svn_upstream _
|
||||
set svn_upstream (/bin/sh -c 'echo "${1%@*}"' -- $svn_upstream)
|
||||
set svn_upstream (echo $svn_upstream | sed 's/@.*//')
|
||||
set -l cur_prefix
|
||||
for i in (seq (count $svn_remote))
|
||||
set -l remote $svn_remote[$i]
|
||||
set -l mod_upstream (/bin/sh -c 'echo "${1#$2}"' -- $svn_upstream $remote)
|
||||
set -l mod_upstream (echo $svn_upstream | sed "s|$remote||")
|
||||
if test "$svn_upstream" != "$mod_upstream"
|
||||
# we found a valid remote
|
||||
set svn_upstream $mod_upstream
|
||||
|
@ -258,14 +263,14 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
|
|||
set upstream git-svn
|
||||
end
|
||||
else
|
||||
set upstream (/bin/sh -c 'val=${1#/branches}; echo "${val#/}"' -- $svn_upstream)
|
||||
set upstream (echo $svn_upstream | sed 's|/branches||; s|/||g')
|
||||
|
||||
# Use fetch config to fix upstream
|
||||
set -l fetch_val (command git config "$cur_prefix".fetch)
|
||||
if test -n "$fetch_val"
|
||||
set -l IFS :
|
||||
echo "$fetch_val" | read -l trunk pattern
|
||||
set upstream (/bin/sh -c 'echo "${1%/$2}"' -- $pattern $trunk)/$upstream
|
||||
set upstream (echo $pattern | sed -e "s|/$trunk\$||") /$upstream
|
||||
end
|
||||
end
|
||||
else if test $upstream = svn+git
|
||||
|
@ -291,17 +296,27 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
|
|||
|
||||
# calculate the result
|
||||
if test -n "$verbose"
|
||||
# Verbose has a space by default
|
||||
set -l prefix "$___fish_git_prompt_char_upstream_prefix"
|
||||
# Using two underscore version to check if user explicitly set to nothing
|
||||
if not set -q __fish_git_prompt_char_upstream_prefix
|
||||
set -l prefix " "
|
||||
end
|
||||
|
||||
echo $count | read -l behind ahead
|
||||
switch "$count"
|
||||
case '' # no upstream
|
||||
case "0 0" # equal to upstream
|
||||
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_equal"
|
||||
echo "$prefix$___fish_git_prompt_char_upstream_equal"
|
||||
case "0 *" # ahead of upstream
|
||||
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead"
|
||||
echo "$prefix$___fish_git_prompt_char_upstream_ahead$ahead"
|
||||
case "* 0" # behind upstream
|
||||
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind"
|
||||
echo "$prefix$___fish_git_prompt_char_upstream_behind$behind"
|
||||
case '*' # diverged from upstream
|
||||
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_diverged$ahead-$behind"
|
||||
echo "$prefix$___fish_git_prompt_char_upstream_diverged$ahead-$behind"
|
||||
end
|
||||
if test -n "$count" -a -n "$name"
|
||||
echo " "(command git rev-parse --abbrev-ref "$upstream" ^/dev/null)
|
||||
end
|
||||
else if test -n "$informative"
|
||||
echo $count | read -l behind ahead
|
||||
|
@ -356,6 +371,7 @@ function __fish_git_prompt --description "Prompt function for Git"
|
|||
set -l informative_status
|
||||
|
||||
__fish_git_prompt_validate_chars
|
||||
__fish_git_prompt_validate_colors
|
||||
|
||||
if test "true" = $inside_worktree
|
||||
if test -n "$__fish_git_prompt_show_informative_status"
|
||||
|
@ -388,8 +404,6 @@ function __fish_git_prompt --description "Prompt function for Git"
|
|||
end
|
||||
end
|
||||
|
||||
__fish_git_prompt_validate_colors
|
||||
|
||||
set -l branch_color $___fish_git_prompt_color_branch
|
||||
set -l branch_done $___fish_git_prompt_color_branch_done
|
||||
if test -n "$__fish_git_prompt_showcolorhints"
|
||||
|
@ -411,7 +425,7 @@ function __fish_git_prompt --description "Prompt function for Git"
|
|||
if test -n "$u"
|
||||
set u "$___fish_git_prompt_color_untrackedfiles$u$___fish_git_prompt_color_untrackedfiles_done"
|
||||
end
|
||||
set b (/bin/sh -c 'echo "${1#refs/heads/}"' -- $b)
|
||||
set b (echo $b | sed 's|refs/heads/||')
|
||||
if test -n "$b"
|
||||
set b "$branch_color$b$branch_done"
|
||||
end
|
||||
|
@ -657,21 +671,12 @@ function __fish_git_prompt_set_color
|
|||
set default_done "$argv[3]"
|
||||
end
|
||||
|
||||
if test (count $user_variable) -eq 2
|
||||
set user_variable_bright $user_variable[2]
|
||||
set user_variable $user_variable[1]
|
||||
end
|
||||
|
||||
set -l variable _$user_variable_name
|
||||
set -l variable_done "$variable"_done
|
||||
|
||||
if not set -q $variable
|
||||
if test -n "$user_variable"
|
||||
if test -n "$user_variable_bright"
|
||||
set -g $variable (set_color --bold $user_variable)
|
||||
else
|
||||
set -g $variable (set_color $user_variable)
|
||||
end
|
||||
set -g $variable (set_color $user_variable)
|
||||
set -g $variable_done (set_color normal)
|
||||
else
|
||||
set -g $variable $default
|
||||
|
|
4
share/functions/__fish_number_of_cmd_args_wo_opts.fish
Normal file
4
share/functions/__fish_number_of_cmd_args_wo_opts.fish
Normal file
|
@ -0,0 +1,4 @@
|
|||
function __fish_number_of_cmd_args_wo_opts
|
||||
count (__fish_print_cmd_args_without_options)
|
||||
end
|
||||
|
3
share/functions/__fish_print_cmd_args.fish
Normal file
3
share/functions/__fish_print_cmd_args.fish
Normal file
|
@ -0,0 +1,3 @@
|
|||
function __fish_print_cmd_args
|
||||
commandline -poc
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
function __fish_print_cmd_args_without_options
|
||||
__fish_print_cmd_args | grep '^[^-]'
|
||||
end
|
10
share/functions/__fish_print_service_names.fish
Normal file
10
share/functions/__fish_print_service_names.fish
Normal file
|
@ -0,0 +1,10 @@
|
|||
function __fish_print_service_names -d 'All services known to the system'
|
||||
if type -f systemctl >/dev/null
|
||||
command systemctl list-units -t service | cut -d ' ' -f 1 | grep '\.service$' | sed -e 's/\.service$//'
|
||||
else if type -f rc-service
|
||||
command rc-service -l
|
||||
else
|
||||
command ls /etc/init.d
|
||||
end
|
||||
end
|
||||
|
|
@ -32,6 +32,12 @@ function fish_default_key_bindings -d "Default (Emacs-like) key bindings for fis
|
|||
bind \e\[H beginning-of-line
|
||||
bind \e\[F end-of-line
|
||||
|
||||
# for PuTTY
|
||||
# https://github.com/fish-shell/fish-shell/issues/180
|
||||
bind \e\[1~ beginning-of-line
|
||||
bind \e\[3~ delete-char
|
||||
bind \e\[4~ end-of-line
|
||||
|
||||
# OS X SnowLeopard doesn't have these keys. Don't show an annoying error message.
|
||||
bind -k home beginning-of-line 2> /dev/null
|
||||
bind -k end end-of-line 2> /dev/null
|
||||
|
@ -79,8 +85,8 @@ function fish_default_key_bindings -d "Default (Emacs-like) key bindings for fis
|
|||
bind \ef forward-word
|
||||
bind \e\[1\;5C forward-word
|
||||
bind \e\[1\;5D backward-word
|
||||
bind \e\[1\;9A history-token-search-backward # iTerm2
|
||||
bind \e\[1\;9B history-token-search-forward # iTerm2
|
||||
bind \e\[1\;9A history-token-search-backward # iTerm2
|
||||
bind \e\[1\;9B history-token-search-forward # iTerm2
|
||||
bind \e\[1\;9C forward-word #iTerm2
|
||||
bind \e\[1\;9D backward-word #iTerm2
|
||||
bind \ed forward-kill-word
|
||||
|
@ -99,6 +105,9 @@ function fish_default_key_bindings -d "Default (Emacs-like) key bindings for fis
|
|||
bind \ed 'set -l cmd (commandline); if test -z "$cmd"; echo; dirh; commandline -f repaint; else; commandline -f kill-word; end'
|
||||
bind \cd delete-or-exit
|
||||
|
||||
# Allow reading manpages by pressing F1
|
||||
bind -k f1 'man (basename (commandline -po; echo))[1] ^/dev/null; or echo -n \a'
|
||||
|
||||
# This will make sure the output of the current command is paged using the less pager when you press Meta-p
|
||||
bind \ep '__fish_paginate'
|
||||
|
||||
|
|
|
@ -117,22 +117,29 @@ function type --description "Print the type of a command"
|
|||
|
||||
end
|
||||
|
||||
set -l path (which $i ^/dev/null)
|
||||
if test -x (echo $path)
|
||||
set res 0
|
||||
set found 1
|
||||
switch $mode
|
||||
case normal
|
||||
printf (_ '%s is %s\n') $i $path
|
||||
set -l paths
|
||||
if test $selection != multi
|
||||
set paths (which $i ^/dev/null)
|
||||
else
|
||||
set paths (which -a $i ^/dev/null)
|
||||
end
|
||||
for path in $paths
|
||||
if test -x (echo $path)
|
||||
set res 0
|
||||
set found 1
|
||||
switch $mode
|
||||
case normal
|
||||
printf (_ '%s is %s\n') $i $path
|
||||
|
||||
case type
|
||||
echo (_ 'file')
|
||||
|
||||
case path
|
||||
echo $path
|
||||
end
|
||||
if test $selection != multi
|
||||
continue
|
||||
end
|
||||
if test $selection != multi
|
||||
continue
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -17,9 +17,18 @@ Redistributions in binary form must reproduce the above copyright notice, this l
|
|||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import string, sys, re, os.path, gzip, traceback, getopt, errno, codecs
|
||||
import string, sys, re, os.path, bz2, gzip, traceback, getopt, errno, codecs
|
||||
from deroff import Deroffer
|
||||
|
||||
lzma_available = True
|
||||
try:
|
||||
try:
|
||||
import lzma
|
||||
except ImportError:
|
||||
from backports import lzma
|
||||
except ImportError:
|
||||
lzma_available = False
|
||||
|
||||
# Whether we're Python 3
|
||||
IS_PY3 = sys.version_info[0] >= 3
|
||||
|
||||
|
@ -717,6 +726,16 @@ def parse_manpage_at_path(manpage_path, output_directory):
|
|||
fd = gzip.open(manpage_path, 'r')
|
||||
manpage = fd.read()
|
||||
if IS_PY3: manpage = manpage.decode('latin-1')
|
||||
elif manpage_path.endswith('.bz2'):
|
||||
fd = bz2.BZ2File(manpage_path, 'r')
|
||||
manpage = fd.read()
|
||||
if IS_PY3: manpage = manpage.decode('latin-1')
|
||||
elif manpage_path.endswith('.xz') or manpage_path.endswith('.lzma'):
|
||||
if not lzma_available:
|
||||
return
|
||||
fd = lzma.LZMAFile(str(manpage_path), 'r')
|
||||
manpage = fd.read()
|
||||
if IS_PY3: manpage = manpage.decode('latin-1')
|
||||
else:
|
||||
if IS_PY3:
|
||||
fd = open(manpage_path, 'r', encoding='latin-1')
|
||||
|
@ -816,6 +835,15 @@ def parse_and_output_man_pages(paths, output_directory, show_progress):
|
|||
last_progress_string_length = 0
|
||||
if show_progress and not WRITE_TO_STDOUT:
|
||||
print("Parsing man pages and writing completions to {0}".format(output_directory))
|
||||
|
||||
man_page_suffixes = set([os.path.splitext(m)[1][1:] for m in paths])
|
||||
lzma_xz_occurs = "xz" in man_page_suffixes or "lzma" in man_page_suffixes
|
||||
if lzma_xz_occurs and not lzma_available:
|
||||
add_diagnostic('At least one man page is compressed with lzma or xz, but the "lzma" module is not available.'
|
||||
' Any man page compressed with either will be skipped.',
|
||||
NOT_VERBOSE)
|
||||
flush_diagnostics(sys.stderr)
|
||||
|
||||
for manpage_path in paths:
|
||||
index += 1
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
set -g __fish_git_prompt_show_informative_status 1
|
||||
set -g __fish_git_prompt_hide_untrackedfiles 1
|
||||
|
||||
set -g __fish_git_prompt_color_branch magenta bold
|
||||
set -g __fish_git_prompt_color_branch magenta --bold
|
||||
set -g __fish_git_prompt_showupstream "informative"
|
||||
set -g __fish_git_prompt_char_upstream_ahead "↑"
|
||||
set -g __fish_git_prompt_char_upstream_behind "↓"
|
||||
|
@ -20,7 +20,7 @@ set -g __fish_git_prompt_color_dirtystate blue
|
|||
set -g __fish_git_prompt_color_stagedstate yellow
|
||||
set -g __fish_git_prompt_color_invalidstate red
|
||||
set -g __fish_git_prompt_color_untrackedfiles $fish_color_normal
|
||||
set -g __fish_git_prompt_color_cleanstate green bold
|
||||
set -g __fish_git_prompt_color_cleanstate green --bold
|
||||
|
||||
|
||||
function fish_prompt --description 'Write out the prompt'
|
||||
|
|
|
@ -15,9 +15,15 @@ else:
|
|||
import http.server as SimpleHTTPServer
|
||||
import socketserver as SocketServer
|
||||
from urllib.parse import parse_qs
|
||||
|
||||
# Disable CLI web browsers
|
||||
term = os.environ.pop('TERM', None)
|
||||
import webbrowser
|
||||
if term:
|
||||
os.environ['TERM'] = term
|
||||
|
||||
import subprocess
|
||||
import re, socket, os, sys, cgi, select, time, glob
|
||||
import re, socket, cgi, select, time, glob
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
|
|
|
@ -647,20 +647,20 @@ enum token_type tok_peek_next(tokenizer_t *tok, wcstring *out_next_string)
|
|||
{
|
||||
out_next_string->clear();
|
||||
}
|
||||
|
||||
|
||||
enum token_type result = TOK_END;
|
||||
if (tok_has_next(tok))
|
||||
{
|
||||
int saved = tok_get_pos(tok);
|
||||
tok_next(tok);
|
||||
result = tok_last_type(tok);
|
||||
|
||||
|
||||
if (out_next_string != NULL)
|
||||
{
|
||||
const wchar_t *last = tok_last(tok);
|
||||
out_next_string->assign(last ? last : L"");
|
||||
}
|
||||
|
||||
|
||||
tok_set_pos(tok, saved);
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -317,7 +317,7 @@ static bool wildcard_complete_internal(const wcstring &orig,
|
|||
if (wildcard_complete_internal(orig, str + i, wc+1, false, desc, desc_func, out, expand_flags, flags))
|
||||
{
|
||||
res = true;
|
||||
|
||||
|
||||
/* #929: if the recursive call gives us a prefix match, just stop. This is sloppy - what we really want to do is say, once we've seen a match of a particular type, ignore all matches of that type further down the string, such that the wildcard produces the "minimal match." */
|
||||
bool has_prefix_match = false;
|
||||
const size_t after_count = out.size();
|
||||
|
|
|
@ -276,7 +276,10 @@ _xdg_mime_magic_parse_header(FILE *magic_file, XdgMimeMagicMatch *match)
|
|||
|
||||
buffer = _xdg_mime_magic_read_to_newline(magic_file, &end_of_file);
|
||||
if (end_of_file)
|
||||
{
|
||||
free(buffer);
|
||||
return XDG_MIME_MAGIC_EOF;
|
||||
}
|
||||
|
||||
end_ptr = buffer;
|
||||
while (*end_ptr != ']' && *end_ptr != '\000' && *end_ptr != '\n')
|
||||
|
|
Loading…
Reference in a new issue