Merge branch 'master' into ast

Conflicts:
	complete.cpp
	fish_tests.cpp
	highlight.cpp
This commit is contained in:
ridiculousfish 2013-12-07 12:54:43 -08:00
commit a23441109d
37 changed files with 732 additions and 571 deletions

1
.gitignore vendored
View File

@ -18,7 +18,6 @@ doc_src/commands.hdr
doc_src/index.hdr doc_src/index.hdr
po/*.gmo po/*.gmo
fish fish
fish.spec
fish_indent fish_indent
fish_pager fish_pager
fish_tests fish_tests

View File

@ -20,14 +20,7 @@
# #
# Makefile for the fish shell. Can build fish and associated # Makefile for the fish shell. Can build fish and associated
# applications, install them, recalculate dependencies and also create # applications, install them, and recalculate dependencies.
# 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.
# #
# Used by docdir # Used by docdir
@ -186,48 +179,6 @@ HELP_SRC := $(wildcard doc_src/*.txt)
TEST_IN := $(wildcard tests/test*.in) 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/ # Files in ./share/completions/
# #
@ -449,7 +400,7 @@ doc.h: $(HDR_FILES)
# #
%.po:messages.pot %.po:messages.pot
if test $(HAVE_GETTEXT) = 1;then \ if test "$(HAVE_GETTEXT)" = 1;then \
if test -f $*.po; then \ if test -f $*.po; then \
msgmerge -U --backup=existing $*.po messages.pot;\ msgmerge -U --backup=existing $*.po messages.pot;\
else \ else \
@ -463,7 +414,7 @@ doc.h: $(HDR_FILES)
# #
messages.pot: *.cpp *.h share/completions/*.fish share/functions/*.fish 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; \ 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 \ 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"\ echo "Your xgettext version is too old to build the messages.pot file"\
@ -508,7 +459,7 @@ share/man: $(HELP_SRC)
-mkdir share/man -mkdir share/man
touch share/man touch share/man
-rm -Rf share/man/man1 -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 # The build rules for installing/uninstalling fish
@ -714,7 +665,7 @@ uninstall-legacy: uninstall
.PHONY: uninstall-legacy .PHONY: uninstall-legacy
install-translations: $(TRANSLATIONS) install-translations: $(TRANSLATIONS)
if test $(HAVE_GETTEXT) = 1; then \ if test "$(HAVE_GETTEXT)" = 1; then \
for i in $(TRANSLATIONS); do \ for i in $(TRANSLATIONS); do \
$(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/locale/`basename $$i .gmo`/LC_MESSAGES; \ $(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; \ $(INSTALL) -m 644 $$i $(DESTDIR)$(datadir)/locale/`basename $$i .gmo`/LC_MESSAGES/fish.mo; \
@ -724,7 +675,7 @@ install-translations: $(TRANSLATIONS)
.PHONY: install-translations .PHONY: install-translations
uninstall-translations: uninstall-translations:
if test $(HAVE_GETTEXT) = 1; then \ if test "$(HAVE_GETTEXT)" = 1; then \
for i in $(TRANSLATIONS_SRC); do \ for i in $(TRANSLATIONS_SRC); do \
rm -f $(DESTDIR)$(datadir)/locale/*/LC_MESSAGES/fish.mo; \ rm -f $(DESTDIR)$(datadir)/locale/*/LC_MESSAGES/fish.mo; \
done; \ done; \
@ -800,13 +751,6 @@ depend:
./config.status ./config.status
.PHONY: depend .PHONY: depend
#
# Build the RPM spec file.
#
fish.spec: fish.spec.in
./config.status
# #
# Cleanup targets # Cleanup targets
# #
@ -816,7 +760,6 @@ fish.spec: fish.spec.in
# #
distclean: clean distclean: clean
rm -f fish.spec
rm -f config.status config.log config.h Makefile rm -f config.status config.log config.h Makefile
.PHONY: distclean .PHONY: distclean

View File

@ -86,7 +86,7 @@ done
# Input is kept as . because we cd to the input directory beforehand # Input is kept as . because we cd to the input directory beforehand
# This prevents doxygen from generating "documentation" for intermediate directories # This prevents doxygen from generating "documentation" for intermediate directories
DOXYPARAMS=$(cat <<EOF DOXYPARAMS=$(cat <<EOF
PROJECT_NUMBER=2.0.0 PROJECT_NUMBER=$PROJECT_NUMBER
INPUT=. INPUT=.
OUTPUT_DIRECTORY=$OUTPUTDIR OUTPUT_DIRECTORY=$OUTPUTDIR
QUIET=YES QUIET=YES

View File

@ -195,11 +195,6 @@ double C_STRTOD(wchar_t const *nptr, wchar_t **endptr)
return r; 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, ...) void builtin_printf_state_t::fatal_error(const wchar_t *fmt, ...)
{ {
// Don't error twice // 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; T val;
if (*s == L'\"' || *s == L'\'') if (*s == L'\"' || *s == L'\'')
{ {
unsigned wchar_t ch = *++s; wchar_t ch = *++s;
val = ch; val = ch;
} }
else else
@ -736,8 +731,8 @@ no_more_flag_characters:
++f; ++f;
{ {
unsigned wchar_t conversion = *f; wchar_t conversion = *f;
if (! ok[conversion]) if (conversion > 0xFF || ! ok[conversion])
{ {
this->fatal_error(_(L"%.*ls: invalid conversion specification"), (int)(f + 1 - direc_start), direc_start); this->fatal_error(_(L"%.*ls: invalid conversion specification"), (int)(f + 1 - direc_start), direc_start);
return 0; return 0;

View File

@ -1198,6 +1198,11 @@ static size_t read_unquoted_escape(const wchar_t *input, wcstring *result, bool
{ {
chars=8; chars=8;
max_val = WCHAR_MAX; max_val = WCHAR_MAX;
// Don't exceed the largest Unicode code point - see #1107
if (0x10FFFF < max_val)
max_val = (wchar_t)0x10FFFF;
break; break;
} }
@ -1594,6 +1599,7 @@ static bool unescape_string_internal(const wchar_t * const input, const size_t i
{ {
/* Swallow newline */ /* Swallow newline */
to_append = NOT_A_WCHAR; to_append = NOT_A_WCHAR;
input_position += 1; /* Skip over the backslash */
break; break;
} }

View File

@ -45,6 +45,7 @@
#include "wutil.h" #include "wutil.h"
#include "path.h" #include "path.h"
#include "parse_tree.h" #include "parse_tree.h"
#include "iothread.h"
/* /*
Completion description strings, mostly for different types of files, such as sockets, block devices, etc. Completion description strings, mostly for different types of files, such as sockets, block devices, etc.
@ -342,7 +343,6 @@ class completer_t
const completion_request_flags_t flags; const completion_request_flags_t flags;
const wcstring initial_cmd; const wcstring initial_cmd;
std::vector<completion_t> completions; 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 */ /** Table of completions conditions that have already been tested and the corresponding test results */
typedef std::map<wcstring, bool> condition_cache_t; typedef std::map<wcstring, bool> condition_cache_t;
@ -431,7 +431,7 @@ public:
/* Never do command substitution in autosuggestions. Sadly, we also can't yet do job expansion because it's not thread safe. */ /* 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; expand_flags_t result = 0;
if (this->type() == COMPLETE_AUTOSUGGEST) if (this->type() == COMPLETE_AUTOSUGGEST)
result |= EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_JOBS; result |= EXPAND_SKIP_CMDSUBST;
/* Allow fuzzy matching */ /* Allow fuzzy matching */
if (this->fuzzy()) if (this->fuzzy())
@ -439,18 +439,6 @@ public:
return result; 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 */ /* Autoloader for completions */
@ -1351,6 +1339,15 @@ void complete_load(const wcstring &name, bool reload)
completion_autoloader.load(name, 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 Find completion for the argument str of command cmd_orig with
previous option popt. Insert results into comp_out. Return 0 if file previous option popt. Insert results into comp_out. Return 0 if file
@ -1375,14 +1372,15 @@ bool completer_t::complete_param(const wcstring &scmd_orig, const wcstring &spop
if (this->type() == COMPLETE_DEFAULT) if (this->type() == COMPLETE_DEFAULT)
{ {
ASSERT_IS_MAIN_THREAD();
complete_load(cmd, true); complete_load(cmd, true);
} }
else if (this->type() == COMPLETE_AUTOSUGGEST) else if (this->type() == COMPLETE_AUTOSUGGEST)
{ {
/* Maybe indicate we should try loading this on the main thread */ /* Maybe load this command (on the main thread) */
if (! list_contains_string(this->commands_to_load, cmd) && ! completion_autoloader.has_tried_loading(cmd)) if (! completion_autoloader.has_tried_loading(cmd))
{ {
this->commands_to_load.push_back(cmd); iothread_perform_on_main(complete_load_no_reload, &cmd);
} }
} }
@ -1793,7 +1791,7 @@ bool completer_t::try_complete_user(const wcstring &str)
return res; return res;
} }
void complete(const wcstring &cmd_with_subcmds, std::vector<completion_t> &comps, completion_request_flags_t flags, wcstring_list_t *commands_to_load) void complete(const wcstring &cmd_with_subcmds, std::vector<completion_t> &comps, completion_request_flags_t flags)
{ {
/* Determine the innermost subcommand */ /* Determine the innermost subcommand */
const wchar_t *cmdsubst_begin, *cmdsubst_end; const wchar_t *cmdsubst_begin, *cmdsubst_end;
@ -1932,11 +1930,6 @@ void complete(const wcstring &cmd_with_subcmds, std::vector<completion_t> &comps
if (completer.empty()) if (completer.empty())
do_file = true; 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 */ /* And if we're autosuggesting, and the token is empty, don't do file suggestions */
if ((flags & COMPLETION_REQUEST_AUTOSUGGESTION) && current_argument_unescape.empty()) if ((flags & COMPLETION_REQUEST_AUTOSUGGESTION) && current_argument_unescape.empty())
do_file = false; do_file = false;
@ -1948,7 +1941,6 @@ void complete(const wcstring &cmd_with_subcmds, std::vector<completion_t> &comps
} }
comps = completer.get_completions(); comps = completer.get_completions();
completer.get_commands_to_load(commands_to_load);
} }

View File

@ -216,14 +216,11 @@ void complete_remove(const wchar_t *cmd,
const wchar_t *long_opt); const wchar_t *long_opt);
/** Find all completions of the command cmd, insert them into out. If to_load is /** Find all completions of the command cmd, insert them into out.
* not NULL, append all commands that we would autoload, but did not (presumably
* because this is not the main thread)
*/ */
void complete(const wcstring &cmd, void complete(const wcstring &cmd,
std::vector<completion_t> &comp, std::vector<completion_t> &comp,
completion_request_flags_t flags, completion_request_flags_t flags);
wcstring_list_t *to_load = NULL);
/** /**
Print a list of all current completions into the string. Print a list of all current completions into the string.

View File

@ -873,7 +873,7 @@ case $target_os in
esac esac
# Tell the world what we know # Tell the world what we know
AC_CONFIG_FILES([Makefile fish.spec]) AC_CONFIG_FILES([Makefile])
AC_OUTPUT AC_OUTPUT
if test ! x$local_found_posix_switch = xyes; then if test ! x$local_found_posix_switch = xyes; then

View File

@ -188,7 +188,7 @@ void print_open_fds(void)
{ {
if (open_fds.at(i)) if (open_fds.at(i))
{ {
fprintf(stderr, "fd %lu\n", i); fprintf(stderr, "fd %lu\n", (unsigned long) i);
} }
} }
} }

View File

@ -49,6 +49,7 @@ parameter expansion.
#include "signal.h" #include "signal.h"
#include "tokenizer.h" #include "tokenizer.h"
#include "complete.h" #include "complete.h"
#include "iothread.h"
#include "parse_util.h" #include "parse_util.h"
@ -560,6 +561,166 @@ std::vector<wcstring> expand_get_all_process_names(void)
return result; 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 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. 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)) if (!(flags & EXPAND_SKIP_JOBS))
{ {
ASSERT_IS_MAIN_THREAD(); const struct find_job_data_t data = {proc, flags, &out};
const job_t *j; found = iothread_perform_on_main(find_job, &data);
// 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;
}
}
}
}
if (found) if (found)
{ {

View File

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

View File

@ -165,6 +165,22 @@ static void test_unescape_sane()
err(L"In unescaping '%ls', expected '%ls' but got '%ls'\n", tests[i].input, tests[i].expected, output.c_str()); 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");
}
} }
/** /**
@ -450,7 +466,7 @@ static void test_fork(void)
size_t i, max = 100; size_t i, max = 100;
for (i=0; i < 100; i++) 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 */ /* Do something horrible to try to trigger an error */
#define THREAD_COUNT 8 #define THREAD_COUNT 8
#define FORK_COUNT 10 #define FORK_COUNT 10
@ -506,6 +522,50 @@ static void test_fork(void)
#undef FORK_COUNT #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 Test the parser
*/ */
@ -1372,7 +1432,7 @@ void perf_complete()
str[0]=c; str[0]=c;
reader_set_buffer(str, 0); reader_set_buffer(str, 0);
complete(str, out, COMPLETION_REQUEST_DEFAULT, NULL); complete(str, out, COMPLETION_REQUEST_DEFAULT);
matches += out.size(); matches += out.size();
out.clear(); out.clear();
@ -1392,7 +1452,7 @@ void perf_complete()
reader_set_buffer(str, 0); reader_set_buffer(str, 0);
complete(str, out, COMPLETION_REQUEST_DEFAULT, NULL); complete(str, out, COMPLETION_REQUEST_DEFAULT);
matches += out.size(); matches += out.size();
out.clear(); out.clear();
@ -2363,6 +2423,7 @@ int main(int argc, char **argv)
if (should_test_function("convert_nulls")) test_convert_nulls(); if (should_test_function("convert_nulls")) test_convert_nulls();
if (should_test_function("tok")) test_tok(); if (should_test_function("tok")) test_tok();
if (should_test_function("fork")) test_fork(); if (should_test_function("fork")) test_fork();
if (should_test_function("iothread")) test_iothread();
if (should_test_function("parser")) test_parser(); if (should_test_function("parser")) test_parser();
if (should_test_function("utils")) test_utils(); if (should_test_function("utils")) test_utils();
if (should_test_function("escape_sequences")) test_escape_sequences(); if (should_test_function("escape_sequences")) test_escape_sequences();

View File

@ -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; bool has_timestamp = false;
time_t timestamp; time_t timestamp;
const char *interior_line; 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); for (interior_line = next_line(line_start, end - line_start);
interior_line != NULL && ! has_timestamp; interior_line != NULL && ! has_timestamp;
interior_line = next_line(interior_line, end - interior_line)) 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. */ /* Try parsing a timestamp from this line. If we succeed, the loop will break. */
has_timestamp = parse_timestamp(interior_line, &timestamp); has_timestamp = parse_timestamp(interior_line, &timestamp);
processed_once = true;
} }
assert(processed_once);
/* Skip this item if the timestamp is past our cutoff. */ /* Skip this item if the timestamp is past our cutoff. */
if (has_timestamp && timestamp > cutoff_timestamp) if (has_timestamp && timestamp > cutoff_timestamp)
{ {

View File

@ -60,6 +60,8 @@
#include "intern.h" #include "intern.h"
#include <vector> #include <vector>
#define DEFAULT_TERM L"ansi"
/** /**
Struct representing a keybinding. Returned by input_get_mappings. Struct representing a keybinding. Returned by input_get_mappings.
*/ */
@ -346,13 +348,29 @@ int input_init()
input_common_init(&interrupt_handler); input_common_init(&interrupt_handler);
const env_var_t term = env_get_string(L"TERM");
int errret; int errret;
if (setupterm(0, STDOUT_FILENO, &errret) == ERR) if (setupterm(0, STDOUT_FILENO, &errret) == ERR)
{ {
debug(0, _(L"Could not set up terminal")); 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()); assert(! term.missing());
output_set_term(term); output_set_term(term);

2
io.cpp
View File

@ -71,7 +71,7 @@ void io_pipe_t::print() const
void io_buffer_t::print() const void io_buffer_t::print() const
{ {
fprintf(stderr, "buffer %p (input: %s, size %lu)\n", out_buffer_ptr(), 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() void io_buffer_t::read()

View File

@ -22,6 +22,11 @@
#define IO_MAX_THREADS 64 #define IO_MAX_THREADS 64
#endif #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; static int s_active_thread_count;
typedef unsigned char ThreadIndex_t; typedef unsigned char ThreadIndex_t;
@ -32,16 +37,22 @@ static struct WorkerThread_t
pthread_t thread; pthread_t thread;
} threads[IO_MAX_THREADS]; } threads[IO_MAX_THREADS];
struct ThreadedRequest_t struct SpawnRequest_t
{ {
int sequenceNumber;
int (*handler)(void *); int (*handler)(void *);
void (*completionCallback)(void *, int); void (*completionCallback)(void *, int);
void *context; void *context;
int handlerResult; 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) static struct WorkerThread_t *next_vacant_thread_slot(void)
{ {
for (ThreadIndex_t i=0; i < IO_MAX_THREADS; i++) 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; return NULL;
} }
static pthread_mutex_t s_request_queue_lock; /* Spawn support */
static std::queue<ThreadedRequest_t *> s_request_queue; static pthread_mutex_t s_spawn_queue_lock;
static int s_last_sequence_number; 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 int s_read_pipe, s_write_pipe;
static void iothread_init(void) static void iothread_init(void)
@ -63,8 +82,11 @@ static void iothread_init(void)
{ {
inited = true; inited = true;
/* Initialize the queue lock */ /* Initialize some locks */
VOMIT_ON_FAILURE(pthread_mutex_init(&s_request_queue_lock, NULL)); 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 */ /* Initialize the completion pipes */
int pipes[2] = {0, 0}; 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); s_request_queue.push(req);
} }
static ThreadedRequest_t *dequeue_request(void) static SpawnRequest_t *dequeue_spawn_request(void)
{ {
ThreadedRequest_t *result = NULL; SpawnRequest_t *result = NULL;
scoped_lock lock(s_request_queue_lock); scoped_lock lock(s_spawn_queue_lock);
if (! s_request_queue.empty()) if (! s_request_queue.empty())
{ {
result = s_request_queue.front(); result = s_request_queue.front();
@ -109,7 +131,7 @@ static void *iothread_worker(void *threadPtr)
struct WorkerThread_t *thread = (struct WorkerThread_t *)threadPtr; struct WorkerThread_t *thread = (struct WorkerThread_t *)threadPtr;
/* Grab a request off of the queue */ /* 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 */ /* Run the handler and store the result */
if (req) if (req)
@ -127,7 +149,7 @@ static void *iothread_worker(void *threadPtr)
/* Spawn another thread if there's work to be done. */ /* Spawn another thread if there's work to be done. */
static void iothread_spawn_if_needed(void) 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) if (! s_request_queue.empty() && s_active_thread_count < IO_MAX_THREADS)
{ {
struct WorkerThread_t *thread = next_vacant_thread_slot(); struct WorkerThread_t *thread = next_vacant_thread_slot();
@ -168,14 +190,13 @@ int iothread_perform_base(int (*handler)(void *), void (*completionCallback)(voi
iothread_init(); iothread_init();
/* Create and initialize a request. */ /* Create and initialize a request. */
struct ThreadedRequest_t *req = new ThreadedRequest_t(); struct SpawnRequest_t *req = new SpawnRequest_t();
req->handler = handler; req->handler = handler;
req->completionCallback = completionCallback; req->completionCallback = completionCallback;
req->context = context; req->context = context;
req->sequenceNumber = ++s_last_sequence_number;
/* Take our lock */ /* Take our lock */
scoped_lock lock(s_request_queue_lock); scoped_lock lock(s_spawn_queue_lock);
/* Add to the queue */ /* Add to the queue */
add_to_queue(req); add_to_queue(req);
@ -196,31 +217,38 @@ void iothread_service_completion(void)
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
ThreadIndex_t threadIdx = (ThreadIndex_t)-1; ThreadIndex_t threadIdx = (ThreadIndex_t)-1;
VOMIT_ON_FAILURE(1 != read_loop(iothread_port(), &threadIdx, sizeof threadIdx)); VOMIT_ON_FAILURE(1 != read_loop(iothread_port(), &threadIdx, sizeof threadIdx));
assert(threadIdx < IO_MAX_THREADS);
struct WorkerThread_t *thread = &threads[threadIdx]; if (threadIdx == IO_SERVICE_MAIN_THREAD_REQUEST_QUEUE)
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 (req->completionCallback) iothread_service_main_thread_requests();
req->completionCallback(req->context, req->handlerResult);
delete req;
} }
else
{
assert(threadIdx < IO_MAX_THREADS);
/* Maybe spawn another thread, if there's more work to be done. */ struct WorkerThread_t *thread = &threads[threadIdx];
VOMIT_ON_FAILURE(pthread_mutex_lock(&s_request_queue_lock)); assert(thread->thread != 0);
iothread_spawn_if_needed();
VOMIT_ON_FAILURE(pthread_mutex_unlock(&s_request_queue_lock)); 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) 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); printf("(Waited %.02f msec for %d thread(s) to drain)\n", 1000 * (after - now), thread_count);
#endif #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;
}

View File

@ -28,11 +28,22 @@ void iothread_service_completion(void);
/** Waits for all iothreads to terminate. */ /** Waits for all iothreads to terminate. */
void iothread_drain_all(void); 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> template<typename T>
int iothread_perform(int (*handler)(T *), void (*completionCallback)(T *, int), T *context) 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)); 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 #endif

View File

@ -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()) job_iterator_t::job_iterator_t() : job_list(&parser_t::principal_parser().job_list())
{ {
ASSERT_IS_MAIN_THREAD();
this->reset(); this->reset();
} }

View File

@ -1349,12 +1349,8 @@ struct autosuggestion_context_t
file_detection_context_t detector; file_detection_context_t detector;
const wcstring working_directory; const wcstring working_directory;
const env_vars_snapshot_t vars; const env_vars_snapshot_t vars;
wcstring_list_t commands_to_load;
const unsigned int generation_count; 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) : autosuggestion_context_t(history_t *history, const wcstring &term, size_t pos) :
search_string(term), search_string(term),
cursor_pos(pos), cursor_pos(pos),
@ -1362,8 +1358,7 @@ struct autosuggestion_context_t
detector(history, term), detector(history, term),
working_directory(env_get_pwd_slash()), working_directory(env_get_pwd_slash()),
vars(env_vars_snapshot_t::highlighting_keys), vars(env_vars_snapshot_t::highlighting_keys),
generation_count(s_generation_count), generation_count(s_generation_count)
has_tried_reloading(false)
{ {
} }
@ -1433,7 +1428,7 @@ struct autosuggestion_context_t
/* Try normal completions */ /* Try normal completions */
std::vector<completion_t> 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()) if (! completions.empty())
{ {
const completion_t &comp = completions.at(0); const completion_t &comp = completions.at(0);
@ -1462,23 +1457,6 @@ static bool can_autosuggest(void)
static void autosuggest_completed(autosuggestion_context_t *ctx, int result) 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 && if (result &&
can_autosuggest() && can_autosuggest() &&
ctx->search_string == data->command_line && ctx->search_string == data->command_line &&
@ -3213,7 +3191,7 @@ const wchar_t *reader_readline(void)
const wcstring buffcpy = wcstring(cmdsub_begin, token_end); const wcstring buffcpy = wcstring(cmdsub_begin, token_end);
//fprintf(stderr, "Complete (%ls)\n", buffcpy.c_str()); //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 */ /* Munge our completions */
sort_and_make_unique(comp); sort_and_make_unique(comp);

View File

@ -166,7 +166,7 @@ void reader_pop();
- The command to be completed as a null terminated array of wchar_t - The command to be completed as a null terminated array of wchar_t
- An array_list_t in which completions will be inserted. - 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); void reader_set_complete_function(complete_function_t);
/** /**

View File

@ -537,10 +537,6 @@ static void s_desired_append_char(screen_t *s,
s->desired.add_line(); s->desired.add_line();
s->desired.cursor.y++; s->desired.cursor.y++;
s->desired.cursor.x=0; 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); line_t &line = s->desired.line(line_no);
@ -1215,7 +1211,14 @@ static screen_layout_t compute_layout(screen_t *s,
result.left_prompt_space = left_prompt_width; result.left_prompt_space = left_prompt_width;
// See remark about for why we can't use the right prompt here // See remark about for why we can't use the right prompt here
//result.right_prompt = right_prompt; //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; done = true;
} }

View File

@ -30,6 +30,14 @@ function __fish_brew_outdated_formulas
brew outdated brew outdated
end end
function __fish_brew_pinned_formulas
brew list --pinned
end
function __fish_brew_taps
brew tap
end
############ ############
# commands # # 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_needs_command' -a audit -d 'Check formula'
complete -f -c brew -n '__fish_brew_using_command audit' -a '(__fish_brew_formulae)' 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 # cat
complete -f -c brew -n '__fish_brew_needs_command' -a cat -d 'Display formula' 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)' 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 # cleanup
complete -f -c brew -n '__fish_brew_needs_command' -a cleanup -d 'Remove old installed versions' 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' -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' -l dry-run -d 'Show what files would be removed'
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' -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)' complete -f -c brew -n '__fish_brew_using_command cleanup' -a '(__fish_brew_installed_formulas)'
# create # 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 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 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 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 # deps
complete -f -c brew -n '__fish_brew_needs_command' -a deps -d 'Show a formula\'s dependencies' 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' -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 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 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)' complete -f -c brew -n '__fish_brew_using_command deps' -a '(__fish_brew_formulae)'
# diy # 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_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' 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_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 # fetch
complete -f -c brew -n '__fish_brew_needs_command' -a fetch -d 'Download source for formula' 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 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' -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' -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_using_command fetch' -a '(__fish_brew_formulae)'
complete -f -c brew -n '__fish_brew_needs_command' -a 'help' -d 'Display help' 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-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-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 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 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 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 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 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)' complete -c brew -n '__fish_brew_using_command install' -a '(__fish_brew_formulae)'
# link # link
complete -f -c brew -n '__fish_brew_needs_command' -a 'link ln' -d 'Symlink installed formula' 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 link' -a '(__fish_brew_installed_formulas)'
complete -f -c brew -n '__fish_brew_using_command ln' -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 # 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_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 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 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)' complete -c brew -n '__fish_brew_using_command list' -a '(__fish_brew_formulae)'
#ls #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 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 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)' complete -c brew -n '__fish_brew_using_command ls' -a '(__fish_brew_formulae)'
# log # log
@ -132,12 +174,19 @@ complete -c brew -n '__fish_brew_using_command missing' -a '(__fish_brew_formula
# options # 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_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' complete -c brew -n '__fish_brew_using_command options' -a '(__fish_brew_formulae)' -d 'formula'
# outdated # 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_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' 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 # prune
complete -f -c brew -n '__fish_brew_needs_command' -a prune -d 'Remove dead symlinks' 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 macports -d 'Search on MacPorts'
complete -f -c brew -n '__fish_brew_using_command -S' -l fink -d 'Search on Fink' 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 # 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_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 # test
complete -f -c brew -n '__fish_brew_needs_command' -a test -d 'Run tests for formula' 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 # uninstall
complete -f -c brew -n '__fish_brew_needs_command' -a 'uninstall remove rm' -d 'Uninstall formula' 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 # unlink
complete -f -c brew -n '__fish_brew_needs_command' -a unlink -d 'Unlink formula' 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 # untap
complete -f -c brew -n '__fish_brew_needs_command' -a untap -d 'Remove a tapped repository' 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 # update
complete -f -c brew -n '__fish_brew_needs_command' -a update -d 'Fetch newest version of Homebrew and formulas' 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 # 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_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 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)' complete -c brew -n '__fish_brew_using_command uses' -a '(__fish_brew_formulae)'
# versions # versions
@ -194,6 +258,7 @@ complete -c brew -n '__fish_brew_using_command versions' -a '(__fish_brew_formul
# switches # # 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' -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 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' complete -f -c brew -n '__fish_brew_needs_command' -l config -x -d 'Show Homebrew and system configuration'

View 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)'

View 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)'

View 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)"

View File

@ -31,7 +31,7 @@ complete -c scp -d "Remote Path" -n "commandline -ct|sgrep -o '.*:'" -a "
commandline -ct|sgrep -o '.*:' commandline -ct|sgrep -o '.*:'
)( )(
#Get the list of remote files from the specified ssh server #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
) )
" "

View File

@ -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 # 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 #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' complete -c service -n "test (count (commandline -poc)) -gt 1" -xa '$__fish_service_commands'

View File

@ -30,9 +30,13 @@ function __fish_complete_cd -d "Completions for the cd command"
for i in $mycdpath for i in $mycdpath
# Move to the initial directory first, # Move to the initial directory first,
# in case the CDPATH directory is relative # in case the CDPATH directory is relative
builtin cd $wd ^/dev/null
builtin cd $wd builtin cd $i ^/dev/null
builtin cd $i
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 # 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 # 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
end end
builtin cd $wd builtin cd $wd ^/dev/null
end end

View File

@ -21,7 +21,33 @@ function __fish_complete_man
set section $section"[^)]*" set section $section"[^)]*"
# Do the actual search # 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
end end

View 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

View File

@ -2,7 +2,7 @@
# #
# Written by Kevin Ballard <kevin@sb.org> # Written by Kevin Ballard <kevin@sb.org>
# Updated by Brian Gernhardt <brian@gernhardtsoftware.com> # Updated by Brian Gernhardt <brian@gernhardtsoftware.com>
# #
# This is heavily based off of the git-prompt.bash script that ships with # 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>. # 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 # The act of porting the code, along with any new code, are Copyright (C) 2012
@ -205,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 set upstream svn+git # default upstream is SVN if available, else git
# Save the config key (without .url) for later use # 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 set svn_prefix $svn_prefix $remote_prefix
end end
end end
@ -242,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) 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 if test (count $svn_upstream) -ne 0
echo $svn_upstream[-1] | read -l _ svn_upstream _ 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 set -l cur_prefix
for i in (seq (count $svn_remote)) for i in (seq (count $svn_remote))
set -l remote $svn_remote[$i] 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" if test "$svn_upstream" != "$mod_upstream"
# we found a valid remote # we found a valid remote
set svn_upstream $mod_upstream set svn_upstream $mod_upstream
@ -263,14 +263,14 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
set upstream git-svn set upstream git-svn
end end
else 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 # Use fetch config to fix upstream
set -l fetch_val (command git config "$cur_prefix".fetch) set -l fetch_val (command git config "$cur_prefix".fetch)
if test -n "$fetch_val" if test -n "$fetch_val"
set -l IFS : set -l IFS :
echo "$fetch_val" | read -l trunk pattern 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
end end
else if test $upstream = svn+git else if test $upstream = svn+git
@ -426,7 +426,7 @@ function __fish_git_prompt --description "Prompt function for Git"
if test -n "$u" if test -n "$u"
set u "$___fish_git_prompt_color_untrackedfiles$u$___fish_git_prompt_color_untrackedfiles_done" set u "$___fish_git_prompt_color_untrackedfiles$u$___fish_git_prompt_color_untrackedfiles_done"
end end
set b (/bin/sh -c 'echo "${1#refs/heads/}"' -- $b) set b (echo $b | sed 's|refs/heads/||')
if test -n "$b" if test -n "$b"
set b "$branch_color$b$branch_done" set b "$branch_color$b$branch_done"
end end

View File

@ -0,0 +1,4 @@
function __fish_number_of_cmd_args_wo_opts
count (__fish_print_cmd_args_without_options)
end

View File

@ -0,0 +1,3 @@
function __fish_print_cmd_args
commandline -poc
end

View File

@ -0,0 +1,3 @@
function __fish_print_cmd_args_without_options
__fish_print_cmd_args | grep '^[^-]'
end

View 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

View File

@ -4,7 +4,7 @@
set -g __fish_git_prompt_show_informative_status 1 set -g __fish_git_prompt_show_informative_status 1
set -g __fish_git_prompt_hide_untrackedfiles 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_showupstream "informative"
set -g __fish_git_prompt_char_upstream_ahead "↑" set -g __fish_git_prompt_char_upstream_ahead "↑"
set -g __fish_git_prompt_char_upstream_behind "↓" 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_stagedstate yellow
set -g __fish_git_prompt_color_invalidstate red set -g __fish_git_prompt_color_invalidstate red
set -g __fish_git_prompt_color_untrackedfiles $fish_color_normal 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' function fish_prompt --description 'Write out the prompt'

View File

@ -15,9 +15,15 @@ else:
import http.server as SimpleHTTPServer import http.server as SimpleHTTPServer
import socketserver as SocketServer import socketserver as SocketServer
from urllib.parse import parse_qs from urllib.parse import parse_qs
# Disable CLI web browsers
term = os.environ.pop('TERM', None)
import webbrowser import webbrowser
if term:
os.environ['TERM'] = term
import subprocess import subprocess
import re, socket, os, sys, cgi, select, time, glob import re, socket, cgi, select, time, glob
try: try:
import json import json
except ImportError: except ImportError: