aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2013-10-06 13:08:57 -0700
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2013-10-06 13:08:57 -0700
commitdd91779442125ca46a434cd94cc51ae32e43bee1 (patch)
treee023ebb7a8a0e6f9c6c4a394158773ced0c98a82
parente58b73179f4727c79465c6f273aef377b9bb8bee (diff)
parentfab7299d49492ce548d4ceed66d3acbd05dd99c7 (diff)
Merge branch 'master' into ast_no_templates
Conflicts: configure.ac exec.cpp
-rw-r--r--.gitattributes18
-rw-r--r--.gitignore5
-rw-r--r--CONTRIBUTING.md (renamed from STYLEGUIDE.md)0
-rw-r--r--Makefile.in92
-rw-r--r--README.md8
-rwxr-xr-xbuild_tools/build_documentation.sh4
-rwxr-xr-xbuild_tools/git_version_gen.sh31
-rwxr-xr-xbuild_tools/make_tarball.sh24
-rw-r--r--builtin.cpp59
-rw-r--r--builtin_commandline.cpp6
-rw-r--r--builtin_set_color.cpp8
-rw-r--r--builtin_test.cpp40
-rw-r--r--complete.cpp51
-rw-r--r--complete.h12
-rwxr-xr-xconfig.guess532
-rwxr-xr-xconfig.sub337
-rw-r--r--configure.ac30
-rw-r--r--doc_src/bind.txt37
-rw-r--r--doc_src/commands.hdr.in13
-rw-r--r--doc_src/design.hdr4
-rw-r--r--doc_src/faq.hdr15
-rw-r--r--doc_src/fish_config.txt2
-rw-r--r--doc_src/function.txt5
-rw-r--r--doc_src/index.hdr.in88
-rw-r--r--doc_src/license.hdr4
-rw-r--r--doc_src/nextd.txt4
-rw-r--r--doc_src/prevd.txt4
-rw-r--r--doc_src/source.txt12
-rw-r--r--doc_src/test.txt102
-rw-r--r--doc_src/tutorial.hdr746
-rw-r--r--env.cpp65
-rw-r--r--exec.cpp199
-rw-r--r--exec.h2
-rw-r--r--expand.cpp53
-rw-r--r--fish.cpp35
-rw-r--r--fish.xcodeproj/project.pbxproj3
-rw-r--r--fish_indent.cpp2
-rw-r--r--fish_pager.cpp7
-rw-r--r--fish_tests.cpp21
-rw-r--r--fishd.cpp14
-rw-r--r--highlight.cpp4
-rw-r--r--history.cpp11
-rw-r--r--input.cpp6
-rw-r--r--input.h3
-rwxr-xr-xinstall-sh680
-rw-r--r--io.cpp13
-rw-r--r--io.h12
-rw-r--r--mimedb.cpp2
-rw-r--r--osx/launch_fish.scptbin4490 -> 4650 bytes
-rw-r--r--parse_util.cpp40
-rw-r--r--parser.cpp88
-rw-r--r--parser.h6
-rw-r--r--path.cpp68
-rw-r--r--path.h3
-rw-r--r--postfork.cpp32
-rw-r--r--postfork.h6
-rw-r--r--proc.cpp29
-rw-r--r--proc.h28
-rw-r--r--reader.cpp250
-rw-r--r--reader.h5
-rw-r--r--screen.cpp339
-rw-r--r--screen.h7
-rw-r--r--share/completions/apt-get.fish4
-rw-r--r--share/completions/git.fish4
-rw-r--r--share/completions/make.fish2
-rw-r--r--share/completions/perl.fish6
-rw-r--r--share/completions/psql.fish66
-rw-r--r--share/completions/rsync.fish16
-rw-r--r--share/completions/scp.fish9
-rw-r--r--share/completions/useradd.fish10
-rw-r--r--share/completions/vim-addons.fish54
-rw-r--r--share/config.fish71
-rw-r--r--share/functions/__fish_complete_ls.fish2
-rw-r--r--share/functions/__fish_config_interactive.fish25
-rw-r--r--share/functions/__fish_git_prompt.fish504
-rw-r--r--share/functions/__fish_list_current_token.fish1
-rw-r--r--share/functions/__fish_print_hostnames.fish6
-rw-r--r--share/functions/__fish_print_make_targets.fish2
-rw-r--r--share/functions/__fish_print_mounted.fish7
-rw-r--r--share/functions/__fish_print_packages.fish35
-rw-r--r--share/functions/__fish_pwd.fish10
-rw-r--r--share/functions/__fish_urlencode.fish9
-rw-r--r--share/functions/eval.fish16
-rw-r--r--share/functions/fish_default_key_bindings.fish13
-rw-r--r--share/functions/help.fish5
-rw-r--r--share/functions/hostname.fish10
-rw-r--r--share/functions/ls.fish2
-rw-r--r--share/functions/man.fish2
-rw-r--r--share/functions/open.fish6
-rw-r--r--share/functions/prompt_pwd.fish13
-rwxr-xr-xshare/tools/create_manpage_completions.py22
-rwxr-xr-xshare/tools/web_config/webconfig.py2
-rw-r--r--tests/test1.in5
-rw-r--r--tests/test1.out5
-rw-r--r--tokenizer.cpp60
-rw-r--r--tokenizer.h8
-rw-r--r--user_doc.head.html153
-rw-r--r--wgetopt.cpp1
-rw-r--r--wildcard.cpp36
99 files changed, 3920 insertions, 1608 deletions
diff --git a/.gitattributes b/.gitattributes
index 6f346fba..94ef0ab2 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,4 +1,20 @@
.gitattributes export-ignore
.gitignore export-ignore
-/build_tools export-ignore
+/build_tools/make_svn_completions.fish export-ignore
+/build_tools/description-pak export-ignore
+/build_tools/make_hg_completions.fish export-ignore
+/build_tools/make_vcs_completions.fish export-ignore
+/build_tools/make_vcs_completions_generic.fish export-ignore
+/build_tools/osx_package_resources export-ignore
+/build_tools/osx_package_resources/terminal_logo.png export-ignore
+/build_tools/osx_package_resources/welcome.rtf export-ignore
+/build_tools/make_csv_completions.fish export-ignore
+/build_tools/osx_distribution.xml export-ignore
+/build_tools/make_tarball.sh export-ignore
+/build_tools/make_deb.sh export-ignore
+/build_tools/osx_package_scripts export-ignore
+/build_tools/osx_package_scripts/add-shell export-ignore
+/build_tools/osx_package_scripts/postinstall export-ignore
+/build_tools/make_pkg.sh export-ignore
+/build_tools/make_darcs_completions.fish export-ignore
diff --git a/.gitignore b/.gitignore
index a9fe03cb..b2ea73dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
*.o
*~
+*.exe
-Doxyfile.help
Makefile
autom4te.cache/
build/
@@ -12,6 +12,7 @@ config.h.in
config.log
config.status
configure
+doc/
doc.h
doc_src/commands.hdr
doc_src/index.hdr
@@ -32,3 +33,5 @@ user_doc/
xcuserdata
tests/*tmp.*
tests/foo.txt
+FISH-BUILD-VERSION-FILE
+version
diff --git a/STYLEGUIDE.md b/CONTRIBUTING.md
index d3e2ca1f..d3e2ca1f 100644
--- a/STYLEGUIDE.md
+++ b/CONTRIBUTING.md
diff --git a/Makefile.in b/Makefile.in
index c36cbe7d..07dec023 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -153,9 +153,10 @@ MIME_OBJS := mimedb.o print_help.o xdgmimealias.o xdgmime.o \
#
# These files are the source files, they contain a few @FOO@-style substitutions
+# Note that this order defines the order that they appear in the documentation
#
-HDR_FILES_SRC := doc_src/index.hdr.in doc_src/commands.hdr.in doc_src/design.hdr doc_src/license.hdr doc_src/faq.hdr
+HDR_FILES_SRC := doc_src/index.hdr.in doc_src/tutorial.hdr doc_src/design.hdr doc_src/license.hdr doc_src/commands.hdr.in doc_src/faq.hdr
#
@@ -269,19 +270,32 @@ TRANSLATIONS := $(TRANSLATIONS_SRC:.po=.gmo)
ifeq ($(HAVE_DOXYGEN), 1)
user_doc=user_doc
+ share_man=share/man
else
user_doc=
+ share_man=
endif
#
# Make everything needed for installing fish
#
-all: $(PROGRAMS) $(user_doc) share/man $(TRANSLATIONS)
+all: $(PROGRAMS) $(user_doc) $(share_man) $(TRANSLATIONS)
@echo fish has now been built.
@echo Use \'$(MAKE) install\' to install fish.
.PHONY: all
+#
+# Pull version information
+#
+
+FISH-BUILD-VERSION-FILE: FORCE
+ @./build_tools/git_version_gen.sh
+-include FISH-BUILD-VERSION-FILE
+CPPFLAGS += -DFISH_BUILD_VERSION=\"$(FISH_BUILD_VERSION)\"
+.PHONY: FORCE
+env.o fish.o fish_indent.o fish_pager.o fishd.o mimedb.o: FISH-BUILD-VERSION-FILE
+
#
# These dependencies make sure that autoconf and configure are run
@@ -311,9 +325,11 @@ prof: all
# Depend on the sources (*.hdr.in) and manually make the
# intermediate *.hdr and doc.h files if needed
+# The sed command deletes everything including and after the first -, for simpler version numbers
user_doc: $(HDR_FILES_SRC) Doxyfile.user user_doc.head.html $(HELP_SRC) doc.h $(HDR_FILES)
- (cat Doxyfile.user ; echo PROJECT_NUMBER=@PACKAGE_VERSION@) | doxygen - && touch user_doc
+ (cat Doxyfile.user ; echo PROJECT_NUMBER=$(FISH_BUILD_VERSION) | sed "s/-.*//") | doxygen - && touch user_doc
+
#
@@ -321,7 +337,7 @@ user_doc: $(HDR_FILES_SRC) Doxyfile.user user_doc.head.html $(HELP_SRC) doc.h $(
#
doc: *.h *.cpp doc.h Doxyfile
- (cat Doxyfile ; echo PROJECT_NUMBER=@PACKAGE_VERSION@) | doxygen - ;
+ (cat Doxyfile ; echo PROJECT_NUMBER=$(FISH_BUILD_VERSION)) | doxygen - ;
#
@@ -351,26 +367,34 @@ test: $(PROGRAMS) fish_tests
#
doc_src/commands.hdr:$(HELP_SRC) doc_src/commands.hdr.in
- -rm command_list.tmp $@
+ -rm command_list.tmp command_list_toc.tmp $@
for i in `printf "%s\n" $(HELP_SRC)|sort`; do \
echo "<hr>" >>command_list.tmp; \
cat $$i >>command_list.tmp; \
echo >>command_list.tmp; \
echo >>command_list.tmp; \
+ NAME=`basename $$i .txt`; \
+ echo '- <a href="#'$$NAME'">'$$NAME'</a>' >> command_list_toc.tmp; \
echo "Back to <a href='index.html#toc-commands'>index</a>". >>command_list.tmp; \
done
mv command_list.tmp command_list.txt
- cat $@.in | awk '{if ($$0 ~ /@command_list@/){ system("cat command_list.txt");} else{ print $$0;}}' >$@
+ mv command_list_toc.tmp command_list_toc.txt
+ cat $@.in | awk '{if ($$0 ~ /@command_list_toc@/) { system("cat command_list_toc.txt"); } else if ($$0 ~ /@command_list@/){ system("cat command_list.txt");} else{ print $$0;}}' >$@
toc.txt: $(HDR_FILES:index.hdr=index.hdr.in)
-rm toc.tmp $@
+ # Ugly hack to set the toc initial title for the main page
+ echo '- <a href="index.html" id="toc-index">Documentation</a>' > toc.tmp
+ # The first sed command captures the page name, followed by the description
+ # The second sed command captures the command name \1 and the description \2, but only up to a dash
+ # This is to reduce the size of the TOC in the command listing on the main page
for i in $(HDR_FILES:index.hdr=index.hdr.in); do\
NAME=`basename $$i .hdr`; \
NAME=`basename $$NAME .hdr.in`; \
sed <$$i >>toc.tmp -n \
-e 's,.*\\page *\([^ ]*\) *\(.*\)$$,- <a href="'$$NAME'.html" id="toc-'$$NAME'">\2</a>,p' \
- -e 's,.*\\section *\([^ ]*\) *\(.*\)$$, - <a href="'$$NAME'.html#\1">\2</a>,p'; \
+ -e 's,.*\\section *\([^ ]*\) *\([^-]*\)\(.*\)$$, - <a href="'$$NAME'.html#\1">\2</a>,p'; \
done
mv toc.tmp $@
@@ -629,10 +653,12 @@ install-force: all install-translations
@echo fish is now installed on your system.
@echo To run fish, type \'fish\' in your terminal.
@echo
- @echo To use fish as your login shell:
- @grep -q -- "$(DESTDIR)$(bindir)/fish" /etc/shells || echo \* add the line \'$(DESTDIR)$(bindir)/fish\' to the file \'/etc/shells\'.
- @echo \* use the command \'chsh -s $(DESTDIR)$(bindir)/fish\'.
- @echo
+ @if type chsh &> /dev/null; then \
+ echo To use fish as your login shell:; \
+ grep -q -- "$(DESTDIR)$(bindir)/fish" /etc/shells || echo \* add the line \'$(DESTDIR)$(bindir)/fish\' to the file \'/etc/shells\'.; \
+ echo \* use the command \'chsh -s $(DESTDIR)$(bindir)/fish\'.; \
+ echo; \
+ fi;
@echo To set your colors, run \'fish_config\'
@echo To scan your man pages for completions, run \'fish_update_completions\'
@echo To autocomplete command suggestions press Ctrl + F or right arrow key.
@@ -778,47 +804,12 @@ depend:
.PHONY: depend
#
-# Make compressed tar archives
-#
-
-fish-@PACKAGE_VERSION@.tar.gz: fish-@PACKAGE_VERSION@.tar
- gzip -f --best -c fish-@PACKAGE_VERSION@.tar >fish-@PACKAGE_VERSION@.tar.gz
-
-fish-@PACKAGE_VERSION@.tar.bz2: fish-@PACKAGE_VERSION@.tar
- bzip2 -f --best -k fish-@PACKAGE_VERSION@.tar
-
-dist: fish-@PACKAGE_VERSION@.tar.bz2
-.PHONY: dist
-
-#
# Build the RPM spec file.
#
fish.spec: fish.spec.in
./config.status
-
-
-#
-# Create .rpm file for the current systems architecture and an
-# .src.rpm file.
-#
-
-rpm: fish-@PACKAGE_VERSION@.tar.bz2 fish.spec
- @if which rpmbuild; then true; else \
- echo Could not find the rpmbuild command, needed to build an rpm; \
- echo You may be able to install it using the following command:; \
- echo \'yum install rpm-build\'; \
- false; \
- fi
- cp fish.spec /usr/src/redhat/SPECS/
- cp fish-@PACKAGE_VERSION@.tar.bz2 /usr/src/redhat/SOURCES/
- rpmbuild -ba --clean /usr/src/redhat/SPECS/fish.spec
- mv /usr/src/redhat/RPMS/*/fish*@PACKAGE_VERSION@*.rpm .
- mv /usr/src/redhat/SRPMS/fish*@PACKAGE_VERSION@*.src.rpm .
-.PHONY: rpm
-
-
#
# Cleanup targets
#
@@ -847,15 +838,12 @@ clean:
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 toc.txt
+ rm -f command_list.txt command_list_toc.txt toc.txt
rm -f doc_src/index.hdr doc_src/commands.hdr
- rm -f fish-@PACKAGE_VERSION@.tar
- rm -f fish-@PACKAGE_VERSION@.tar.gz
- rm -f fish-@PACKAGE_VERSION@.tar.bz2
- if test $(HAVE_DOXYGEN) = 1; then \
+ rm -f FISH-BUILD-VERSION-FILE
+ if test "$(HAVE_DOXYGEN)" = 1; then \
rm -rf doc user_doc share/man; \
fi
- rm -rf fish-@PACKAGE_VERSION@
rm -f $(TRANSLATIONS)
.PHONY: clean
diff --git a/README.md b/README.md
index f1a34b40..c7462465 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,9 @@ Detailed user documentation is available by running `help` within fish, and also
fish is written in a sane subset of C++98, with a few components from C++TR1. It builds successfully with g++ 4.2 or later, and with clang. It also will build as C++11.
-fish can be built using autotools or Xcode.
+fish can be built using autotools or Xcode. autoconf 2.60 or later is required.
+
+fish requires gettext for translation support.
### Autotools Build
@@ -40,7 +42,7 @@ If fish reports that it could not find curses, try installing a curses developme
On Debian or Ubuntu you want:
- sudo apt-get install libncurses5-dev libncursesw5-dev
+ sudo apt-get install libncurses5-dev
on RedHat, CentOS, or Amazon EC2:
@@ -66,6 +68,6 @@ Substitute /bin/bash with /bin/tcsh or /bin/zsh as appropriate.
## 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
+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).
Found a bug? Have an awesome idea? Please open an issue on this github page.
diff --git a/build_tools/build_documentation.sh b/build_tools/build_documentation.sh
index 2d971ec2..76c19a04 100755
--- a/build_tools/build_documentation.sh
+++ b/build_tools/build_documentation.sh
@@ -20,10 +20,8 @@ else
fi
# Determine which man pages we don't want to generate.
-# Don't make a test man page. fish's test is conforming, so the system man pages
-# are applicable and generally better.
# on OS X, don't make a man page for open, since we defeat fish's open function on OS X.
-CONDEMNED_PAGES=test.1
+CONDEMNED_PAGES=
if test `uname` = 'Darwin'; then
CONDEMNED_PAGES="$CONDEMNED_PAGES open.1"
fi
diff --git a/build_tools/git_version_gen.sh b/build_tools/git_version_gen.sh
new file mode 100755
index 00000000..3ffd0eb2
--- /dev/null
+++ b/build_tools/git_version_gen.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Originally from the git sources (GIT-VERSION-GEN)
+# Presumably (C) Junio C Hamano <junkio@cox.net>
+# Reused under GPL v2.0
+# Modified for fish by David Adam <zanchey@ucc.gu.uwa.edu.au>
+
+FBVF=FISH-BUILD-VERSION-FILE
+DEF_VER=2.0.GIT
+
+# First see if there is a version file (included in release tarballs),
+# then try git-describe, then default.
+if test -f version
+then
+ VN=$(cat version) || VN="$DEF_VER"
+elif test -d .git -o -f .git && type git >/dev/null
+then
+ VN=$(git describe --tags --dirty 2>/dev/null)
+else
+ VN="$DEF_VER"
+fi
+
+if test -r $FBVF
+then
+ VC=$(sed -e 's/^FISH_BUILD_VERSION = //' <$FBVF)
+else
+ VC=unset
+fi
+test "$VN" = "$VC" || {
+ echo >&2 "FISH_BUILD_VERSION = $VN"
+ echo "FISH_BUILD_VERSION = $VN" >$FBVF
+}
diff --git a/build_tools/make_tarball.sh b/build_tools/make_tarball.sh
index b74fc9c4..f16171d1 100755
--- a/build_tools/make_tarball.sh
+++ b/build_tools/make_tarball.sh
@@ -19,8 +19,12 @@ wd="$PWD"
# The name of the prefix, which is the directory that you get when you untar
prefix="fish"
+# Get the version from git-describe
+VERSION=`git describe --tags --dirty 2>/dev/null`
+prefix="$prefix-$VERSION"
+
# The path where we will output the tar file
-path=~/fish_built/fish-2.0.tar
+path=~/fish_built/$prefix.tar
# Clean up stuff we've written before
rm -f "$path" "$path".gz
@@ -28,14 +32,22 @@ rm -f "$path" "$path".gz
# git starts the archive
git archive --format=tar --prefix="$prefix"/ master > "$path"
-# tarball out the documentation
-make user_doc
-make share/man
+# tarball out the documentation, generate a configure script and version file
+# Don't use autoreconf since it invokes commands that may not be installed, like aclocal
+# Don't run autoheader since configure.ac runs it. autoconf is enough.
+autoconf
+./configure --with-doxygen
+make user_doc share/man
+echo $VERSION > version
cd /tmp
rm -f "$prefix"
ln -s "$wd" "$prefix"
-gnutar --append --file="$path" "$prefix"/user_doc/html
-gnutar --append --file="$path" "$prefix"/share/man
+TAR_APPEND="gnutar --append --file=$path --mtime=now --owner=0 --group=0 --mode=g+w,a+rX"
+$TAR_APPEND --no-recursion "$prefix"/user_doc
+$TAR_APPEND "$prefix"/user_doc/html "$prefix"/share/man
+$TAR_APPEND "$prefix"/version
+$TAR_APPEND "$prefix"/configure "$prefix"/config.h.in
+rm -f "$prefix"/version
rm -f "$prefix"
# gzip it
diff --git a/builtin.cpp b/builtin.cpp
index 90fb099b..06c9a9b8 100644
--- a/builtin.cpp
+++ b/builtin.cpp
@@ -1600,30 +1600,43 @@ static int builtin_echo(parser_t &parser, wchar_t **argv)
bool print_newline = true, print_spaces = true, interpret_special_chars = false;
while (*argv)
{
- if (! wcscmp(*argv, L"-n"))
+ wchar_t *s = *argv, c = *s;
+ if (c == L'-')
{
- print_newline = false;
- }
- else if (! wcscmp(*argv, L"-e"))
- {
- interpret_special_chars = true;
- }
- else if (! wcscmp(*argv, L"-ne"))
- {
- print_newline = false;
- interpret_special_chars = true;
- }
- else if (! wcscmp(*argv, L"-s"))
- {
- // fish-specific extension, which we should try to nix
- print_spaces = false;
- }
- else if (! wcscmp(*argv, L"-E"))
- {
- interpret_special_chars = false;
+ /* Ensure that option is valid */
+ for (++s, c = *s; c != L'\0'; c = *(++s))
+ {
+ if (c != L'n' && c != L'e' && c != L's' && c != L'E')
+ {
+ goto invalid_echo_option;
+ }
+ }
+
+ /* Parse option */
+ for (s = *argv, ++s, c = *s; c != L'\0'; c = *(++s))
+ {
+ switch (c)
+ {
+ case L'n':
+ print_newline = false;
+ break;
+ case L'e':
+ interpret_special_chars = true;
+ break;
+ case L's':
+ // fish-specific extension,
+ // which we should try to nix
+ print_spaces = false;
+ break;
+ case L'E':
+ interpret_special_chars = false;
+ break;
+ }
+ }
}
else
{
+ invalid_echo_option:
break;
}
argv++;
@@ -3016,7 +3029,7 @@ static int builtin_source(parser_t &parser, wchar_t ** argv)
if ((fd = wopen_cloexec(argv[1], O_RDONLY)) == -1)
{
append_format(stderr_buffer, _(L"%ls: Error encountered while sourcing file '%ls':\n"), argv[0], argv[1]);
- builtin_wperror(L".");
+ builtin_wperror(L"source");
return STATUS_BUILTIN_ERROR;
}
@@ -3024,7 +3037,7 @@ static int builtin_source(parser_t &parser, wchar_t ** argv)
{
close(fd);
append_format(stderr_buffer, _(L"%ls: Error encountered while sourcing file '%ls':\n"), argv[0], argv[1]);
- builtin_wperror(L".");
+ builtin_wperror(L"source");
return STATUS_BUILTIN_ERROR;
}
@@ -4110,7 +4123,6 @@ int builtin_parse(parser_t &parser, wchar_t **argv)
*/
static const builtin_data_t builtin_datas[]=
{
- { L".", &builtin_source, N_(L"Evaluate contents of file") },
{ L"[", &builtin_test, N_(L"Test a condition") },
{ L"and", &builtin_generic, N_(L"Execute command if previous command suceeded") },
{ L"begin", &builtin_begin, N_(L"Create a block of code") },
@@ -4151,6 +4163,7 @@ static const builtin_data_t builtin_datas[]=
{ L"return", &builtin_return, N_(L"Stop the currently evaluated function") },
{ L"set", &builtin_set, N_(L"Handle environment variables") },
{ L"set_color", &builtin_set_color, N_(L"Set the terminal color") },
+ { L"source", &builtin_source, N_(L"Evaluate contents of file") },
{ L"status", &builtin_status, N_(L"Return status information about fish") },
{ L"switch", &builtin_switch, N_(L"Conditionally execute a block of commands") },
{ L"test", &builtin_test, N_(L"Test a condition") },
diff --git a/builtin_commandline.cpp b/builtin_commandline.cpp
index c1bf7de0..5564d05b 100644
--- a/builtin_commandline.cpp
+++ b/builtin_commandline.cpp
@@ -169,7 +169,11 @@ static void write_part(const wchar_t *begin,
out.push_back(L'\n');
break;
}
-
+
+ default:
+ {
+ break;
+ }
}
}
diff --git a/builtin_set_color.cpp b/builtin_set_color.cpp
index 14cf84ca..6e8f55b0 100644
--- a/builtin_set_color.cpp
+++ b/builtin_set_color.cpp
@@ -152,14 +152,14 @@ static int builtin_set_color(parser_t &parser, wchar_t **argv)
}
const rgb_color_t fg = rgb_color_t(fgcolor ? fgcolor : L"");
- if (fgcolor && fg.is_none())
+ if (fgcolor && (fg.is_none() || fg.is_ignore()))
{
append_format(stderr_buffer, _(L"%ls: Unknown color '%ls'\n"), argv[0], fgcolor);
return STATUS_BUILTIN_ERROR;
}
const rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : L"");
- if (bgcolor && bg.is_none())
+ if (bgcolor && (bg.is_none() || bg.is_ignore()))
{
append_format(stderr_buffer, _(L"%ls: Unknown color '%ls'\n"), argv[0], bgcolor);
return STATUS_BUILTIN_ERROR;
@@ -212,7 +212,7 @@ static int builtin_set_color(parser_t &parser, wchar_t **argv)
if (fgcolor != NULL)
{
- if (fg.is_normal())
+ if (fg.is_normal() || fg.is_reset())
{
write_foreground_color(0);
writembs(tparm(exit_attribute_mode));
@@ -225,7 +225,7 @@ static int builtin_set_color(parser_t &parser, wchar_t **argv)
if (bgcolor != NULL)
{
- if (! bg.is_normal())
+ if (! bg.is_normal() && ! bg.is_reset())
{
write_background_color(index_for_color(bg));
}
diff --git a/builtin_test.cpp b/builtin_test.cpp
index 7f1792f1..0d16823a 100644
--- a/builtin_test.cpp
+++ b/builtin_test.cpp
@@ -23,12 +23,6 @@ enum
int builtin_test(parser_t &parser, wchar_t **argv);
-static const wchar_t * const condstr[] =
-{
- L"!", L"&&", L"||", L"==", L"!=", L"<", L">", L"-nt", L"-ot", L"-ef", L"-eq",
- L"-ne", L"-lt", L"-gt", L"-le", L"-ge", L"=~"
-};
-
namespace test_expressions
{
@@ -39,13 +33,15 @@ enum token_t
test_bang, // "!", inverts sense
test_filetype_b, // "-b", for block special files
- test_filetype_c, // "-c" for character special files
- test_filetype_d, // "-d" for directories
- test_filetype_e, // "-e" for files that exist
- test_filetype_f, // "-f" for for regular files
- test_filetype_g, // "-g" for set-group-id
- test_filetype_h, // "-h" for symbolic links
+ test_filetype_c, // "-c", for character special files
+ test_filetype_d, // "-d", for directories
+ test_filetype_e, // "-e", for files that exist
+ test_filetype_f, // "-f", for for regular files
+ test_filetype_G, // "-G", for check effective group id
+ test_filetype_g, // "-g", for set-group-id
+ test_filetype_h, // "-h", for symbolic links
test_filetype_L, // "-L", same as -h
+ test_filetype_O, // "-O", for check effective user id
test_filetype_p, // "-p", for FIFO
test_filetype_S, // "-S", socket
@@ -101,9 +97,11 @@ static const struct token_info_t
{test_filetype_d, L"-d", UNARY_PRIMARY},
{test_filetype_e, L"-e", UNARY_PRIMARY},
{test_filetype_f, L"-f", UNARY_PRIMARY},
+ {test_filetype_G, L"-G", UNARY_PRIMARY},
{test_filetype_g, L"-g", UNARY_PRIMARY},
{test_filetype_h, L"-h", UNARY_PRIMARY},
{test_filetype_L, L"-L", UNARY_PRIMARY},
+ {test_filetype_O, L"-O", UNARY_PRIMARY},
{test_filetype_p, L"-p", UNARY_PRIMARY},
{test_filetype_S, L"-S", UNARY_PRIMARY},
{test_filesize_s, L"-s", UNARY_PRIMARY},
@@ -818,25 +816,31 @@ static bool unary_primary_evaluate(test_expressions::token_t token, const wcstri
case test_filetype_b: // "-b", for block special files
return !wstat(arg, &buf) && S_ISBLK(buf.st_mode);
- case test_filetype_c: // "-c" for character special files
+ case test_filetype_c: // "-c", for character special files
return !wstat(arg, &buf) && S_ISCHR(buf.st_mode);
- case test_filetype_d: // "-d" for directories
+ case test_filetype_d: // "-d", for directories
return !wstat(arg, &buf) && S_ISDIR(buf.st_mode);
- case test_filetype_e: // "-e" for files that exist
+ case test_filetype_e: // "-e", for files that exist
return !wstat(arg, &buf);
- case test_filetype_f: // "-f" for for regular files
+ case test_filetype_f: // "-f", for for regular files
return !wstat(arg, &buf) && S_ISREG(buf.st_mode);
- case test_filetype_g: // "-g" for set-group-id
+ case test_filetype_G: // "-G", for check effective group id
+ return !wstat(arg, &buf) && getegid() == buf.st_gid;
+
+ case test_filetype_g: // "-g", for set-group-id
return !wstat(arg, &buf) && (S_ISGID & buf.st_mode);
- case test_filetype_h: // "-h" for symbolic links
+ case test_filetype_h: // "-h", for symbolic links
case test_filetype_L: // "-L", same as -h
return !lwstat(arg, &buf) && S_ISLNK(buf.st_mode);
+ case test_filetype_O: // "-O", for check effective user id
+ return !wstat(arg, &buf) && geteuid() == buf.st_uid;
+
case test_filetype_p: // "-p", for FIFO
return !wstat(arg, &buf) && S_ISFIFO(buf.st_mode);
diff --git a/complete.cpp b/complete.cpp
index 8fbcb1d3..8df02b35 100644
--- a/complete.cpp
+++ b/complete.cpp
@@ -312,20 +312,6 @@ completion_t &completion_t::operator=(const completion_t &him)
return *this;
}
-bool completion_t::operator < (const completion_t& rhs) const
-{
- return this->completion < rhs.completion;
-}
-
-bool completion_t::operator == (const completion_t& rhs) const
-{
- return this->completion == rhs.completion;
-}
-
-bool completion_t::operator != (const completion_t& rhs) const
-{
- return !(*this == rhs);
-}
wcstring_list_t completions_to_wcstring_list(const std::vector<completion_t> &list)
{
@@ -338,11 +324,17 @@ wcstring_list_t completions_to_wcstring_list(const std::vector<completion_t> &li
return strings;
}
-void sort_completions(std::vector<completion_t> &completions)
+bool completion_t::is_alphabetically_less_than(const completion_t &a, const completion_t &b)
+{
+ return a.completion < b.completion;
+}
+
+bool completion_t::is_alphabetically_equal_to(const completion_t &a, const completion_t &b)
{
- std::sort(completions.begin(), completions.end());
+ return a.completion == b.completion;
}
+
/** Class representing an attempt to compute completions */
class completer_t
{
@@ -1149,22 +1141,18 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
if (cdpath.missing_or_empty())
cdpath = L".";
- if (str_cmd.find(L'/') != wcstring::npos || str_cmd.at(0) == L'~')
+ if (use_command)
{
- if (use_command)
+ if (expand_string(str_cmd, this->completions, ACCEPT_INCOMPLETE | EXECUTABLES_ONLY | this->expand_flags()) != EXPAND_ERROR)
{
-
- if (expand_string(str_cmd, this->completions, ACCEPT_INCOMPLETE | EXECUTABLES_ONLY | this->expand_flags()) != EXPAND_ERROR)
+ if (this->wants_descriptions())
{
- if (this->wants_descriptions())
- {
- this->complete_cmd_desc(str_cmd);
- }
+ this->complete_cmd_desc(str_cmd);
}
}
}
- else
+ if (str_cmd.find(L'/') == wcstring::npos && str_cmd.at(0) != L'~')
{
if (use_command)
{
@@ -1624,7 +1612,7 @@ void completer_t::complete_param_expand(const wcstring &sstr, bool do_file)
comp_str = str;
}
- expand_flags_t flags = EXPAND_SKIP_CMDSUBST | ACCEPT_INCOMPLETE;
+ expand_flags_t flags = EXPAND_SKIP_CMDSUBST | ACCEPT_INCOMPLETE | this->expand_flags();
if (! do_file)
flags |= EXPAND_SKIP_WILDCARDS;
@@ -1633,9 +1621,13 @@ void completer_t::complete_param_expand(const wcstring &sstr, bool do_file)
if (this->type() == COMPLETE_AUTOSUGGEST || do_file)
flags |= EXPAND_NO_DESCRIPTIONS;
+ /* Don't do fuzzy matching for files if the string begins with a dash (#568). We could consider relaxing this if there was a preceding double-dash argument */
+ if (string_prefixes_string(L"-", sstr))
+ flags &= ~EXPAND_FUZZY_MATCH;
+
if (expand_string(comp_str,
this->completions,
- flags | this->expand_flags()) == EXPAND_ERROR)
+ flags ) == EXPAND_ERROR)
{
debug(3, L"Error while expanding string '%ls'", comp_str);
}
@@ -1919,6 +1911,11 @@ void complete(const wcstring &cmd, std::vector<completion_t> &comps, completion_
end_loop=1;
break;
}
+
+ default:
+ {
+ break;
+ }
}
if (tok_get_pos(&tok) >= (long)pos)
diff --git a/complete.h b/complete.h
index da94bacd..84b84482 100644
--- a/complete.h
+++ b/complete.h
@@ -127,11 +127,10 @@ 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 &);
-
- /* The following are needed for sorting and uniquing completions */
- bool operator < (const completion_t& rhs) const;
- bool operator == (const completion_t& rhs) const;
- bool operator != (const completion_t& rhs) const;
+
+ /* 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);
};
enum
@@ -146,9 +145,6 @@ typedef uint32_t completion_request_flags_t;
/** Given a list of completions, returns a list of their completion fields */
wcstring_list_t completions_to_wcstring_list(const std::vector<completion_t> &completions);
-/** Sorts a list of completions */
-void sort_completions(std::vector<completion_t> &completions);
-
/**
Add a completion.
diff --git a/config.guess b/config.guess
index ec46d18c..d622a44e 100755
--- a/config.guess
+++ b/config.guess
@@ -1,10 +1,10 @@
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
-# Inc.
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+# 2011, 2012 Free Software Foundation, Inc.
-timestamp='2006-02-27'
+timestamp='2012-02-10'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -17,9 +17,7 @@ timestamp='2006-02-27'
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@@ -27,16 +25,16 @@ timestamp='2006-02-27'
# the same distribution terms that you use for the rest of that program.
-# Originally written by Per Bothner <per@bothner.com>.
-# Please send patches to <config-patches@gnu.org>. Submit a context
-# diff and a properly formatted ChangeLog entry.
+# Originally written by Per Bothner. Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
#
# This script attempts to guess a canonical system name similar to
# config.sub. If it succeeds, it prints the system name on stdout, and
# exits with 0. Otherwise, it exits with 1.
#
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit build system type.
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
me=`echo "$0" | sed -e 's,.*/,,'`
@@ -56,7 +54,8 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
@@ -144,7 +143,7 @@ UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:NetBSD:*:*)
# NetBSD (nbsd) targets should (where applicable) match one or
- # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
# *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
# switched to ELF, *-*-netbsd* would select the old
# object file format. This provides both forward
@@ -161,6 +160,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
*) machine=${UNAME_MACHINE_ARCH}-unknown ;;
esac
# The Operating System including object format, if it has switched
@@ -169,7 +169,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
- | grep __ELF__ >/dev/null
+ | grep -q __ELF__
then
# Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
# Return netbsd for either. FIX?
@@ -179,7 +179,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
fi
;;
*)
- os=netbsd
+ os=netbsd
;;
esac
# The OS release
@@ -211,7 +211,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
exit ;;
macppc:MirBSD:*:*)
- echo powerppc-unknown-mirbsd${UNAME_RELEASE}
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
exit ;;
*:MirBSD:*:*)
echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
@@ -222,7 +222,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
;;
*5.*)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
;;
esac
# According to Compaq, /usr/sbin/psrinfo has been available on
@@ -268,7 +268,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- exit ;;
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
Alpha\ *:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# Should we change UNAME_MACHINE based on the output of uname instead
@@ -294,7 +297,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
echo s390-ibm-zvmoe
exit ;;
*:OS400:*:*)
- echo powerpc-ibm-os400
+ echo powerpc-ibm-os400
exit ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
@@ -323,14 +326,33 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
case `/usr/bin/uname -p` in
sparc) echo sparc-icl-nx7; exit ;;
esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
sun4H:SunOS:5.*:*)
echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
- i86pc:SunOS:5.*:*)
- echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
@@ -374,23 +396,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# MiNT. But MiNT is downward compatible to TOS, so this should
# be no problem.
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
+ echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
+ exit ;;
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
+ echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
- echo m68k-milan-mint${UNAME_RELEASE}
- exit ;;
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
- echo m68k-hades-mint${UNAME_RELEASE}
- exit ;;
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
- echo m68k-unknown-mint${UNAME_RELEASE}
- exit ;;
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
m68k:machten:*:*)
echo m68k-apple-machten${UNAME_RELEASE}
exit ;;
@@ -460,8 +482,8 @@ EOF
echo m88k-motorola-sysv3
exit ;;
AViiON:dgux:*:*)
- # DG/UX returns AViiON for all architectures
- UNAME_PROCESSOR=`/usr/bin/uname -p`
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
then
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
@@ -474,7 +496,7 @@ EOF
else
echo i586-dg-dgux${UNAME_RELEASE}
fi
- exit ;;
+ exit ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
echo m88k-dolphin-sysv3
exit ;;
@@ -531,7 +553,7 @@ EOF
echo rs6000-ibm-aix3.2
fi
exit ;;
- *:AIX:*:[45])
+ *:AIX:*:[4567])
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
IBM_ARCH=rs6000
@@ -574,52 +596,52 @@ EOF
9000/[678][0-9][0-9])
if [ -x /usr/bin/getconf ]; then
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
- case "${sc_cpu_version}" in
- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
- 532) # CPU_PA_RISC2_0
- case "${sc_kernel_bits}" in
- 32) HP_ARCH="hppa2.0n" ;;
- 64) HP_ARCH="hppa2.0w" ;;
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
'') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
- esac ;;
- esac
+ esac ;;
+ esac
fi
if [ "${HP_ARCH}" = "" ]; then
eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
+ sed 's/^ //' << EOF >$dummy.c
- #define _HPUX_SOURCE
- #include <stdlib.h>
- #include <unistd.h>
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
- int main ()
- {
- #if defined(_SC_KERNEL_BITS)
- long bits = sysconf(_SC_KERNEL_BITS);
- #endif
- long cpu = sysconf (_SC_CPU_VERSION);
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
- case CPU_PA_RISC2_0:
- #if defined(_SC_KERNEL_BITS)
- switch (bits)
- {
- case 64: puts ("hppa2.0w"); break;
- case 32: puts ("hppa2.0n"); break;
- default: puts ("hppa2.0"); break;
- } break;
- #else /* !defined(_SC_KERNEL_BITS) */
- puts ("hppa2.0"); break;
- #endif
- default: puts ("hppa1.0"); break;
- }
- exit (0);
- }
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
EOF
(CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
test -z "$HP_ARCH" && HP_ARCH=hppa
@@ -639,7 +661,7 @@ EOF
# => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
- grep __LP64__ >/dev/null
+ grep -q __LP64__
then
HP_ARCH="hppa2.0w"
else
@@ -710,22 +732,22 @@ EOF
exit ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
echo c1-convex-bsd
- exit ;;
+ exit ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
- exit ;;
+ exit ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
echo c34-convex-bsd
- exit ;;
+ exit ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
echo c38-convex-bsd
- exit ;;
+ exit ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
echo c4-convex-bsd
- exit ;;
+ exit ;;
CRAY*Y-MP:*:*:*)
echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
@@ -749,14 +771,14 @@ EOF
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
@@ -768,38 +790,48 @@ EOF
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit ;;
*:FreeBSD:*:*)
- case ${UNAME_MACHINE} in
- pc98)
- echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case ${UNAME_PROCESSOR} in
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
*)
- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
esac
exit ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
exit ;;
- i*:MINGW*:*)
+ *:MINGW*:*)
echo ${UNAME_MACHINE}-pc-mingw32
exit ;;
- i*:MSYS_NT-*:*:*)
- echo ${UNAME_MACHINE}-pc-mingw32
+ i*:MSYS*:*)
+ echo ${UNAME_MACHINE}-pc-msys
exit ;;
i*:windows32*:*)
- # uname -m includes "-pc" on this system.
- echo ${UNAME_MACHINE}-mingw32
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
exit ;;
i*:PW*:*)
echo ${UNAME_MACHINE}-pc-pw32
exit ;;
- x86:Interix*:[345]*)
- echo i586-pc-interix${UNAME_RELEASE}
- exit ;;
- EM64T:Interix*:[345]*)
- echo x86_64-unknown-interix${UNAME_RELEASE}
- exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
echo i${UNAME_MACHINE}-pc-mks
exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
@@ -829,17 +861,68 @@ EOF
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
exit ;;
+ aarch64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
cris:Linux:*:*)
- echo cris-axis-linux-gnu
+ echo ${UNAME_MACHINE}-axis-linux-gnu
exit ;;
crisv32:Linux:*:*)
- echo crisv32-axis-linux-gnu
+ echo ${UNAME_MACHINE}-axis-linux-gnu
exit ;;
frv:Linux:*:*)
- echo frv-unknown-linux-gnu
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ hexagon:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ LIBC=gnu
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
exit ;;
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
@@ -850,74 +933,33 @@ EOF
m68*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
- mips:Linux:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #undef CPU
- #undef mips
- #undef mipsel
- #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=mipsel
- #else
- #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=mips
- #else
- CPU=
- #endif
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^CPU/{
- s: ::g
- p
- }'`"
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
- ;;
- mips64:Linux:*:*)
+ mips:Linux:*:* | mips64:Linux:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#undef CPU
- #undef mips64
- #undef mips64el
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=mips64el
+ CPU=${UNAME_MACHINE}el
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=mips64
+ CPU=${UNAME_MACHINE}
#else
CPU=
#endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^CPU/{
- s: ::g
- p
- }'`"
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
;;
or32:Linux:*:*)
- echo or32-unknown-linux-gnu
- exit ;;
- ppc:Linux:*:*)
- echo powerpc-unknown-linux-gnu
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
- ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-gnu
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-gnu
exit ;;
- alpha:Linux:*:*)
- case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
- EV5) UNAME_MACHINE=alphaev5 ;;
- EV56) UNAME_MACHINE=alphaev56 ;;
- PCA56) UNAME_MACHINE=alphapca56 ;;
- PCA57) UNAME_MACHINE=alphapca56 ;;
- EV6) UNAME_MACHINE=alphaev6 ;;
- EV67) UNAME_MACHINE=alphaev67 ;;
- EV68*) UNAME_MACHINE=alphaev68 ;;
- esac
- objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
- if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
@@ -927,14 +969,17 @@ EOF
*) echo hppa-unknown-linux-gnu ;;
esac
exit ;;
- parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-gnu
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux
exit ;;
sh64*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
sh*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
@@ -942,75 +987,18 @@ EOF
sparc:Linux:*:* | sparc64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
vax:Linux:*:*)
echo ${UNAME_MACHINE}-dec-linux-gnu
exit ;;
x86_64:Linux:*:*)
- echo x86_64-unknown-linux-gnu
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
- i*86:Linux:*:*)
- # The BFD linker knows what the default object file format is, so
- # first see if it will tell us. cd to the root directory to prevent
- # problems with other programs or directories called `ld' in the path.
- # Set LC_ALL=C to ensure ld outputs messages in English.
- ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
- | sed -ne '/supported targets:/!d
- s/[ ][ ]*/ /g
- s/.*supported targets: *//
- s/ .*//
- p'`
- case "$ld_supported_targets" in
- elf32-i386)
- TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
- ;;
- a.out-i386-linux)
- echo "${UNAME_MACHINE}-pc-linux-gnuaout"
- exit ;;
- coff-i386)
- echo "${UNAME_MACHINE}-pc-linux-gnucoff"
- exit ;;
- "")
- # Either a pre-BFD a.out linker (linux-gnuoldld) or
- # one that does not give us useful --help.
- echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
- exit ;;
- esac
- # Determine whether the default compiler is a.out or elf
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <features.h>
- #ifdef __ELF__
- # ifdef __GLIBC__
- # if __GLIBC__ >= 2
- LIBC=gnu
- # else
- LIBC=gnulibc1
- # endif
- # else
- LIBC=gnulibc1
- # endif
- #else
- #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__sun)
- LIBC=gnu
- #else
- LIBC=gnuaout
- #endif
- #endif
- #ifdef __dietlibc__
- LIBC=dietlibc
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^LIBC/{
- s: ::g
- p
- }'`"
- test x"${LIBC}" != x && {
- echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
- exit
- }
- test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
- ;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both
@@ -1018,11 +1006,11 @@ EOF
echo i386-sequent-sysv4
exit ;;
i*86:UNIX_SV:4.2MP:2.*)
- # Unixware is an offshoot of SVR4, but it has its own version
- # number series starting with 2...
- # I am not positive that other SVR4 systems won't match this,
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
# I just have to hope. -- rms.
- # Use sysv4.2uw... so that sysv4* matches it.
+ # Use sysv4.2uw... so that sysv4* matches it.
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
exit ;;
i*86:OS/2:*:*)
@@ -1039,7 +1027,7 @@ EOF
i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable
exit ;;
- i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
echo i386-unknown-lynxos${UNAME_RELEASE}
exit ;;
i*86:*DOS:*:*)
@@ -1054,7 +1042,7 @@ EOF
fi
exit ;;
i*86:*:5:[678]*)
- # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
case `/bin/uname -X | grep "^Machine"` in
*486*) UNAME_MACHINE=i486 ;;
*Pentium) UNAME_MACHINE=i586 ;;
@@ -1082,10 +1070,13 @@ EOF
exit ;;
pc:*:*:*)
# Left here for compatibility:
- # uname -m prints for DJGPP always 'pc', but it prints nothing about
- # the processor, so we play safe by assuming i386.
- echo i386-pc-msdosdjgpp
- exit ;;
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
Intel:Mach:3*:*)
echo i386-pc-mach3
exit ;;
@@ -1120,8 +1111,18 @@ EOF
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4; exit; } ;;
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
echo m68k-unknown-lynxos${UNAME_RELEASE}
exit ;;
@@ -1134,7 +1135,7 @@ EOF
rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE}
exit ;;
- PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
echo powerpc-unknown-lynxos${UNAME_RELEASE}
exit ;;
SM[BE]S:UNIX_SV:*:*)
@@ -1154,10 +1155,10 @@ EOF
echo ns32k-sni-sysv
fi
exit ;;
- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
- # says <Richard.M.Bartel@ccMail.Census.GOV>
- echo i586-unisys-sysv4
- exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
*:UNIX_System_V:4*:FTX*)
# From Gerald Hewes <hewes@openmarket.com>.
# How about differentiating between stratus architectures? -djm
@@ -1183,11 +1184,11 @@ EOF
exit ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
if [ -d /usr/nec ]; then
- echo mips-nec-sysv${UNAME_RELEASE}
+ echo mips-nec-sysv${UNAME_RELEASE}
else
- echo mips-unknown-sysv${UNAME_RELEASE}
+ echo mips-unknown-sysv${UNAME_RELEASE}
fi
- exit ;;
+ exit ;;
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
echo powerpc-be-beos
exit ;;
@@ -1197,6 +1198,9 @@ EOF
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
echo i586-pc-beos
exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
SX-4:SUPER-UX:*:*)
echo sx4-nec-superux${UNAME_RELEASE}
exit ;;
@@ -1206,6 +1210,15 @@ EOF
SX-6:SUPER-UX:*:*)
echo sx6-nec-superux${UNAME_RELEASE}
exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
Power*:Rhapsody:*:*)
echo powerpc-apple-rhapsody${UNAME_RELEASE}
exit ;;
@@ -1215,6 +1228,16 @@ EOF
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
case $UNAME_PROCESSOR in
+ i386)
+ eval $set_cc_for_build
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ UNAME_PROCESSOR="x86_64"
+ fi
+ fi ;;
unknown) UNAME_PROCESSOR=powerpc ;;
esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
@@ -1230,6 +1253,9 @@ EOF
*:QNX:*:4*)
echo i386-pc-qnx
exit ;;
+ NEO-?:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
NSE-?:NONSTOP_KERNEL:*:*)
echo nse-tandem-nsk${UNAME_RELEASE}
exit ;;
@@ -1275,13 +1301,13 @@ EOF
echo pdp10-unknown-its
exit ;;
SEI:*:*:SEIUX)
- echo mips-sei-seiux${UNAME_RELEASE}
+ echo mips-sei-seiux${UNAME_RELEASE}
exit ;;
*:DragonFly:*:*)
echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit ;;
*:*VMS:*:*)
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
case "${UNAME_MACHINE}" in
A*) echo alpha-dec-vms ; exit ;;
I*) echo ia64-dec-vms ; exit ;;
@@ -1296,6 +1322,12 @@ EOF
i*86:rdos:*:*)
echo ${UNAME_MACHINE}-pc-rdos
exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo ${UNAME_MACHINE}-unknown-esx
+ exit ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2
@@ -1318,11 +1350,11 @@ main ()
#include <sys/param.h>
printf ("m68k-sony-newsos%s\n",
#ifdef NEWSOS4
- "4"
+ "4"
#else
- ""
+ ""
#endif
- ); exit (0);
+ ); exit (0);
#endif
#endif
@@ -1456,9 +1488,9 @@ This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from
- http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
and
- http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
If the version you run ($0) is already up to date, please
send the following data and any information you think might be
diff --git a/config.sub b/config.sub
index ab2c16c0..6205f842 100755
--- a/config.sub
+++ b/config.sub
@@ -1,10 +1,10 @@
#! /bin/sh
# Configuration validation subroutine script.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
-# Inc.
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+# 2011, 2012 Free Software Foundation, Inc.
-timestamp='2006-02-27'
+timestamp='2012-04-18'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
@@ -21,9 +21,7 @@ timestamp='2006-02-27'
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@@ -32,13 +30,16 @@ timestamp='2006-02-27'
# Please send patches to <config-patches@gnu.org>. Submit a context
-# diff and a properly formatted ChangeLog entry.
+# diff and a properly formatted GNU ChangeLog entry.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
# If it is invalid, we print an error message on stderr and exit with code 1.
# Otherwise, we print the canonical config type on stdout and succeed.
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
# that are meaningful with *any* GNU software.
@@ -72,7 +73,8 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
@@ -120,12 +122,18 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
- nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
- uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
+ android-linux)
+ os=-linux-android
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+ ;;
*)
basic_machine=`echo $1 | sed 's/-[^-]*$//'`
if [ $basic_machine != $1 ]
@@ -148,10 +156,13 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
- -apple | -axis | -knuth | -cray)
+ -apple | -axis | -knuth | -cray | -microblaze)
os=
basic_machine=$1
;;
+ -bluegene*)
+ os=-cnk
+ ;;
-sim | -cisco | -oki | -wec | -winbond)
os=
basic_machine=$1
@@ -166,10 +177,10 @@ case $os in
os=-chorusos
basic_machine=$1
;;
- -chorusrdb)
- os=-chorusrdb
+ -chorusrdb)
+ os=-chorusrdb
basic_machine=$1
- ;;
+ ;;
-hiux*)
os=-hiuxwe2
;;
@@ -214,6 +225,12 @@ case $os in
-isc*)
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
+ -lynx*178)
+ os=-lynxos178
+ ;;
+ -lynx*5)
+ os=-lynxos5
+ ;;
-lynx*)
os=-lynxos
;;
@@ -238,23 +255,32 @@ case $basic_machine in
# Some are omitted here because they have special meanings below.
1750a | 580 \
| a29k \
+ | aarch64 | aarch64_be \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
- | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | be32 | be64 \
| bfin \
| c4x | clipper \
| d10v | d30v | dlx | dsp16xx \
- | fr30 | frv \
+ | epiphany \
+ | fido | fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
- | m32r | m32rle | m68000 | m68k | m88k | maxq | mb | microblaze | mcore \
+ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep | metag \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
- | mips64vr | mips64vrel \
+ | mips64octeon | mips64octeonel \
| mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
| mips64vr4100 | mips64vr4100el \
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
@@ -267,31 +293,42 @@ case $basic_machine in
| mipsisa64sr71k | mipsisa64sr71kel \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
+ | moxie \
| mt \
| msp430 \
+ | nds32 | nds32le | nds32be \
| nios | nios2 \
| ns16k | ns32k \
+ | open8 \
| or32 \
| pdp10 | pdp11 | pj | pjl \
- | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | powerpc | powerpc64 | powerpc64le | powerpcle \
| pyramid \
- | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | rl78 | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
- | strongarm \
- | tahoe | thumb | tic4x | tic80 | tron \
- | v850 | v850e \
+ | spu \
+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| we32k \
- | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \
- | z8k)
+ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
basic_machine=$basic_machine-unknown
;;
- m32c)
- basic_machine=$basic_machine-unknown
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
;;
- m6811 | m68hc11 | m6812 | m68hc12)
- # Motorola 68HC11/12.
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
basic_machine=$basic_machine-unknown
os=-none
;;
@@ -301,6 +338,21 @@ case $basic_machine in
basic_machine=mt-unknown
;;
+ strongarm | thumb | xscale)
+ basic_machine=arm-unknown
+ ;;
+ xgate)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ xscaleeb)
+ basic_machine=armeb-unknown
+ ;;
+
+ xscaleel)
+ basic_machine=armel-unknown
+ ;;
+
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
# (2) the word "unknown" tends to confuse beginning users.
@@ -315,29 +367,36 @@ case $basic_machine in
# Recognize the basic CPU types with company name.
580-* \
| a29k-* \
+ | aarch64-* | aarch64_be-* \
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
- | avr-* \
+ | avr-* | avr32-* \
+ | be32-* | be64-* \
| bfin-* | bs2000-* \
- | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
| clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
| elxsi-* \
- | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | hexagon-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \
- | m32r-* | m32rle-* \
+ | le32-* | le64-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
- | m88110-* | m88k-* | maxq-* | mcore-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
- | mips64vr-* | mips64vrel-* \
+ | mips64octeon-* | mips64octeonel-* \
| mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
| mips64vr4100-* | mips64vr4100el-* \
| mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \
@@ -352,29 +411,36 @@ case $basic_machine in
| mmix-* \
| mt-* \
| msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
| nios-* | nios2-* \
| none-* | np1-* | ns16k-* | ns32k-* \
+ | open8-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pyramid-* \
- | romp-* | rs6000-* \
- | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \
- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
- | tahoe-* | thumb-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+ | tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile*-* \
| tron-* \
- | v850-* | v850e-* | vax-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+ | vax-* \
| we32k-* \
- | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \
- | xstormy16-* | xtensa-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
| ymp-* \
- | z8k-*)
+ | z8k-* | z80-*)
;;
- m32c-*)
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
@@ -392,7 +458,7 @@ case $basic_machine in
basic_machine=a29k-amd
os=-udi
;;
- abacus)
+ abacus)
basic_machine=abacus-unknown
;;
adobe68k)
@@ -438,6 +504,10 @@ case $basic_machine in
basic_machine=m68k-apollo
os=-bsd
;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
aux)
basic_machine=m68k-apple
os=-aux
@@ -446,10 +516,35 @@ case $basic_machine in
basic_machine=ns32k-sequent
os=-dynix
;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
c90)
basic_machine=c90-cray
os=-unicos
;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
convex-c1)
basic_machine=c1-convex
os=-bsd
@@ -478,8 +573,8 @@ case $basic_machine in
basic_machine=craynv-cray
os=-unicosmp
;;
- cr16c)
- basic_machine=cr16c-unknown
+ cr16 | cr16-*)
+ basic_machine=cr16-unknown
os=-elf
;;
crds | unos)
@@ -517,6 +612,10 @@ case $basic_machine in
basic_machine=m88k-motorola
os=-sysv3
;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
djgpp)
basic_machine=i586-pc
os=-msdosdjgpp
@@ -632,7 +731,6 @@ case $basic_machine in
i370-ibm* | ibm*)
basic_machine=i370-ibm
;;
-# I'm not sure what "Sysv32" means. Should this be sysv3.2?
i*86v32)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv32
@@ -671,6 +769,14 @@ case $basic_machine in
basic_machine=m68k-isi
os=-sysv
;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
m88k-omron*)
basic_machine=m88k-omron
;;
@@ -682,10 +788,17 @@ case $basic_machine in
basic_machine=ns32k-utek
os=-sysv
;;
+ microblaze)
+ basic_machine=microblaze-xilinx
+ ;;
mingw32)
basic_machine=i386-pc
os=-mingw32
;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
miniframe)
basic_machine=m68000-convergent
;;
@@ -714,10 +827,18 @@ case $basic_machine in
ms1-*)
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
;;
+ msys)
+ basic_machine=i386-pc
+ os=-msys
+ ;;
mvs)
basic_machine=i370-ibm
os=-mvs
;;
+ nacl)
+ basic_machine=le32-unknown
+ os=-nacl
+ ;;
ncr3000)
basic_machine=i486-ncr
os=-sysv4
@@ -782,6 +903,12 @@ case $basic_machine in
np1)
basic_machine=np1-gould
;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
nsr-tandem)
basic_machine=nsr-tandem
;;
@@ -812,6 +939,14 @@ case $basic_machine in
basic_machine=i860-intel
os=-osf
;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
pbd)
basic_machine=sparc-tti
;;
@@ -856,9 +991,10 @@ case $basic_machine in
;;
power) basic_machine=power-ibm
;;
- ppc) basic_machine=powerpc-unknown
+ ppc | ppcbe) basic_machine=powerpc-unknown
;;
- ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ppc-* | ppcbe-*)
+ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppcle | powerpclittle | ppc-le | powerpc-little)
basic_machine=powerpcle-unknown
@@ -913,6 +1049,10 @@ case $basic_machine in
sb1el)
basic_machine=mipsisa64sb1el-unknown
;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
sei)
basic_machine=mips-sei
os=-seiux
@@ -924,6 +1064,9 @@ case $basic_machine in
basic_machine=sh-hitachi
os=-hms
;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
sh64)
basic_machine=sh64-unknown
;;
@@ -945,6 +1088,9 @@ case $basic_machine in
basic_machine=i860-stratus
os=-sysv4
;;
+ strongarm-* | thumb-*)
+ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
sun2)
basic_machine=m68000-sun
;;
@@ -1001,17 +1147,9 @@ case $basic_machine in
basic_machine=t90-cray
os=-unicos
;;
- tic54x | c54x*)
- basic_machine=tic54x-unknown
- os=-coff
- ;;
- tic55x | c55x*)
- basic_machine=tic55x-unknown
- os=-coff
- ;;
- tic6x | c6x*)
- basic_machine=tic6x-unknown
- os=-coff
+ tile*)
+ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
;;
tx39)
basic_machine=mipstx39-unknown
@@ -1080,6 +1218,9 @@ case $basic_machine in
xps | xps100)
basic_machine=xps100-honeywell
;;
+ xscale-* | xscalee[bl]-*)
+ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+ ;;
ymp)
basic_machine=ymp-cray
os=-unicos
@@ -1088,6 +1229,10 @@ case $basic_machine in
basic_machine=z8k-unknown
os=-sim
;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
none)
basic_machine=none-none
os=-none
@@ -1126,7 +1271,7 @@ case $basic_machine in
we32k)
basic_machine=we32k-att
;;
- sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
basic_machine=sh-unknown
;;
sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
@@ -1173,9 +1318,12 @@ esac
if [ x"$os" != x"" ]
then
case $os in
- # First match some system type aliases
- # that might get confused with valid system types.
+ # First match some system type aliases
+ # that might get confused with valid system types.
# -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
-solaris1 | -solaris1.*)
os=`echo $os | sed -e 's|solaris1|sunos4|'`
;;
@@ -1196,10 +1344,11 @@ case $os in
# Each alternative MUST END IN A *, to match a version number.
# -sysv* is not here because it comes later, after sysvr4.
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
- | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
- | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* \
+ | -aos* | -aros* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
@@ -1208,9 +1357,10 @@ case $os in
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
- | -chorusos* | -chorusrdb* \
- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
@@ -1218,7 +1368,7 @@ case $os in
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
- | -skyos* | -haiku* | -rdos*)
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1257,7 +1407,7 @@ case $os in
-opened*)
os=-openedition
;;
- -os400*)
+ -os400*)
os=-os400
;;
-wince*)
@@ -1306,7 +1456,7 @@ case $os in
-sinix*)
os=-sysv4
;;
- -tpf*)
+ -tpf*)
os=-tpf
;;
-triton*)
@@ -1348,6 +1498,11 @@ case $os in
-zvmoe)
os=-zvmoe
;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -nacl*)
+ ;;
-none)
;;
*)
@@ -1370,6 +1525,12 @@ else
# system, and we'll never get to this point.
case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
*-acorn)
os=-riscix1.2
;;
@@ -1379,9 +1540,21 @@ case $basic_machine in
arm*-semi)
os=-aout
;;
- c4x-* | tic4x-*)
- os=-coff
- ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ hexagon-*)
+ os=-elf
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
# This must come before the *-dec entry.
pdp10-*)
os=-tops20
@@ -1400,13 +1573,13 @@ case $basic_machine in
;;
m68000-sun)
os=-sunos3
- # This also exists in the configure program, but was not the
- # default.
- # os=-sunos4
;;
m68*-cisco)
os=-aout
;;
+ mep-*)
+ os=-elf
+ ;;
mips*-cisco)
os=-elf
;;
@@ -1431,7 +1604,7 @@ case $basic_machine in
*-ibm)
os=-aix
;;
- *-knuth)
+ *-knuth)
os=-mmixware
;;
*-wec)
@@ -1536,7 +1709,7 @@ case $basic_machine in
-sunos*)
vendor=sun
;;
- -aix*)
+ -cnk*|-aix*)
vendor=ibm
;;
-beos*)
diff --git a/configure.ac b/configure.ac
index d8a91bef..ea7c592f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,3 @@
-
#
# This file is the main build configuration file for fish. It is used
# to determine your systems capabilities, and tries to adapt fish to
@@ -9,7 +8,12 @@
# configure the build process.
#
-AC_INIT(fish,2.0.0,fish-users@lists.sf.net)
+m4_syscmd([build_tools/git_version_gen.sh 2>/dev/null])
+
+AC_PREREQ([2.60])
+AC_INIT(fish,
+ m4_esyscmd([cut -f 3 -d ' ' FISH-BUILD-VERSION-FILE | tr -d '\n']),
+ fish-users@lists.sf.net)
conf_arg=$@
@@ -93,19 +97,19 @@ fi
# So ensure this happens before we modify CXXFLAGS below
#
-AC_PROG_CXX([clang++ g++ c++])
-AC_PROG_CPP
+AC_PROG_CXX([g++ c++])
AC_PROG_INSTALL
+AC_LANG(C++)
echo "CXXFLAGS: $CXXFLAGS"
#
# Detect directories which may contain additional headers, libraries
# and commands. This needs to be done early - before Autoconf starts
-# to mess with CFLAGS and all the other environemnt variables.
+# to mess with CXXFLAGS and all the other environemnt variables.
#
# This mostly helps OS X users, since fink usually installs out of
-# tree and doesn't update CFLAGS.
+# tree and doesn't update CXXFLAGS.
#
# It also helps FreeBSD which puts libiconv in /usr/local/lib
@@ -115,7 +119,6 @@ for i in /usr/pkg /sw /opt /opt/local /usr/local; do
if test -d $i/include; then
AC_MSG_RESULT(yes)
CXXFLAGS="$CXXFLAGS -I$i/include/"
- CFLAGS="$CFLAGS -I$i/include/"
else
AC_MSG_RESULT(no)
fi
@@ -123,7 +126,7 @@ for i in /usr/pkg /sw /opt /opt/local /usr/local; do
AC_MSG_CHECKING([for $i/lib library directory])
if test -d $i/lib; then
AC_MSG_RESULT(yes)
- LDFLAGS="$LDFLAGS -L$i/lib/ -Wl,-rpath,$i/lib/"
+ LDFLAGS="$LDFLAGS -L$i/lib/"
else
AC_MSG_RESULT(no)
fi
@@ -209,6 +212,7 @@ AS_IF([test "$use_doxygen" != "no"],
AC_MSG_CHECKING([the doxygen version])
doxygen_version=`doxygen --version 2>/dev/null`
AC_MSG_RESULT([$doxygen_version])
+ dnl This requires autoconf 2.60 or newer
AS_VERSION_COMPARE([$doxygen_version], [$doxygen_minimum],
[ if test "$use_doxygen" = auto; then
AC_MSG_WARN([doxygen version $doxygen_version found, but $doxygen_minimum required])
@@ -324,7 +328,7 @@ if test "$glibc" = yes; then
# fallback.h, in order to keep fish working on non-gnu platforms.
#
- CFLAGS="$CFLAGS -D_GNU_SOURCE=1 -D_ISO99_SOURCE=1"
+ CXXFLAGS="$CXXFLAGS -D_GNU_SOURCE=1 -D_ISO99_SOURCE=1"
else
AC_MSG_RESULT(no)
fi
@@ -476,7 +480,7 @@ 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])] )
+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])] )
LIBS_SHARED=$LIBS
LIBS=$LIBS_COMMON
@@ -601,7 +605,7 @@ AC_CHECK_HEADER(
# conditional definition of __EXTENSIONS__, to avoid redundant tests.
#
-XCFLAGS="$CXXFLAGS"
+XCXXFLAGS="$CXXFLAGS"
echo checking how to use -D_XOPEN_SOURCE=600 and -D_POSIX_C_SOURCE=200112L...
local_found_posix_switch=no
@@ -609,7 +613,7 @@ local_found_posix_switch=no
for i in "" "-D_POSIX_C_SOURCE=200112L" "-D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200112L"; do
AC_MSG_CHECKING( if switches \"$i\" works)
- CFLAGS="$XCFLAGS $i"
+ CXXFLAGS="$XCXXFLAGS $i"
#
# Try to run this program, which should test various extensions
@@ -683,7 +687,7 @@ done
#
if test ! x$local_found_posix_switch = xyes; then
- CFLAGS="$XCFLAGS"
+ CXXFLAGS="$XCXXFLAGS"
fi
diff --git a/doc_src/bind.txt b/doc_src/bind.txt
index 614a1495..8c7004d0 100644
--- a/doc_src/bind.txt
+++ b/doc_src/bind.txt
@@ -17,7 +17,7 @@ an escape character, Alt-based key bindings can be written using the
using the \c \\c escape, for example Control-x (^X) can be written as
<tt>\\cx</tt>. Note that Alt-based key bindings are case sensitive and
Control-based key bindings are not. This is a constraint of text-based
-termainls, not \c fish.
+terminals, not \c fish.
The default key binding can be set by specifying a SEQUENCE of the empty
string (that is, <code>''</code>). It will be used whenever no
@@ -46,9 +46,13 @@ bind to the function name. This way it becomes significantly easier to
test the function while editing, and the result is usually more
readable as well.
+If such a script produces output, the script needs to finish by
+calling 'commandline -f repaint' in order to tell fish that a repaint
+is in order.
+
Key bindings are not saved between sessions by default. To save custom
keybindings, edit the \c fish_user_key_bindings function and insert the
-appropirate \c bind statements.
+appropriate \c bind statements.
The following parameters are available:
@@ -56,6 +60,35 @@ The following parameters are available:
- <tt>-K</tt> or <tt>--key-names</tt> Display a list of available key names
- <tt>-f</tt> or <tt>--function-names</tt> Display a list of available input functions
+The following special input functions are available:
+
+- \c backward-char, moves one character to the left
+- \c backward-delete-char, deletes one character of input to the left of the cursor
+- \c backward-kill-line, move everything from the beginning of the line to the cursor to the killring
+- \c backward-kill-word, move the word to the left of the cursor to the killring
+- \c backward-word, move one word to the left
+- \c beginning-of-history, move to the beginning of the history
+- \c beginning-of-line, move to the beginning of the line
+- \c capitalize-word, make the current word begin with a capital letter
+- \c complete, guess the remainder of the current token
+- \c delete-char, delete one character to the right of the cursor
+- \c delete-line, delete the entire line
+- \c downcase-word, make the current word lowercase
+- \c dump-functions, print a list of all key-bindings
+- \c end-of-history, move to the end of the history
+- \c end-of-line, move to the end of the line
+- \c explain, print a description of possible problems with the current command
+- \c forward-char, move one character to the right
+- \c forward-word, move one word to the right
+- \c history-search-backward, search the history for the previous match
+- \c history-search-forward, search the history for the next match
+- \c kill-line, move everything from the cursor to the end of the line to the killring
+- \c kill-whole-line, move the line to the killring
+- \c kill-word, move the next word to the killring
+- \c upcase-word, make the current word uppercase
+- \c yank, insert the latest entry of the killring into the buffer
+- \c yank-pop, rotate to the previous entry of the killring
+
\subsection bind-example Examples
<tt>bind \\cd 'exit'</tt> causes \c fish to exit when Control-d is pressed.
diff --git a/doc_src/commands.hdr.in b/doc_src/commands.hdr.in
index b62a6d56..c29675bd 100644
--- a/doc_src/commands.hdr.in
+++ b/doc_src/commands.hdr.in
@@ -1,6 +1,15 @@
-/** \page commands Commands, functions and builtins bundled with fish
-Fish ships with a large number of builtin commands, shellscript functions and external commands. These are all described below.
+/** \page commands Commands bundled with fish
+
+\htmlonly <div class="fish_left_bar fish_left_little"> \endhtmlonly
+@command_list_toc@
+\htmlonly </div> \endhtmlonly
+\htmlonly
+<div class="fish_right_bar fish_right_big">
+<h1 class="interior_title_borderless">Commands</h1>
+Fish ships with a large number of builtin commands, shellscript functions and external commands. These are all described below.
+\endhtmlonly
@command_list@
+\htmlonly </div> \endhtmlonly
*/
diff --git a/doc_src/design.hdr b/doc_src/design.hdr
index f1047546..b0b4635f 100644
--- a/doc_src/design.hdr
+++ b/doc_src/design.hdr
@@ -1,5 +1,7 @@
/** \page design Design document
+\htmlonly <div class="fish_only_bar"> \endhtmlonly
+
\section design-overview Overview
This is a description of the design principles that have been used to
@@ -132,3 +134,5 @@ Examples:
- The language should be uniform, so that once the user understands the command/argument syntax, he will know the whole language, and be able to use tab-completion to discover new featues.
*/
+
+\htmlonly </div> \endhtmlonly
diff --git a/doc_src/faq.hdr b/doc_src/faq.hdr
index 449c10f4..c727dd5d 100644
--- a/doc_src/faq.hdr
+++ b/doc_src/faq.hdr
@@ -1,5 +1,7 @@
/** \page faq Frequently asked questions
+\htmlonly <div class="fish_left_bar fish_left_big"> \endhtmlonly
+
- <a href='#faq-envvar'>How do I set or clear an environment variable?</a>
- <a href='#faq-login-cmd'>How do I run a command every login? What's fish's equivalent to <tt>.bashrc</tt>?</a>
- <a href='#faq-prompt'>How do I set my prompt?</a>
@@ -18,7 +20,12 @@
- <a href='#faq-history'>Why doesn't history substitution ("!$" etc.) work?</a>
- <a href='#faq-uninstalling'>How do I uninstall fish?</a>
-<hr>
+\htmlonly
+</div>
+<div class="fish_right_bar fish_right_little">
+<h1 class="interior_title">Frequently Asked Questions</h1>
+
+\endhtmlonly
\section faq-envvar How do I set or clear an environment variable?
@@ -29,7 +36,7 @@ set -e key</pre>
<hr>
-\section faq-login-cmd How do I run a command every login? What's fish's equivalent to <tt>.bashrc</tt>?
+\section faq-login-cmd How do I run a command every login? What's fish's equivalent to .bashrc?
Edit the file <tt>~/.config/fish/config.fish</tt>, creating it if it does not
exist. (Note the leading period.)
@@ -263,3 +270,7 @@ rm -f fish mimedb fish_pager fishd fish_indent
</pre>
*/
+
+\htmlonly
+</div>
+\endhtmlonly
diff --git a/doc_src/fish_config.txt b/doc_src/fish_config.txt
index a9627bb2..777f2522 100644
--- a/doc_src/fish_config.txt
+++ b/doc_src/fish_config.txt
@@ -11,7 +11,7 @@ to make changes to your prompt and color configuration.
you have finished, close the browser window and then press the Enter key to
terminate the configuration session.
-There are no parameters for <code>fish_config</code>.
+<code>fish_config</code> optionally accepts name of the initial configuration tab. For e.g. <code>fish_config history</code> will start configuration interface with history tab.
If the \c BROWSER environment variable is set, it will be used as the name
of the web browser to open instead of the system default.
diff --git a/doc_src/function.txt b/doc_src/function.txt
index c072c551..8d8e4519 100644
--- a/doc_src/function.txt
+++ b/doc_src/function.txt
@@ -12,16 +12,19 @@ function is given as a command.
The following options are available:
+- <code>-a NAMES</code> or <code>--argument-names NAMES</code> assigns the value of successive command-line arguments to the names given in NAMES.
- <code>-d DESCRIPTION</code> or \c --description=DESCRIPTION is a description of what the function does, suitable as a completion description.
- <code>-e</code> or <code>--on-event EVENT_NAME</code> tells fish to run this function when the specified named event is emitted. Fish internally generates named events e.g. when showing the prompt.
- <code>-j PID</code> or <code> --on-job-exit PID</code> tells fish to run this function when the job with group ID PID exits. Instead of PID, the string 'caller' can be specified. This is only legal when in a command substitution, and will result in the handler being triggered by the exit of the job which created this command substitution.
- <code>-p PID</code> or <code> --on-process-exit PID</code> tells fish to run this function when the fish child process with process ID PID exits.
- <code>-s</code> or <code>--on-signal SIGSPEC</code> tells fish to run this function when the signal SIGSPEC is delivered. SIGSPEC can be a signal number, or the signal name, such as SIGHUP (or just HUP).
+- \c -S or \c --no-scope-shadowing allows the function to access the variables of calling functions. Normally, any variables inside the function that have the same name as variables from the calling function are "shadowed", and their contents is independent of the calling function.
- <code>-v</code> or <code>--on-variable VARIABLE_NAME</code> tells fish to run this function when the variable VARIABLE_NAME changes value.
If the user enters any additional arguments after the function, they
are inserted into the environment <a href="index.html#variables-arrays">variable array</a>
-<code>$argv</code>.
+<code>$argv</code>. If the \c --argument-names option is provided, the arguments are
+also assigned to names specified in that option.
By using one of the event handler switches, a function can be made to run automatically at specific events. The user may generate new events using the <a href="#emit">emit</a> builtin. Fish generates the following named events:
diff --git a/doc_src/index.hdr.in b/doc_src/index.hdr.in
index 9b674479..f82f309a 100644
--- a/doc_src/index.hdr.in
+++ b/doc_src/index.hdr.in
@@ -1,9 +1,12 @@
/** \mainpage Fish user documentation
-\section toc Table of contents
-
-- <a href="index.html" name="toc-index">Fish user documentation</a>
+\htmlonly <div class="fish_left_bar"> \endhtmlonly
@toc@
+\htmlonly </div> \endhtmlonly
+
+\htmlonly
+<div class="fish_right_bar">
+\endhtmlonly
\section introduction Introduction
@@ -376,6 +379,20 @@ Help on a specific builtin can also be obtained with the <code>-h</code>
parameter. For instance, to obtain help on the \c fg builtin, either
type <code>fg -h</code> or <code>help fg</code>.
+\section autosuggestions Autosuggestions
+
+fish suggests commands as you type, based on command history, completions,
+and valid file paths. As you type commands, you will see a completion offered after the
+cursor, in a muted gray color (which can be changed with the
+<code>fish_color_autosuggestion</code> variable).
+
+To accept the autosuggestion (replacing the command line contents),
+hit right arrow or Control-F. If the autosuggestion is not what you want,
+just ignore it: it won't execute unless you accept it.
+
+Autosuggestions are a powerful way to quickly summon frequently entered commands, by
+typing the first few characters. They are also an efficient technique for navigating
+through directory hierarchies.
\section completion Tab completion
@@ -795,7 +812,7 @@ To set the variable \c smurf_color to the value \c blue, use the command
<code>set smurf_color blue</code>.
After a variable has been set, you can use the value of a variable in
-the shell through <a href="expand-variable">variable expansion</a>.
+the shell through <a href="#expand-variable">variable expansion</a>.
Example:
@@ -1102,57 +1119,30 @@ shortcuts.
Here are some of the commands available in the editor:
-- Tab <a href="#completion">completes</a> the current token
-- Home or Ctrl-A moves to the beginning of the line
-- End or Ctrl-E moves to the end of line
-- Left and Right moves one character left or right
-- Alt-Left and Alt-Right moves one word left or right, or moves forward/backward in the directory history if the commandline is empty
+- Tab <a href="#completion">completes</a> the current token.
+- Home or Ctrl-A moves the cursor to the beginning of the line.
+- End or Ctrl-E moves to the end of line. If the cursor is already at the end of the line, and an autosuggestion is available, End or Ctrl-E accepts the autosuggestion.
+- Left (or Ctrl-B) and Right (or Ctrl-F) move the cursor left or right by one character. If the cursor is already at the end of the line, and an autosuggestion is available, the Right key and the Ctrl-F combination accept the suggestion.
+- Alt-Left and Alt-Right move the cursor one word left or right, or moves forward/backward in the directory history if the command line is empty.
- Up and Down search the command history for the previous/next command containing the string that was specified on the commandline before the search was started. If the commandline was empty when the search started, all commands match. See the <a href='#history'>history </a>section for more information on history searching.
- Alt-Up and Alt-Down search the command history for the previous/next token containing the token under the cursor before the search was started. If the commandline was not on a token when the search started, all tokens match. See the <a href='#history'>history </a>section for more information on history searching.
-- Delete and Backspace removes one character forwards or backwards respectively
-- Ctrl-C deletes entire line
-- Ctrl-D delete one character to the right of the cursor, unless the buffer is empty, in which case the shell will exit
-- Ctrl-K moves contents from the cursor to the end of line to the <a href="#killring">killring</a>
-- Ctrl-U moves contents from the beginning of line to the cursor to the <a href="#killring">killring</a>
-- Ctrl-L clears and repaints the screen
-- Ctrl-W moves the previous word to the <a href="#killring">killring</a>
-- Alt-D moves the next word to the <a href="#killring">killring</a>
-- Alt-W prints a short description of the command under the cursor
-- Alt-L lists the contents of the current directory, unless the cursor is over a directory argument, in which case the contents of that directory will be listed
+- Delete and Backspace removes one character forwards or backwards respectively.
+- Ctrl-C deletes the entire line.
+- Ctrl-D delete one character to the right of the cursor. If the command line is empty, Ctrl-D will exit fish.
+- Ctrl-K moves contents from the cursor to the end of line to the <a href="#killring">killring</a>.
+- Ctrl-U moves contents from the beginning of line to the cursor to the <a href="#killring">killring</a>.
+- Ctrl-L clears and repaints the screen.
+- Ctrl-W moves the previous word to the <a href="#killring">killring</a>.
+- Alt-D moves the next word to the <a href="#killring">killring</a>.
+- Alt-W prints a short description of the command under the cursor.
+- Alt-L lists the contents of the current directory, unless the cursor is over a directory argument, in which case the contents of that directory will be listed.
- 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.
You can change these key bindings using the
<a href="commands.html#bind">bind</a> builtin command.
-
-- \c backward-char, moves one character to the left
-- \c backward-delete-char, deletes one character of input to the left of the cursor
-- \c backward-kill-line, move everything from the beginning of the line to the cursor to the killring
-- \c backward-kill-word, move the word to the left of the cursor to the killring
-- \c backward-word, move one word to the left
-- \c beginning-of-history, move to the beginning of the history
-- \c beginning-of-line, move to the beginning of the line
-- \c complete, guess the remainder of the current token
-- \c delete-char, delete one character to the right of the cursor
-- \c delete-line, delete the entire line
-- \c dump-functions, print a list of all key-bindings
-- \c end-of-history, move to the end of the history
-- \c end-of-line, move to the end of the line
-- \c explain, print a description of possible problems with the current command
-- \c forward-char, move one character to the right
-- \c forward-word, move one word to the right
-- \c history-search-backward, search the history for the previous match
-- \c history-search-forward, search the history for the next match
-- \c kill-line, move everything from the cursor to the end of the line to the killring
-- \c kill-whole-line, move the line to the killring
-- \c kill-word, move the next word to the killring
-- \c yank, insert the latest entry of the killring into the buffer
-- \c yank-pop, rotate to the previous entry of the killring
-
-If such a script produces output, the script needs to finish by
-calling 'commandline -f repaint' in order to tell fish that a repaint
-is in order.
-
\subsection killring Copy and paste (Kill Ring)
\c fish uses an Emacs style kill ring for copy and paste
@@ -1390,3 +1380,5 @@ If you have an improvement for fish, you can submit it via the mailing list
or the GitHub page.
*/
+
+\htmlonly </div> \endhtmlonly
diff --git a/doc_src/license.hdr b/doc_src/license.hdr
index 2225a085..64bab10f 100644
--- a/doc_src/license.hdr
+++ b/doc_src/license.hdr
@@ -1,5 +1,7 @@
/** \page license Licenses
+\htmlonly <div class="fish_only_bar"> \endhtmlonly
+
<h2>License for fish</h2>
Fish Copyright (C) 2005-2009 Axel Liljencrantz. Fish is released under
@@ -1399,3 +1401,5 @@ POSSIBILITY OF SUCH DAMAGES.
<P>
*/
+
+\htmlonly </div> \endhtmlonly
diff --git a/doc_src/nextd.txt b/doc_src/nextd.txt
index dba94ce0..297063af 100644
--- a/doc_src/nextd.txt
+++ b/doc_src/nextd.txt
@@ -12,7 +12,8 @@ directory history is also displayed.
\subsection nextd-example Example
-<pre>cd /usr/src
+\code
+cd /usr/src
# Working directory is now /usr/src
cd /usr/src/fish-shell
# Working directory is now /usr/src/fish-shell
@@ -20,3 +21,4 @@ prevd
# Working directory is now /usr/src
nextd
# Working directory is now /usr/src/fish-shell</pre>
+\endcode
diff --git a/doc_src/prevd.txt b/doc_src/prevd.txt
index b72fc375..e49faff2 100644
--- a/doc_src/prevd.txt
+++ b/doc_src/prevd.txt
@@ -14,7 +14,8 @@ history is also displayed.
\subsection prevd-example Example
-<pre>cd /usr/src
+\code
+cd /usr/src
# Working directory is now /usr/src
cd /usr/src/fish-shell
# Working directory is now /usr/src/fish-shell
@@ -22,3 +23,4 @@ prevd
# Working directory is now /usr/src
nextd
# Working directory is now /usr/src/fish-shell</pre>
+\endcode
diff --git a/doc_src/source.txt b/doc_src/source.txt
index 06958375..c49e2491 100644
--- a/doc_src/source.txt
+++ b/doc_src/source.txt
@@ -1,11 +1,11 @@
-\section source . - evaluate contents of file.
+\section source source - evaluate contents of file.
\subsection source-synopsis Synopsis
-<tt>. FILENAME [ARGUMENTS...]</tt>
+<tt>source FILENAME [ARGUMENTS...]</tt>
\subsection source-description Description
-\c . (source) evaluates the commands of the specified file in the current
+\c source evaluates the commands of the specified file in the current
shell. This is different from starting a new process to perform the
commands (i.e. <tt>fish < FILENAME</tt>) since the commands will be
evaluated by the current shell, which means that changes in
@@ -16,11 +16,11 @@ variable.
If no file is specified, or if the file name '-' is used, stdin will
be read.
-The return status of \c . is the return status of the last job to
+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 . exits with a non-zero status.
+\c source exits with a non-zero status.
\subsection source-example Example
-<tt>. ~/.config/fish/config.fish</tt> causes fish to re-read its initialization file.
+<tt>source ~/.config/fish/config.fish</tt> causes fish to re-read its initialization file.
diff --git a/doc_src/test.txt b/doc_src/test.txt
index 600e7ea7..946c5330 100644
--- a/doc_src/test.txt
+++ b/doc_src/test.txt
@@ -6,37 +6,95 @@
\subsection test-description Description
Tests the expression given and sets the exit status to 0 if true,
-and 1 if false.
+and 1 if false. An expression is made up of one or more operators
+and their arguments.
-The following options are available:
-- \c -h displays a help message and then exits.
-- <tt>-L FILE</tt> returns true if \c FILE is a symbolic link.
-- <tt>-S FILE</tt> returns true if \c FILE is a socket.
-- <tt>COND1 -a COND2</tt> combines two conditions with a logical and.
+The following operators are available to examine files and directories:
- <tt>-b FILE</tt> returns true if \c FILE is a block device.
- <tt>-c FILE</tt> returns true if \c FILE is a character device.
- <tt>-d FILE</tt> returns true if \c FILE is a directory.
- <tt>-e FILE</tt> returns true if \c FILE exists.
- <tt>-f FILE</tt> returns true if \c FILE is a regular file.
-- <tt>-f FILE</tt> returns true if \c FILE has set-group-ID bit set.
-- <tt>-n STRING</tt> returns true if the length of \c STRING is non-zero.
-- <tt>COND1 -o COND2</tt> combines two conditions with a logical or.
+- <tt>-g FILE</tt> returns true if \c FILE has the set-group-ID bit set.
+- <tt>-G FILE</tt> returns true if \c FILE exists and has the same group ID
+as the current user.
+- <tt>-L FILE</tt> returns true if \c FILE is a symbolic link.
+- <tt>-O FILE</tt> returns true if \c FILE exists and is owned by the current
+user.
- <tt>-p FILE</tt> returns true if \c FILE is a named pipe.
-- <tt>-r FILE</tt> returns true if \c FILE is readable.
-- <tt>-s FILE</tt> returns true if the size of \c FILE is non-zero.
-- <tt>-t FD</tt> returns true if \c FD is a terminal (TTY).
-- <tt>-u FILE</tt> returns true if \c FILE has set-user-ID bit set.
-- <tt>-w FILE</tt> returns true if \c FILE is writable.
-- <tt>-x FILE</tt> returns true if \c FILE is executable.
-- <tt>-z STRING</tt> returns true if \c STRING length is zero.
+- <tt>-r FILE</tt> returns true if \c FILE is marked as readable.
+- <tt>-s FILE</tt> returns true if the size of \c FILE is greater than zero.
+- <tt>-S FILE</tt> returns true if \c FILE is a socket.
+- <tt>-t FD</tt> returns true if the file descriptor \c FD is a terminal (TTY).
+- <tt>-u FILE</tt> returns true if \c FILE has the set-user-ID bit set.
+- <tt>-w FILE</tt> returns true if \c FILE is marked as writable; note that this does not check if the filesystem is read-only.
+- <tt>-x FILE</tt> returns true if \c FILE is marked as executable.
+
+The following operators are available to compare and examine text strings:
+- <tt>STRING1 = STRING2</tt> returns true if the strings \c STRING1 and
+\c STRING2 are identical.
+- <tt>STRING1 != STRING2</tt> returns true if the strings \c STRING1 and
+\c STRING2 are not identical.
+- <tt>-n STRING</tt> returns true if the length of \c STRING is non-zero.
+- <tt>-z STRING</tt> returns true if the length of \c STRING is zero.
+
+The following operators are available to compare and examine numbers:
+- <tt>NUM1 -eq NUM2</tt> returns true if \c NUM1 and \c NUM2 are numerically equal.
+- <tt>NUM1 -ne NUM2</tt> returns true if \c NUM1 and \c NUM2 are not numerically equal.
+- <tt>NUM1 -gt NUM2</tt> returns true if \c NUM1 is greater than <tt>NUM2</tt>.
+- <tt>NUM1 -ge NUM2</tt> returns true if \c NUM1 is greater than or equal to <tt>NUM2</tt>.
+- <tt>NUM1 -lt NUM2</tt> returns true if \c NUM1 is less than <tt>NUM2</tt>.
+- <tt>NUM1 -le NUM2</tt> returns true if \c NUM1 is less than or equal to <tt>NUM2</tt>.
+
+Note that only integers are supported. For more complex mathematical
+operations, including fractions, the \c env program may be useful. Consult the
+documentation for your operating system.
+
+Expressions can be combined using the following operators:
+- <tt>COND1 -a COND2</tt> returns true if both \c COND1 and \c COND2 are true.
+- <tt>COND1 -o COND2</tt> returns true if either \c COND1 or \c COND2 are true.
+
+Expressions can be inverted using the \c ! operator:
+- <tt>! EXPRESSION</tt> returns true if \c EXPRESSION is false, and false if
+\c EXPRESSION is true.
-\subsection test-example Example
+Expressions can be grouped using parentheses.
+- <tt>( EXPRESSION )</tt> returns the value of <tt>EXPRESSION</tt>.
+Note that parentheses will usually require escaping with <tt>\\(</tt> to avoid
+being interpreted as a command substitution.
+
+\subsection test-example Examples
+
+If the \c /tmp directory exists, copy the \c /etc/motd file to it:
+
+<pre>
+if test -d /tmp
+ cp /etc/motd /tmp/motd
+end
+</pre>
+
+If the variable \c MANPATH is defined and not empty, print the contents:
<pre>
-if test -d "/"
- echo "Fish is cool"
+if test -n $MANPATH
+ echo $MANPATH
end
-</pre>
+</pre>
+
+Parentheses and the \c -o and \c -a operators can be combined to produce
+more complicated expressions. In this example, success is printed if there is
+a \c /foo or \c /bar file as well as a \c /baz or \c /bat file.
+
+<pre>
+if test \\( -f /foo -o -f /bar \\) -a \\( -f /baz -o -f /bat \\)
+ echo Success.
+end.
+</pre>
+
+\subsection test-standards Standards
+
+\c test implements a subset of the
+<a href="http://www.unix.com/man-page/POSIX/1/test/">IEEE Std 1003.1-2008
+(POSIX.1) standard</a>. The following exceptions apply:
+- The \c < and \c > operators for comparing strings are not implemented.
-Because "/" is a directory, the expression will evaluate to true, and
-"Fish is cool" will be output.
diff --git a/doc_src/tutorial.hdr b/doc_src/tutorial.hdr
new file mode 100644
index 00000000..d5cd6948
--- /dev/null
+++ b/doc_src/tutorial.hdr
@@ -0,0 +1,746 @@
+/** \page tutorial Tutorial
+
+\htmlonly
+
+<style type="text/css">
+
+body.tutorial_body {
+ font-family: "Helvetica Neue", Verdana, Helvetica, Arial, sans-serif;
+ font-size: 13pt;
+ background-color: #1E335E;
+ margin: 0;
+}
+
+pre {
+ border: solid #AAA 1px;
+ background-color: black;
+ color: white;
+ padding: 10px 12px;
+ font-size: 10pt;
+ font-family: Menlo, Monaco, "DejaVu Sans Mono", "Courier New", Courier, monospace;
+ line-height: 140%;
+ white-space: pre-wrap;
+ margin-top: 10px;
+ tab-size: 4;
+ -moz-tab-size: 4;
+ -o-tab-size: 4;
+}
+
+p {
+ margin-bottom: 10px;
+ margin-top: 0;
+ color: #333333;
+ line-height: 1.25em;
+}
+
+tt {
+ font-family: monospace;
+}
+
+.suggest {
+ color: #555;
+}
+
+pre u {
+ border-bottom: 2px solid #0F0;
+ text-decoration: none;
+}
+
+.meta {
+ color: white;
+}
+
+pre b {
+ /* Used for commands */
+ color: #005fd7;
+ font-weight: normal;
+}
+
+pre i {
+ /* Used for arguments */
+ color: #00afff;
+ font-style: normal;
+}
+
+pre em {
+ /* Used for path/help word */
+ color: #0a0;
+ font-style: normal;
+}
+
+.quote {
+ color: #A50;
+}
+
+.error {
+ /* Used for errors */
+ color: #F55;
+ font-weight: bold;
+}
+
+.tutorial_nav {
+ position: relative;
+ z-index: 2;
+ margin-left: 10px;
+ margin-top: 15px;
+}
+
+.tutorial_nav ul {
+ padding: 0 15px;
+ margin: 0;
+}
+
+.tutorial_nav li {
+ margin: 0;
+ line-height: normal;
+ height: auto;
+ color: #EEE;
+ font-size: 12pt;
+ font-family: "Trebuchet MS", Verdana, Arial, sans-serif;
+ list-style-image: none;
+ list-style-position: outside;
+ list-style-type: none;
+ padding: 3px 15px;
+ margin: 0 -15px;
+}
+
+.tutorial_nav a {
+ color: inherit;
+ text-decoration: none;
+ font-family:
+ font-size: 12pt;
+}
+
+.tutorial_nav .chevron {
+ font-family: Times, "Times New Roman";
+ color: #DDF;
+ font-size: 16pt;
+ line-height: 10pt;
+ font-weight: bold;
+}
+
+.no_shadow > li > a,
+.no_shadow {
+ text-shadow: none;
+}
+
+.nav > li > a:hover {
+ text-decoration: none;
+ background-color: inherit;
+ color: #99BBFF;
+}
+
+/* Override some default left bar stuff */
+ul.nav li {
+ margin-bottom: 0;
+}
+
+
+.title_top {
+ width: 100%;
+ text-align: left;
+ color: white;
+ font-size: 18pt;
+ height: 72px;
+ z-index: 1;
+ text-indent: 260px;
+}
+
+.tutorial_content {
+ -moz-box-shadow: -5px 0px 5px -2px black;
+ -webkit-box-shadow: -5px 0px 5px -2px black;
+ box-shadow: -5px 0px 5px -2px black;
+
+ margin-left: 280px;
+ padding: 1px 25px 10px 10px;
+ position: relative;
+ z-index: 5;
+ background-color: white;
+}
+
+h3 {
+ font-size: 25px;
+ margin-top: 12px;
+}
+
+h1, h2, h3 { color: #1E335E; }
+h1.interior_title {
+ color: #333;
+ padding-bottom: 10px;
+ border-bottom: 1px solid #AAA;
+}
+
+h1 { font-size: 150%; }
+h2 { font-size: 135%; }
+h3 { font-size: 110%; }
+
+
+
+</style>
+
+
+<div class="fish_left_bar fish_left_medium">
+ <div class="tutorial_nav">
+ <ul class="nav no_shadow">
+ <li><a href="#tut_why_fish"><span class="chevron">&rsaquo;</span> Why fish?</a></li>
+ <li><a href="#tut_learning_Fish"><span class="chevron">&rsaquo;</span> Learning fish</a></li>
+ <li><a href="#tut_running_commands"><span class="chevron">&rsaquo;</span> Running Commands</a></li>
+ <li><a href="#tut_getting_help"><span class="chevron">&rsaquo;</span> Getting Help</a></li>
+ <li><a href="#tut_syntax_highlighting"><span class="chevron">&rsaquo;</span> Syntax Highlighting</a></li>
+ <li><a href="#tut_wildcards"><span class="chevron">&rsaquo;</span> Wildcards</a></li>
+ <li><a href="#tut_pipes_and_redirections"><span class="chevron">&rsaquo;</span> Pipes and Redirections</a></li>
+ <li><a href="#tut_autosuggestions"><span class="chevron">&rsaquo;</span> Autosuggestions</a></li>
+ <li><a href="#tut_tab_completions"><span class="chevron">&rsaquo;</span> Tab Completions</a></li>
+ <li><a href="#tut_variables"><span class="chevron">&rsaquo;</span> Variables</a></li>
+ <li><a href="#tut_exit_status"><span class="chevron">&rsaquo;</span> Exit Status</a></li>
+ <li><a href="#tut_exports"><span class="chevron">&rsaquo;</span> Environment Variables</a></li>
+ <li><a href="#tut_lists"><span class="chevron">&rsaquo;</span> Lists</a></li>
+ <li><a href="#tut_command_substitutions"><span class="chevron">&rsaquo;</span> Command Substitutions</a></li>
+ <li><a href="#tut_combiners"><span class="chevron">&rsaquo;</span> Combiners (And, Or, Not)</a></li>
+ <li><a href="#tut_conditionals"><span class="chevron">&rsaquo;</span> Conditionals (If, Else, Switch)</a></li>
+ <li><a href="#tut_functions"><span class="chevron">&rsaquo;</span> Functions</a></li>
+ <li><a href="#tut_loops"><span class="chevron">&rsaquo;</span> Loops</a></li>
+ <li><a href="#tut_prompt"><span class="chevron">&rsaquo;</span> Prompt</a></li>
+ <li><a href="#tut_startup"><span class="chevron">&rsaquo;</span> Startup</a></li>
+ </ul>
+ </div>
+</div>
+
+<div class="fish_right_bar fish_right_medium">
+
+<h1 class="interior_title">fish tutorial</h1>
+
+<h2 id="tut_why_fish">Why fish?</h2>
+
+<p>fish is a fully-equipped command line shell (like bash or zsh) that is smart and user-friendly. fish supports powerful features like syntax highlighting, autosuggestions, and tab completions that just work, with nothing to learn or configure.
+
+<p>If you want to make your command line more productive, more useful, and more fun, without learning a bunch of arcane syntax and configuration options, then fish might be just what you're looking for!
+
+<h2 id="tut_learning_Fish">Learning fish</h2>
+
+<p>This tutorial assumes a basic understanding of command line shells and Unix commands, and that you have a working copy of fish.
+
+<p>If you have a strong understanding of other shells, and want to know what fish does differently, search for the magic phrase <i>unlike other shells</i>, which is used to call out important differences.
+
+<p>When you start fish, you should see this:
+
+<pre>
+Welcome to fish, the friendly interactive shell
+Type <em>help</em> for instructions on how to use fish
+you@hostname <em>~</em>>
+</pre>
+
+<p>fish comes with a default prompt that shows your username, hostname, and working directory. You'll see <a href="#tut_prompt">how to change your prompt</a> further down. From now on, we'll pretend your prompt is just a '>' to save space.
+
+<h2 id="tut_running_commands">Running Commands</h2>
+
+<p>fish runs commands like other shells: you type a command, followed by its arguments. Spaces are separators:
+
+<pre>
+> <b>echo</b> <i>hello world</i>
+hello world
+</pre>
+
+You can include a literal space in an argument with a backslash, or by using single or double quotes:
+
+<pre>
+> <b>mkdir</b> <i>My\ Files</i>
+> <b>cp</b> <i>~/Some\ File</i> <i class=quote>'My Files'</i>
+> <b>ls</b> <i class=quote>"My Files"</i>
+Some File
+</pre>
+
+Commands can be chained with semicolons.
+
+<h2 id="tut_getting_help">Getting Help</h2>
+
+fish has excellent help and man pages. Run <tt>help</tt> to open help in a web browser, and <tt>man</tt> to open it in a man page. You can also ask for help with a specific command, for example, <tt>help set</tt> to open in a web browser, or <tt>man set</tt> to see it in the terminal.
+
+<pre>
+> <b>man</b> <i>set</i>
+set - handle environment variables
+ Synopsis...
+</pre>
+
+<h2 id="tut_syntax_highlighting">Syntax Highlighting</h2>
+You'll quickly notice that fish performs syntax highlighting as you type. Invalid commands are colored red by default:
+
+<pre>
+> <b class="error">/bin/mkd</b>
+</pre>
+
+A command may be invalid because it does not exist, or refers to a file that you cannot execute. When the command becomes valid, it is shown in a different color:
+
+<pre>
+> <b>/bin/mkdir</b>
+</pre>
+
+fish will underline valid file paths as you type them:
+
+<pre>
+> <b>cat</b> <i><span style="text-decoration: underline">~/somef<u>i</u></span></i>
+</pre>
+
+<p>This tells you that there exists a file that starts with '<tt>somefi</tt>', which is useful feedback as you type.
+
+<p>These colors, and many more, can be changed by running <tt>fish_config</tt>, or by modifying variables directly.
+
+<h2 id="tut_wildcards">Wildcards</h2>
+
+fish supports the familiar wildcard *. To list all JPEG files:
+
+<pre>
+> <b>ls</b> <i>*.jpg</i>
+lena.jpg
+meena.jpg
+santa maria.jpg
+</pre>
+
+<p>You can include multiple wildcards:
+
+<pre>
+> <b>ls</b> <i>l*.p*</i>
+lena.png
+lesson.pdf
+</pre>
+
+<p>Especially powerful is the <i>recursive wildcard</i> ** which searches directories recursively:
+
+<pre>
+> <b>ls</b> <i>/var/**.log</i>
+/var/log/system.log
+/var/run/sntp.log
+</pre>
+
+<p>If that directory traversal is taking a long time, you can control-C out of it.
+
+<h2 id="tut_pipes_and_redirections">Pipes and Redirections</h2>
+
+<p>You can pipe between commands with the usual vertical bar:
+
+<pre>
+> <b>echo</b> <i>hello world</i> | <b>wc</b>
+ 1 2 12
+</pre>
+
+<p>stdin and stdout can be redirected via the familiar &lt; and &gt;. Unlike other shells, stderr is redirected with a caret ^
+
+<pre>
+> <b>grep</b> <i>fish</i> &lt; /etc/shells > ~/output.txt ^ ~/errors.txt
+</pre>
+
+<h2 id="tut_autosuggestions">Autosuggestions</h2>
+
+fish suggests commands as you type, and shows the suggestion to the right of the cursor, in gray. For example:
+
+<pre>
+> <b class="error">/bin/h</b><span class="suggest"><u>o</u>stname</span>
+</pre>
+
+It knows about paths and options:
+
+<pre>
+> <b>grep</b> <i>--i<span class="suggest"><u>g</u>nore-case</span></i>
+</pre>
+
+And history too. Type a command once, and you can re-summon it by just typing a few letters:
+
+<pre>
+> <b>r</b><span class="suggest"><u>s</u>ync -avze ssh . myname@somelonghost.com:/some/long/path/doo/dee/doo/dee/doo</span>
+</pre>
+
+To accept the autosuggestion, hit right arrow or Control-F. If the autosuggestion is not what you want, just ignore it.
+
+<h2 id="tut_tab_completions">Tab Completions</h2>
+
+<p>fish comes with a rich set of tab completions, that work "out of the box."
+
+<p>Press tab, and fish will attempt to complete the command, argument, or path:
+
+<pre>
+> <b class="error">/pri</b><span class="meta">&lt;tab&gt; &rarr;</span> <b>/private/</b>
+</pre>
+
+<p>If there's more than one possibility, it will list them:
+<pre>
+> <b class="error">~/stuff/s</b><span class="meta">&lt;tab&gt;</span>
+<i>~/stuff/s</i>cript.sh <i class="quote">(Executable, 4.8kB)</i> <i>~/stuff/s</i>ources/ <i class="quote">(Directory)</i>
+</pre>
+
+<p>Hit tab again to cycle through the possibilities.
+
+<p>fish can also complete many commands, like git branches:
+
+<pre>
+> <b>git</b> <i>merge pr</i><span class="meta">&lt;tab&gt; &rarr;</span> git merge prompt_designer
+> <b>git</b> <i>checkout b</i><span class="meta">&lt;tab&gt;</span>
+<i>b</i>uiltin_list_io_merge <i class="quote">(Branch)</i> <i>b</i>uiltin_set_color <i class="quote">(Branch)</i> <i>b</i>usted_events <i class="quote">(Tag)</i>
+</pre>
+
+Try hitting tab and see what fish can do!
+
+<h2 id="tut_variables">Variables</h2>
+
+<p>Like other shells, a dollar sign performs <i>variable substitution</i>:
+
+<pre>
+> <b>echo</b> <i>My home directory is $HOME</i>
+My home directory is /home/tutorial
+</pre>
+
+Variable substitution also occurs in double quotes, but not single quotes:
+
+<pre>
+> <b>echo</b> <i class="quote">"My current directory is </i><i>$</i><i class="quote">PWD"</i>
+My current directory is /home/tutorial
+> <b>echo</b> <i class="quote">'My current directory is $PWD'</i>
+My current directory is $PWD
+</pre>
+
+Unlike other shells, fish has no dedicated syntax for setting variables. Instead it has an ordinary command: <tt>set</tt>, which takes a variable name, and then its value.
+
+<pre>
+> <b>set</b> <i>name</i> <i class="quote">'Mister Noodle'</i>
+> <b>echo</b> <i>$name</i>
+Mister Noodle
+</pre>
+
+<p>(Notice the quotes: without them, <tt>Mister</tt> and <tt>Noodle</tt> would have been separate arguments, and <tt>$name</tt> would have been made into a <i>list</i> of two elements.)
+
+<p>Unlike other shells, variables are <i>not</i> further split after substitution:
+
+<pre>
+> <b>mkdir</b> <i>$name</i>
+> <b>ls</b>
+Mister Noodle
+</pre>
+
+In bash, this would have created two directories "Mister" and "Noodle". In fish, it created only one: the variable had the value "Mister Noodle", so that is the argument that was passed to <span style="mono">mkdir</span>, spaces and all.
+
+<h2 id="tut_exit_status">Exit Status</h2>
+
+Unlike other shells, fish stores the exit status of the last command in <tt>$status</tt> instead of <tt>$?</tt>.
+
+<pre>
+> <b>false</b>
+> <b>echo</b> <i>$status</i>
+1
+</pre>
+
+Zero is considered success, and non-zero is failure.
+
+<h2 id="tut_exports">Exports (Environment Variables)</h2>
+
+Unlike other shells, fish does not have an export command. Instead, a variable is exported via an option to <tt>set</tt>, either <tt>--export</tt> or just <tt>-x</tt>.
+
+<pre>
+> <b>set</b> <i>-x MyVariable SomeValue</i>
+> <b>env</b> | <b>grep</b> <i>MyVariable</i>
+<span style="background: #A0A">MyVariable</span>=SomeValue
+</pre>
+
+You can erase a variable with <tt>-e</tt> or <tt>--erase</tt>
+<pre>
+> <b>set</b> <i>-e MyVariable</i>
+> <b>env</b> | <b>grep</b> <i>MyVariable</i>
+<span class="meta">(no output)</span>
+</pre>
+
+<h2 id="tut_lists">Lists</h2>
+
+<p>The <tt>set</tt> command above used quotes to ensure that <tt>Mister Noodle</tt> was one argument. If it had been two arguments, then <tt>name</tt> would have been a <i>list</i> of length 2. In fact, all variables in fish are really lists, that can contain any number of values, or none at all.
+
+<p>Some variables, like <tt>$PWD</tt>, only have one value. By convention, we talk about that variable's value, but we really mean its <i>first</i> (and only) value.
+
+<p>Other variables, like <tt>$PATH</tt>, really do have multiple values. During <i>variable expansion</i>, the variable expands to become multiple arguments:
+
+<pre>
+> <b>echo</b> <i>$PATH</i>
+/usr/bin /bin /usr/sbin /sbin /usr/local/bin
+</pre>
+
+<p>Lists cannot contain other lists: there is no recursion. A variable is a list of strings, full stop.
+
+<p>Get the length of a list with <tt>count</tt>:
+
+<pre>
+> <b>count</b> <i>$PATH</i>
+5
+</pre>
+
+You can append (or prepend) to a list by setting the list to itself, with some additional arguments. Here we append /usr/local/bin to $PATH:
+
+<pre>
+> <b>set</b> <i>PATH $PATH /usr/local/bin</i>
+</pre>
+
+
+You can access individual elements with square brackets. Indexing starts at 1 from the beginning, and -1 from the end:
+<pre>
+> <b>echo</b> <i>$PATH</i>
+/usr/bin /bin /usr/sbin /sbin /usr/local/bin
+> <b>echo</b> <i>$PATH[1]</i>
+/usr/bin
+> <b>echo</b> <i>$PATH[-1]</i>
+/usr/local/bin
+</pre>
+
+You can also access ranges of elements, known as "slices:"
+
+<pre>
+> <b>echo</b> <i>$PATH[1..2]</i>
+/usr/bin /bin
+> <b>echo</b> <i>$PATH[-1..2]</i>
+/usr/local/bin /sbin /usr/sbin /bin
+</pre>
+
+You can iterate over a list (or a slice) with a <i>for loop</i>:
+
+<pre>
+> <b>for</b> <i>val</i> <b>in</b> <i>$PATH</i>
+ <b>echo</b> <i>"entry: $val"</i>
+ <b>end</b>
+entry: usr/bin/
+entry: /bin
+entry: /usr/sbin
+entry: /sbin
+entry: /usr/local/bin
+</pre>
+
+
+<h2 id="tut_command_substitutions">Command Substitutions</h2>
+
+Command substitutions use the output of one command as an argument to another. Unlike other shells, fish does not use backticks ` for command substitutions. Instead, it uses parentheses:
+
+<pre>
+> <b>echo</b> <i>In (</i><b>pwd</b><i>), running (</i><b>uname</b><i>)</i>
+In /home/tutorial, running FreeBSD
+</pre>
+
+A common idiom is to capture the output of a command in a variable:
+
+<pre>
+> <b>set</b> <i>os (</i><b>uname</b><i>)</i>
+> <b>echo</b> <i>$os</i>
+Linux
+</pre>
+
+Command substitutions are not expanded within quotes. Instead, you can temporarily close the quotes, add the command substitution, and reopen them, all in the same argument:
+
+<pre>
+> <b>touch</b> <i class="quote">"testing_"</i><i>(</i><b>date</b> <i>+%s</i><i>)</i><i class="quote">".txt"</i>
+> <b>ls</b> <i>*.txt</i>
+testing_1360099791.txt
+</pre>
+
+<h2 id="tut_combiners">Combiners (And, Or, Not)</h2>
+
+Unlike other shells, fish does not have special syntax like &amp;&amp; or || to combine commands. Instead it has commands <tt>and</tt>, <tt>or</tt>, and <tt>not</tt>.
+
+<pre>
+> <b>cp</b> <i>file1.txt file1_bak.txt</i>; <b>and echo</b> <i class="quote">"Backup successful"</i>; <b>or echo</b> <i class="quote">"Backup failed"</i>
+Backup failed
+</pre>
+
+<h2 id="tut_conditionals">Conditionals (If, Else, Switch)</h2>
+
+Use <tt>if</tt>, <tt>else if</tt>, and <tt>else</tt> to conditionally execute code, based on the exit status of a command.
+
+<pre>
+<b>if grep</b> <i>fish /etc/shells</i>
+ <b>echo</b> <i>Found fish</i>
+<b>else if grep</b> <i>bash /etc/shells</i>
+ <b>echo</b> <i>Found bash</i>
+<b>else</b>
+ <b>echo</b> <i>Got nothing</i>
+<b>end</b>
+</pre>
+
+There is also a <tt>switch</tt> command:
+
+<pre>
+<b>switch</b> <i>(</i><b>uname</b><i>)</i>
+ <b>case</b> <i>Linux</i>
+ <b>echo</b> <i>Hi Tux!</i>
+ <b>case</b> <i>Darwin</i>
+ <b>echo</b> <i>Hi Hexley!</i>
+ <b>case</b> <i>FreeBSD NetBSD DragonFly</i>
+ <b>echo</b> <i>Hi Beastie!</i>
+ <b>case</b> <i class="quote">'*'</i>
+ <b>echo</b> <i>Hi, stranger!</i>
+<b>end</b>
+</pre>
+
+Note that <tt>case</tt> does not fall through, and can accept multiple arguments or (quoted) wildcards.
+
+<h2 id="tut_functions">Functions</h2>
+
+A fish function is a list of commands, which may optionally take arguments. Unlike other shells, arguments are not passed in "numbered variables" like <tt>$1</tt>, but instead in a single list <tt>$argv</tt>. To create a function, use the <tt>function</tt> builtin:
+
+<pre>
+> <i><b>function</b> say_hello
+ <b>echo</b> Hello $argv
+ <b>end</b></i>
+> <b>say_hello</b>
+Hello
+> <b>say_hello <i>everybody!</i></b>
+Hello everybody!
+</pre>
+
+<p>Unlike other shells, fish does not have aliases or special prompt syntax. Functions take their place.
+
+<p>You can list the names of all functions with the <tt>functions</tt> keyword (note the plural!). fish starts out with a number of functions:
+
+<pre>
+> <b>functions</b>
+alias, cd, delete-or-exit, dirh, dirs, down-or-search, eval, export, fish_command_not_found_setup, fish_config, fish_default_key_bindings, fish_prompt, fish_right_prompt, fish_sigtrap_handler, fish_update_completions, funced, funcsave, grep, help, history, isatty, ls, man, math, nextd, nextd-or-forward-word, open, popd, prevd, prevd-or-backward-word, prompt_pwd, psub, pushd, seq, setenv, sgrep, trap, type, umask, up-or-search, vared
+</pre>
+
+<p>You can see the source for any function by passing its name to <tt>functions</tt>:
+
+<pre>
+> <b>functions</b> <i>ls</i>
+function ls --description 'List contents of directory'
+ command ls -G $argv
+end
+</pre>
+
+<h2 id="tut_loops">Loops</h2>
+
+While loops:
+
+<pre>
+> <b>while</b> <i>true</i>
+ <b>echo</b> <i class="quote">"Loop forever"</i>
+<b>end</b>
+Loop forever
+Loop forever
+Loop forever
+...
+</pre>
+
+For loops can be used to iterate over a list. For example, a list of files:
+
+<pre>
+> <b>for</b> <i>file in *.txt</i>
+ <b>cp</b> <i>$file $file.bak</i>
+<b>end</b>
+</pre>
+
+Iterating over a list of numbers can be done with `seq`:
+
+<pre>
+> <b>for</b> <i>x in (</i><b>seq</b> <i>5)</i>
+ <b>touch</b> <i>file_$x.txt</i>
+<b>end</b>
+</pre>
+
+
+<h2 id="tut_prompt">Prompt</h2>
+
+Unlike other shells, there is no prompt variable like PS1. To display your prompt, fish executes a function with the name <tt>fish_prompt</tt>, and its output is used as the prompt.
+
+You can define your own prompt:
+<pre>
+> <b>function <i>fish_prompt</i>
+ echo <i>"New Prompt % "</i>
+ end</b>
+New Prompt % <u> </u>
+</b>
+</pre>
+
+Multiple lines are OK. Colors can be set via <tt>set_color</tt>, passing it named ANSI colors, or hex RGB values:
+
+<pre>
+> <b>function</b> <i>fish_prompt</i>
+ <b>set_color</b> <i>purple</i>
+ <b>date</b> <i class="quote">"+%m/%d/%y"</i>
+ <b>set_color</b> <i>FF0</i>
+ <b>echo</b> <i>(</i><b>pwd</b><i>)</i> <i class="quote">'>'</i>
+ <b>set_color</b> <i>normal</i>
+ <b>end</b>
+<span style="color: purple">02/06/13</span>
+<span style="color: #FF0">/home/tutorial ></span><u> </u>
+</b>
+</pre>
+
+<p>You can choose among some sample prompts by running <tt>fish_config prompt</tt>. fish also supports RPROMPT through <tt>fish_right_prompt</tt>.
+
+<h3>$PATH</h2>
+
+<tt>$PATH</tt> is an environment variable containing the directories in which fish searches for commands. Instead of separating entries with a colon, $PATH is a list. You can modify $PATH in a few ways:
+
+<p><ol>
+<li>By modifying the <tt>$fish_user_paths</tt> variable, which is automatically appended to <tt>$PATH</tt>. For example, to permanently add /usr/local/bin to your <tt>$PATH</tt>, you could write:
+
+<pre>
+> <b>set</b> <i>-U fish_user_paths $fish_user_paths /usr/local/bin</i>
+</pre>
+
+
+<li>Directly in config.fish (see below).</li>
+</ol>
+
+<h2 id="tut_startup">Startup (Where's .bashrc?)</h2>
+
+<p>fish starts by executing commands in <tt>~/.config/fish/config.fish</tt>. You can create it if it does not exist.
+
+<p>It is possible to directly create functions and variables in <tt>config.fish</tt> file, using the commands shown above. For example:
+
+<p><pre>
+> <b>cat</b> <i>~/.config/fish/config.fish</i>
+
+set -x PATH $PATH /sbin/
+
+function ll
+ ls -lh $argv
+end
+</pre>
+
+<p>However, it is more common and efficient to use <i>autoloading functions</i> and <i>universal variables</i>.
+
+<h3>Autoloading Functions</h2>
+
+<p>When fish encounters a command, it attempts to <i>autoload</i> a function for that command, by looking for a file with the name of that command in <tt>~/.config/fish/functions/</tt>.
+
+<p>For example, if you wanted to have a function <tt>ll</tt>, you would add a text file <tt>ll.fish</tt> to <tt>~/.config/fish/functions</tt>:
+
+<pre>
+> <b>cat</b> <i>~/.config/fish/functions/ll.fish</i>
+function ll
+ ls -lh $argv
+end
+</pre>
+
+This is the preferred way to define your prompt as well:
+
+<pre>
+> <b>cat</b> <i>~/.config/fish/functions/fish_prompt.fish</i>
+function fish_prompt
+ echo (pwd) '> '
+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.
+
+<h3>Universal Variables</h2>
+
+<p>A universal variable is a variable whose value is shared across all instances of fish, now and in the future - even after a reboot. You can make a variable universal with <tt>set -U</tt>:
+
+<pre>
+> <b>set</b> <i>-U EDITOR vim</i>
+</pre>
+
+Now in another shell:
+
+<pre>
+> <b>echo</b> <i>$EDITOR</i>
+vim
+</pre>
+
+<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>.
+
+</div>
+ \endhtmlonly
diff --git a/env.cpp b/env.cpp
index ddb5d2c4..13f87b6c 100644
--- a/env.cpp
+++ b/env.cpp
@@ -429,68 +429,15 @@ static void universal_callback(fish_message_type_t type,
}
/**
- Make sure the PATH variable contains the essential directories
+ Make sure the PATH variable contains something
*/
static void setup_path()
{
- const wchar_t *path_el[] =
+ const env_var_t path = env_get_string(L"PATH");
+ if (path.missing_or_empty())
{
- L"/bin",
- L"/usr/bin",
- NULL
- };
-
- env_var_t path = env_get_string(L"PATH");
-
- wcstring_list_t lst;
- if (! path.missing())
- {
- tokenize_variable_array(path, lst);
- }
-
- for (size_t j=0; path_el[j] != NULL; j++)
- {
-
- bool has_el = false;
-
- for (size_t i=0; i<lst.size(); i++)
- {
- const wcstring &el = lst.at(i);
- size_t len = el.size();
-
- while ((len > 0) && (el.at(len-1)==L'/'))
- {
- len--;
- }
-
- if ((wcslen(path_el[j]) == len) &&
- (wcsncmp(el.c_str(), path_el[j], len)==0))
- {
- has_el = true;
- break;
- }
- }
-
- if (! has_el)
- {
- wcstring buffer;
-
- debug(3, L"directory %ls was missing", path_el[j]);
-
- if (!path.missing())
- {
- buffer += path;
- }
-
- buffer.append(ARRAY_SEP_STR);
- buffer.append(path_el[j]);
-
- env_set(L"PATH", buffer.empty()?NULL:buffer.c_str(), ENV_GLOBAL | ENV_EXPORT);
-
- path = env_get_string(L"PATH");
- lst.resize(0);
- tokenize_variable_array(path, lst);
- }
+ const wchar_t *value = L"/usr/bin" ARRAY_SEP_STR L"/bin";
+ env_set(L"PATH", value, ENV_GLOBAL | ENV_EXPORT);
}
}
@@ -667,7 +614,7 @@ void env_init(const struct config_paths_t *paths /* or NULL */)
/*
Set up the version variables
*/
- wcstring version = str2wcstring(PACKAGE_VERSION);
+ wcstring version = str2wcstring(FISH_BUILD_VERSION);
env_set(L"version", version.c_str(), ENV_GLOBAL);
env_set(L"FISH_VERSION", version.c_str(), ENV_GLOBAL);
diff --git a/exec.cpp b/exec.cpp
index 5f467663..7847797d 100644
--- a/exec.cpp
+++ b/exec.cpp
@@ -49,7 +49,6 @@
#include "expand.h"
#include "signal.h"
-
#include "parse_util.h"
/**
@@ -168,6 +167,21 @@ static bool redirection_is_to_real_file(const io_data_t *io)
return result;
}
+static bool chain_contains_redirection_to_real_file(const io_chain_t &io_chain)
+{
+ bool result = false;
+ for (size_t idx=0; idx < io_chain.size(); idx++)
+ {
+ const shared_ptr<const io_data_t> &io = io_chain.at(idx);
+ if (redirection_is_to_real_file(io.get()))
+ {
+ result = true;
+ break;
+ }
+ }
+ return result;
+}
+
void print_open_fds(void)
{
for (size_t i=0; i < open_fds.size(); ++i)
@@ -362,7 +376,7 @@ static void launch_process_nofork(process_t *p)
*/
static int has_fd(const io_chain_t &d, int fd)
{
- return io_chain_get(d, fd) != NULL;
+ return io_chain_get(d, fd).get() != NULL;
}
/**
@@ -490,7 +504,7 @@ static bool io_transmogrify(const io_chain_t &in_chain, io_chain_t &out_chain, s
static void internal_exec_helper(parser_t &parser,
const wchar_t *def,
enum block_type_t block_type,
- io_chain_t &ios)
+ const io_chain_t &ios)
{
io_chain_t morphed_chain;
std::vector<int> opened_fds;
@@ -540,14 +554,9 @@ static bool can_use_posix_spawn_for_job(const job_t *job, const process_t *proce
/* 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;
- for (size_t idx = 0; idx < job->io.size(); idx++)
+ if (chain_contains_redirection_to_real_file(job->block_io_chain()) || chain_contains_redirection_to_real_file(process->io_chain()))
{
- const shared_ptr<const io_data_t> &io = job->io.at(idx);
- if (redirection_is_to_real_file(io.get()))
- {
- result = false;
- break;
- }
+ result = false;
}
return result;
}
@@ -584,13 +593,11 @@ static void exec_no_exec(parser_t &parser, const job_t *job)
}
}
-void exec(parser_t &parser, job_t *j)
+void exec_job(parser_t &parser, job_t *j)
{
pid_t pid = 0;
sigset_t chldset;
- shared_ptr<io_buffer_t> io_buffer;
-
/*
Set to true if something goes wrong while exec:ing the job, in
which case the cleanup code will kick in.
@@ -615,33 +622,35 @@ void exec(parser_t &parser, job_t *j)
debug(4, L"Exec job '%ls' with id %d", j->command_wcstr(), j->job_id);
- if (! parser.block_io.empty())
- {
- j->io.insert(j->io.begin(), parser.block_io.begin(), parser.block_io.end());
- }
+ /* PCA Here we detect the special case of an input buffer redirection, i.e. we want a process to receive data that we hold in a buffer (it is an INPUT for the process, but an output for fish). This is extremely rare: I believe only run_pager creates these and it would be nice to dump it. So we can only have at most one.
- const io_buffer_t *input_redirect = NULL;
- for (size_t idx = 0; idx < j->io.size(); idx++)
+ It would be great to wean fish_pager off of input redirections so that we can dump input redirections and the INTERNAL_BUFFER process type altogether.
+ */
+ const io_buffer_t *single_magic_input_redirect = NULL;
+ const io_chain_t all_ios = j->all_io_redirections();
+ for (size_t idx = 0; idx < all_ios.size(); idx++)
{
- const shared_ptr<io_data_t> &io = j->io.at(idx);
+ const shared_ptr<io_data_t> &io = all_ios.at(idx);
if ((io->io_mode == IO_BUFFER))
{
CAST_INIT(io_buffer_t *, io_buffer, io.get());
if (io_buffer->is_input)
{
+ /* We expect to have at most one of these, per the comment above. Note that this assertion is the only reason we don't break out of the loop below */
+ assert(single_magic_input_redirect == NULL && "Should have at most one input IO_BUFFER");
+
/*
Input redirection - create a new gobetween process to take
care of buffering, save the redirection in input_redirect
*/
process_t *fake = new process_t();
fake->type = INTERNAL_BUFFER;
- fake->pipe_write_fd = 1;
+ fake->pipe_write_fd = STDOUT_FILENO;
j->first_process->pipe_read_fd = io->fd;
fake->next = j->first_process;
j->first_process = fake;
- input_redirect = io_buffer;
- break;
+ single_magic_input_redirect = io_buffer;
}
}
}
@@ -657,7 +666,9 @@ void exec(parser_t &parser, job_t *j)
setup_child_process makes sure signals are properly set
up. It will also call signal_unblock
*/
- if (!setup_child_process(j, 0))
+
+ /* PCA This is for handling exec. Passing all_ios here matches what fish 2.0.0 and 1.x did. It's known to be wrong - for example, it means that redirections bound for subsequent commands in the pipeline will apply to exec. However, using exec in a pipeline doesn't really make sense, so I'm not trying to fix it here. */
+ if (!setup_child_process(j, 0, all_ios))
{
/*
launch_process _never_ returns
@@ -751,6 +762,9 @@ void exec(parser_t &parser, job_t *j)
int pipe_current_read = -1, pipe_current_write = -1, pipe_next_read = -1;
for (process_t *p=j->first_process; p; p = p->next)
{
+ /* The IO chain for this process. It starts with the block IO, then pipes, and then gets any from the process */
+ io_chain_t process_net_io_chain = j->block_io_chain();
+
/* "Consume" any pipe_next_read by making it current */
assert(pipe_current_read == -1);
pipe_current_read = pipe_next_read;
@@ -761,23 +775,52 @@ void exec(parser_t &parser, job_t *j)
/* The pipes the current process write to and read from.
Unfortunately these can't be just allocated on the stack, since
- j->io wants shared_ptr. */
+ j->io wants shared_ptr.
+
+ The write pipe (destined for stdout) needs to occur before redirections. For example, with a redirection like this:
+ `foo 2>&1 | bar`, what we want to happen is this:
+
+ dup2(pipe, stdout)
+ dup2(stdout, stderr)
+
+ so that stdout and stderr both wind up referencing the pipe.
+
+ The read pipe (destined for stdin) is more ambiguous. Imagine a pipeline like this:
+
+ 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.
+ */
+
shared_ptr<io_pipe_t> pipe_write;
shared_ptr<io_pipe_t> pipe_read;
+ /* Write pipe goes first */
+ if (p->next)
+ {
+ pipe_write.reset(new io_pipe_t(p->pipe_write_fd, false));
+ process_net_io_chain.push_back(pipe_write);
+
+ }
+
+ /* 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)
{
pipe_read.reset(new io_pipe_t(p->pipe_read_fd, true));
/* Record the current read in pipe_read */
pipe_read->pipe_fd[0] = pipe_current_read;
- j->io.push_back(pipe_read);
- }
-
- if (p->next)
- {
- pipe_write.reset(new io_pipe_t(p->pipe_write_fd, false));
- j->io.push_back(pipe_write);
+ process_net_io_chain.push_back(pipe_read);
}
+
/*
This call is used so the global environment variable array
@@ -821,13 +864,15 @@ void exec(parser_t &parser, job_t *j)
pipe_next_read = local_pipe[0];
}
+ //fprintf(stderr, "before IO: ");
+ //io_print(j->io);
+
+ // This is the IO buffer we use for storing the output of a block or function when it is in a pipeline
+ shared_ptr<io_buffer_t> block_output_io_buffer;
switch (p->type)
{
case INTERNAL_FUNCTION:
{
- int shadows;
-
-
/*
Calls to function_get_definition might need to
source a file as a part of autoloading, hence there
@@ -839,7 +884,7 @@ void exec(parser_t &parser, job_t *j)
bool function_exists = function_get_definition(p->argv0(), &def);
wcstring_list_t named_arguments = function_get_named_arguments(p->argv0());
- shadows = function_get_shadows(p->argv0());
+ bool shadows = function_get_shadows(p->argv0());
signal_block();
@@ -865,21 +910,22 @@ void exec(parser_t &parser, job_t *j)
if (p->next)
{
// Be careful to handle failure, e.g. too many open fds
- io_buffer.reset(io_buffer_t::create(0));
- if (io_buffer.get() == NULL)
+ block_output_io_buffer.reset(io_buffer_t::create(false /* = not input */, STDOUT_FILENO));
+ if (block_output_io_buffer.get() == NULL)
{
exec_error = true;
job_mark_process_as_failed(j, p);
}
else
{
- j->io.push_back(io_buffer);
+ /* This looks sketchy, because we're adding this io buffer locally - they aren't in the process or job redirection list. Therefore select_try won't be able to read them. However we call block_output_io_buffer->read() below, which reads until EOF. So there's no need to select on this. */
+ process_net_io_chain.push_back(block_output_io_buffer);
}
}
if (! exec_error)
{
- internal_exec_helper(parser, def.c_str(), TOP, j->io);
+ internal_exec_helper(parser, def.c_str(), TOP, process_net_io_chain);
}
parser.allow_function();
@@ -892,21 +938,22 @@ void exec(parser_t &parser, job_t *j)
{
if (p->next)
{
- io_buffer.reset(io_buffer_t::create(0));
- if (io_buffer.get() == NULL)
+ block_output_io_buffer.reset(io_buffer_t::create(0));
+ if (block_output_io_buffer.get() == NULL)
{
exec_error = true;
job_mark_process_as_failed(j, p);
}
else
{
- j->io.push_back(io_buffer);
+ /* See the comment above about it's OK to add an IO redirection to this local buffer, even though it won't be handled in select_try */
+ process_net_io_chain.push_back(block_output_io_buffer);
}
}
if (! exec_error)
{
- internal_exec_helper(parser, p->argv0(), TOP, j->io);
+ internal_exec_helper(parser, p->argv0(), TOP, process_net_io_chain);
}
break;
@@ -915,7 +962,7 @@ void exec(parser_t &parser, job_t *j)
case INTERNAL_BUILTIN:
{
int builtin_stdin=0;
- int close_stdin=0;
+ bool close_stdin = false;
/*
If this is the first process, check the io
@@ -924,7 +971,7 @@ void exec(parser_t &parser, job_t *j)
*/
if (p == j->first_process)
{
- const shared_ptr<const io_data_t> in = io_chain_get(j->io, 0);
+ const shared_ptr<const io_data_t> in = process_net_io_chain.get_io_for_fd(STDIN_FILENO);
if (in)
{
@@ -959,7 +1006,7 @@ void exec(parser_t &parser, job_t *j)
}
else
{
- close_stdin = 1;
+ close_stdin = true;
}
break;
@@ -1023,15 +1070,15 @@ void exec(parser_t &parser, job_t *j)
builtin_push_io(parser, builtin_stdin);
- builtin_out_redirect = has_fd(j->io, 1);
- builtin_err_redirect = has_fd(j->io, 2);
+ builtin_out_redirect = has_fd(process_net_io_chain, STDOUT_FILENO);
+ builtin_err_redirect = has_fd(process_net_io_chain, STDERR_FILENO);
const int fg = job_get_flag(j, JOB_FOREGROUND);
job_set_flag(j, JOB_FOREGROUND, 0);
signal_unblock();
- p->status = builtin_run(parser, p->get_argv(), j->io);
+ p->status = builtin_run(parser, p->get_argv(), process_net_io_chain);
builtin_out_redirect=old_out;
builtin_err_redirect=old_err;
@@ -1077,7 +1124,7 @@ void exec(parser_t &parser, job_t *j)
to buffer such io, since otherwise the internal pipe
buffer might overflow.
*/
- if (!io_buffer)
+ if (! block_output_io_buffer.get())
{
/*
No buffer, so we exit directly. This means we
@@ -1091,14 +1138,16 @@ void exec(parser_t &parser, job_t *j)
break;
}
- io_remove(j->io, io_buffer);
+ // Here we must have a non-NULL block_output_io_buffer
+ assert(block_output_io_buffer.get() != NULL);
+ io_remove(process_net_io_chain, block_output_io_buffer);
- io_buffer->read();
+ block_output_io_buffer->read();
- const char *buffer = io_buffer->out_buffer_ptr();
- size_t count = io_buffer->out_buffer_size();
+ const char *buffer = block_output_io_buffer->out_buffer_ptr();
+ size_t count = block_output_io_buffer->out_buffer_size();
- if (io_buffer->out_buffer_size() > 0)
+ if (block_output_io_buffer->out_buffer_size() > 0)
{
/* We don't have to drain threads here because our child process is simple */
if (g_log_forks)
@@ -1113,9 +1162,9 @@ void exec(parser_t &parser, job_t *j)
This is the child process. Write out the contents of the pipeline.
*/
p->pid = getpid();
- setup_child_process(j, p);
+ setup_child_process(j, p, process_net_io_chain);
- exec_write_and_exit(io_buffer->fd, buffer, count, status);
+ exec_write_and_exit(block_output_io_buffer->fd, buffer, count, status);
}
else
{
@@ -1139,7 +1188,7 @@ void exec(parser_t &parser, job_t *j)
p->completed = 1;
}
- io_buffer.reset();
+ block_output_io_buffer.reset();
break;
}
@@ -1147,9 +1196,9 @@ void exec(parser_t &parser, job_t *j)
case INTERNAL_BUFFER:
{
-
- const char *buffer = input_redirect->out_buffer_ptr();
- size_t count = input_redirect->out_buffer_size();
+ assert(single_magic_input_redirect != NULL);
+ const char *buffer = single_magic_input_redirect->out_buffer_ptr();
+ size_t count = single_magic_input_redirect->out_buffer_size();
/* We don't have to drain threads here because our child process is simple */
if (g_log_forks)
@@ -1164,7 +1213,7 @@ void exec(parser_t &parser, job_t *j)
contents of the pipeline.
*/
p->pid = getpid();
- setup_child_process(j, p);
+ setup_child_process(j, p, process_net_io_chain);
exec_write_and_exit(1, buffer, count, 0);
}
@@ -1194,10 +1243,10 @@ void exec(parser_t &parser, job_t *j)
*/
bool fork_was_skipped = false;
-
- const shared_ptr<io_data_t> stdout_io = io_chain_get(j->io, STDOUT_FILENO);
- const shared_ptr<io_data_t> stderr_io = io_chain_get(j->io, STDERR_FILENO);
-
+
+ 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)
@@ -1286,7 +1335,7 @@ void exec(parser_t &parser, job_t *j)
if (g_log_forks)
{
printf("fork #%d: Executing fork for internal builtin for '%ls'\n", g_fork_count, p->argv0());
- io_print(j->io);
+ io_print(process_net_io_chain);
}
pid = execute_fork(false);
if (pid == 0)
@@ -1297,7 +1346,7 @@ void exec(parser_t &parser, job_t *j)
then exit.
*/
p->pid = getpid();
- setup_child_process(j, p);
+ setup_child_process(j, p, process_net_io_chain);
do_builtin_io(outbuff, outbuff_len, errbuff, errbuff_len);
exit_without_destructors(p->status);
}
@@ -1340,7 +1389,7 @@ void exec(parser_t &parser, job_t *j)
printf("fork #%d: forking for '%s' in '%ls:%ls'\n", g_fork_count, actual_cmd, file ? file : L"", func ? func : L"?");
fprintf(stderr, "IO chain for %s:\n", actual_cmd);
- io_print(j->io);
+ io_print(process_net_io_chain);
}
#if FISH_USE_POSIX_SPAWN
@@ -1351,7 +1400,7 @@ void exec(parser_t &parser, job_t *j)
/* Create posix spawn attributes and actions */
posix_spawnattr_t attr = posix_spawnattr_t();
posix_spawn_file_actions_t actions = posix_spawn_file_actions_t();
- bool made_it = fork_actions_make_spawn_properties(&attr, &actions, j, p);
+ bool made_it = fork_actions_make_spawn_properties(&attr, &actions, j, p, process_net_io_chain);
if (made_it)
{
/* We successfully made the attributes and actions; actually call posix_spawn */
@@ -1387,7 +1436,7 @@ void exec(parser_t &parser, job_t *j)
{
/* This is the child process. */
p->pid = getpid();
- setup_child_process(j, p);
+ setup_child_process(j, p, process_net_io_chain);
safe_launch_process(p, actual_cmd, argv, envv);
/*
@@ -1435,12 +1484,6 @@ void exec(parser_t &parser, job_t *j)
exec_close(pipe_current_write);
pipe_current_write = -1;
}
-
- if (pipe_write.get())
- j->io.remove(pipe_write);
-
- if (pipe_read.get())
- j->io.remove(pipe_read);
}
/* Clean up any file descriptors we left open */
diff --git a/exec.h b/exec.h
index edae1e55..10eda29b 100644
--- a/exec.h
+++ b/exec.h
@@ -42,7 +42,7 @@
*/
class parser_t;
-void exec(parser_t &parser, job_t *j);
+void exec_job(parser_t &parser, job_t *j);
/**
Evaluate the expression cmd in a subshell, add the outputs into the
diff --git a/expand.cpp b/expand.cpp
index dc83c385..45d29249 100644
--- a/expand.cpp
+++ b/expand.cpp
@@ -585,7 +585,30 @@ static int find_process(const wchar_t *proc,
ASSERT_IS_MAIN_THREAD();
const job_t *j;
- if (iswnumeric(proc) || (wcslen(proc)==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(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'
@@ -611,11 +634,9 @@ static int find_process(const wchar_t *proc,
0);
}
}
-
}
else
{
-
int jid;
wchar_t *end;
@@ -624,15 +645,17 @@ static int find_process(const wchar_t *proc,
if (jid > 0 && !errno && !*end)
{
j = job_get(jid);
- if ((j != 0) && (j->command_wcstr() != 0))
+ if ((j != 0) && (j->command_wcstr() != 0) && (!j->command_is_empty()))
{
- {
- append_completion(out, to_string<long>(j->pgid));
- found = 1;
- }
+ 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;
@@ -1729,9 +1752,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();
-
- if (((flags & ACCEPT_INCOMPLETE) && (!(flags & EXPAND_SKIP_WILDCARDS))) ||
- wildcard_has(next, 1))
+
+ 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)
{
const wchar_t *start, *rest;
@@ -1766,7 +1795,7 @@ int expand_string(const wcstring &input, std::vector<completion_t> &output, expa
case 1:
{
res = EXPAND_WILDCARD_MATCH;
- sort_completions(expanded);
+ std::sort(expanded.begin(), expanded.end(), completion_t::is_alphabetically_less_than);
out->insert(out->end(), expanded.begin(), expanded.end());
break;
}
diff --git a/fish.cpp b/fish.cpp
index 8001f376..24499c75 100644
--- a/fish.cpp
+++ b/fish.cpp
@@ -61,6 +61,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "output.h"
#include "history.h"
#include "path.h"
+#include "input.h"
/* PATH_MAX may not exist */
#ifndef PATH_MAX
@@ -210,31 +211,29 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
return paths;
}
+/* Source the file config.fish in the given directory */
+static void source_config_in_directory(const wcstring &dir)
+{
+ /* We want to execute a command like 'builtin source dir/config.fish 2>/dev/null' */
+ const wcstring escaped_dir = escape_string(dir, ESCAPE_ALL);
+ const wcstring cmd = L"builtin source " + escaped_dir + L"/config.fish 2>/dev/null";
+ parser_t &parser = parser_t::principal_parser();
+ parser.eval(cmd, io_chain_t(), TOP);
+}
+
/**
Parse init files. exec_path is the path of fish executable as determined by argv[0].
*/
static int read_init(const struct config_paths_t &paths)
{
- parser_t &parser = parser_t::principal_parser();
- const io_chain_t empty_ios;
- parser.eval(L"builtin . " + paths.data + L"/config.fish 2>/dev/null", empty_ios, TOP);
- parser.eval(L"builtin . " + paths.sysconf + L"/config.fish 2>/dev/null", empty_ios, TOP);
+ source_config_in_directory(paths.data);
+ source_config_in_directory(paths.sysconf);
-
- /*
- We need to get the configuration directory before we can source the user configuration file
- */
+ /* We need to get the configuration directory before we can source the user configuration file. If path_get_config returns false then we have no configuration directory and no custom config to load. */
wcstring config_dir;
-
- /*
- If path_get_config returns false then we have no configuration directory
- and no custom config to load.
- */
if (path_get_config(config_dir))
{
- wcstring config_dir_escaped = escape_string(config_dir, 1);
- wcstring eval_buff = format_string(L"builtin . %ls/config.fish 2>/dev/null", config_dir_escaped.c_str());
- parser.eval(eval_buff, empty_ios, TOP);
+ source_config_in_directory(config_dir);
}
return 1;
@@ -350,7 +349,7 @@ static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *out_c
fwprintf(stderr,
_(L"%s, version %s\n"),
PACKAGE_NAME,
- PACKAGE_VERSION);
+ FISH_BUILD_VERSION);
exit_without_destructors(0);
}
@@ -421,6 +420,8 @@ int main(int argc, char **argv)
env_init(&paths);
reader_init();
history_init();
+ /* For setcolor to support term256 in config.fish (#1022) */
+ update_fish_term256();
parser_t &parser = parser_t::principal_parser();
diff --git a/fish.xcodeproj/project.pbxproj b/fish.xcodeproj/project.pbxproj
index c397f321..3b85e4bc 100644
--- a/fish.xcodeproj/project.pbxproj
+++ b/fish.xcodeproj/project.pbxproj
@@ -1345,6 +1345,7 @@
"DATADIR=L\\\"/usr/local/share\\\"",
"SYSCONFDIR=L\\\"/usr/local/etc\\\"",
"BINDIR=L\\\"/usr/local/bin\\\"",
+ "FISH_BUILD_VERSION=\\\"2.0.0\\\"",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
@@ -1564,6 +1565,7 @@
"DATADIR=L\\\"/usr/local/share\\\"",
"SYSCONFDIR=L\\\"/usr/local/etc\\\"",
"BINDIR=L\\\"/usr/local/bin\\\"",
+ "FISH_BUILD_VERSION=\\\"2.0.0\\\"",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -1591,6 +1593,7 @@
"DATADIR=L\\\"/usr/local/share\\\"",
"SYSCONFDIR=L\\\"/usr/local/etc\\\"",
"BINDIR=L\\\"/usr/local/bin\\\"",
+ "FISH_BUILD_VERSION=\\\"2.0.0\\\"",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
diff --git a/fish_indent.cpp b/fish_indent.cpp
index db48679b..3b54d008 100644
--- a/fish_indent.cpp
+++ b/fish_indent.cpp
@@ -344,7 +344,7 @@ int main(int argc, char **argv)
fwprintf(stderr,
_(L"%ls, version %s\n"),
program_name,
- PACKAGE_VERSION);
+ FISH_BUILD_VERSION);
exit(0);
}
diff --git a/fish_pager.cpp b/fish_pager.cpp
index 2e1a4bba..9cde933e 100644
--- a/fish_pager.cpp
+++ b/fish_pager.cpp
@@ -1289,7 +1289,7 @@ int main(int argc, char **argv)
case 'v':
{
- debug(0, L"%ls, version %s\n", program_name, PACKAGE_VERSION);
+ debug(0, L"%ls, version %s\n", program_name, FISH_BUILD_VERSION);
exit(0);
}
@@ -1370,6 +1370,11 @@ int main(int argc, char **argv)
// debug( 3, L"prefix is '%ls'", prefix );
+ if (comp.empty())
+ {
+ exit_without_destructors(EXIT_FAILURE);
+ }
+
init(mangle_descriptors, result_fd);
mangle_descriptions(comp);
diff --git a/fish_tests.cpp b/fish_tests.cpp
index 9d8f2b80..01030319 100644
--- a/fish_tests.cpp
+++ b/fish_tests.cpp
@@ -552,6 +552,16 @@ static void test_utils()
if (begin != a + wcslen(L"echo (echo (")) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
}
+static void test_escape_sequences(void)
+{
+ say(L"Testing escape codes");
+ if (escape_code_length(L"") != 0) err(L"test_escape_sequences failed on line %d\n", __LINE__);
+ if (escape_code_length(L"abcd") != 0) err(L"test_escape_sequences failed on line %d\n", __LINE__);
+ if (escape_code_length(L"\x1b[2J") != 4) err(L"test_escape_sequences failed on line %d\n", __LINE__);
+ if (escape_code_length(L"\x1b[38;5;123mABC") != strlen("\x1b[38;5;123m")) err(L"test_escape_sequences failed on line %d\n", __LINE__);
+ if (escape_code_length(L"\x1b@") != 2) err(L"test_escape_sequences failed on line %d\n", __LINE__);
+}
+
class lru_node_test_t : public lru_node_t
{
public:
@@ -768,9 +778,8 @@ static void test_path()
say(L"Testing path functions");
wcstring path = L"//foo//////bar/";
- wcstring canon = path;
- path_make_canonical(canon);
- if (canon != L"/foo/bar")
+ path_make_canonical(path);
+ if (path != L"/foo/bar")
{
err(L"Bug in canonical PATH code");
}
@@ -781,6 +790,11 @@ 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__);
+ if (! paths_are_equivalent(L"/", L"/")) err(L"Bug in canonical PATH code on line %ld", (long)__LINE__);
}
enum word_motion_t
@@ -2078,6 +2092,7 @@ int main(int argc, char **argv)
test_fork();
test_parser();
test_utils();
+ test_escape_sequences();
test_lru();
test_expand();
test_fuzzy_match();
diff --git a/fishd.cpp b/fishd.cpp
index 638e1762..edb79c22 100644
--- a/fishd.cpp
+++ b/fishd.cpp
@@ -529,6 +529,14 @@ static bool acquire_socket_lock(const std::string &sock_name, std::string *out_l
*/
static int get_socket(void)
{
+ // Cygwin has random problems involving sockets. When using Cygwin,
+ // allow 20 attempts at making socket correctly.
+#ifdef __CYGWIN__
+ int attempts = 0;
+repeat:
+ attempts += 1;
+#endif
+
int s, len, doexit = 0;
int exitcode = EXIT_FAILURE;
struct sockaddr_un local;
@@ -599,6 +607,10 @@ unlock:
if (doexit)
{
+ // If Cygwin, only allow normal quit when made lots of attempts.
+#ifdef __CYGWIN__
+ if (exitcode && attempts < 20) goto repeat;
+#endif
exit_without_destructors(exitcode);
}
@@ -922,7 +934,7 @@ int main(int argc, char ** argv)
exit(0);
case 'v':
- debug(0, L"%ls, version %s\n", program_name, PACKAGE_VERSION);
+ debug(0, L"%ls, version %s\n", program_name, FISH_BUILD_VERSION);
exit(0);
case '?':
diff --git a/highlight.cpp b/highlight.cpp
index f2a7d6e0..dc221a2f 100644
--- a/highlight.cpp
+++ b/highlight.cpp
@@ -1036,7 +1036,7 @@ static void tokenize(const wchar_t * const buff, std::vector<int> &color, const
bool is_cmd = false;
int is_subcommand = 0;
int mark = tok_get_pos(&tok);
- color.at(tok_get_pos(&tok)) = HIGHLIGHT_COMMAND;
+ color.at(tok_get_pos(&tok)) = use_builtin ? HIGHLIGHT_COMMAND : HIGHLIGHT_ERROR;
if (parser_keywords_is_subcommand(cmd))
{
@@ -1049,7 +1049,7 @@ static void tokenize(const wchar_t * const buff, std::vector<int> &color, const
use_command = 0;
use_builtin = 1;
}
- else if (cmd == L"command")
+ else if (cmd == L"command" || cmd == L"exec")
{
use_command = 1;
use_function = 0;
diff --git a/history.cpp b/history.cpp
index 8e3772d2..f167f6e4 100644
--- a/history.cpp
+++ b/history.cpp
@@ -629,10 +629,16 @@ 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 ) */
for (std::vector<history_item_t>::reverse_iterator iter=new_items.rbegin(); iter < new_items.rend(); ++iter)
{
+ /* Skip duplicates */
+ if (! seen.insert(iter->str()).second)
+ continue;
+
if (! first)
result.append(separator);
result.append(iter->str());
@@ -645,6 +651,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());
diff --git a/input.cpp b/input.cpp
index f3d752a9..b587fcba 100644
--- a/input.cpp
+++ b/input.cpp
@@ -115,6 +115,9 @@ static const wchar_t * const name_arr[] =
L"self-insert",
L"transpose-chars",
L"transpose-words",
+ L"upcase-word",
+ L"downcase-word",
+ L"capitalize-word",
L"null",
L"eof",
L"vi-arg-digit",
@@ -201,6 +204,9 @@ static const wchar_t code_arr[] =
R_SELF_INSERT,
R_TRANSPOSE_CHARS,
R_TRANSPOSE_WORDS,
+ R_UPCASE_WORD,
+ R_DOWNCASE_WORD,
+ R_CAPITALIZE_WORD,
R_NULL,
R_EOF,
R_VI_ARG_DIGIT,
diff --git a/input.h b/input.h
index 465d5047..c5722b2f 100644
--- a/input.h
+++ b/input.h
@@ -44,6 +44,9 @@ enum
R_SELF_INSERT,
R_TRANSPOSE_CHARS,
R_TRANSPOSE_WORDS,
+ R_UPCASE_WORD,
+ R_DOWNCASE_WORD,
+ R_CAPITALIZE_WORD,
R_VI_ARG_DIGIT,
R_VI_DELETE_TO,
R_EXECUTE,
diff --git a/install-sh b/install-sh
index 594a4edb..a9244eb0 100755
--- a/install-sh
+++ b/install-sh
@@ -1,251 +1,527 @@
#!/bin/sh
-#
# install - install a program, script, or datafile
-# This comes from X11R5 (mit/util/scripts/install.sh).
+
+scriptversion=2011-01-19.21; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-# Copyright 1991 by the Massachusetts Institute of Technology
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
#
-# Permission to use, copy, modify, distribute, and sell this software and its
-# documentation for any purpose is hereby granted without fee, provided that
-# the above copyright notice appear in all copies and that both that
-# copyright notice and this permission notice appear in supporting
-# documentation, and that the name of M.I.T. not be used in advertising or
-# publicity pertaining to distribution of the software without specific,
-# written prior permission. M.I.T. makes no representations about the
-# suitability of this software for any purpose. It is provided "as is"
-# without express or implied warranty.
+#
+# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
-# from scratch. It can only install one file at a time, a restriction
-# shared with many OS's install programs.
+# from scratch.
+nl='
+'
+IFS=" "" $nl"
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
-doit="${DOITPROG-}"
-
-
-# put in absolute paths if you don't have them in your path; or use env. vars.
-
-mvprog="${MVPROG-mv}"
-cpprog="${CPPROG-cp}"
-chmodprog="${CHMODPROG-chmod}"
-chownprog="${CHOWNPROG-chown}"
-chgrpprog="${CHGRPPROG-chgrp}"
-stripprog="${STRIPPROG-strip}"
-rmprog="${RMPROG-rm}"
-mkdirprog="${MKDIRPROG-mkdir}"
-
-transformbasename=""
-transform_arg=""
-instcmd="$mvprog"
-chmodcmd="$chmodprog 0755"
-chowncmd=""
-chgrpcmd=""
-stripcmd=""
-rmcmd="$rmprog -f"
-mvcmd="$mvprog"
-src=""
-dst=""
-dir_arg=""
-
-while [ x"$1" != x ]; do
- case $1 in
- -c) instcmd="$cpprog"
- shift
- continue;;
-
- -d) dir_arg=true
- shift
- continue;;
-
- -m) chmodcmd="$chmodprog $2"
- shift
- shift
- continue;;
-
- -o) chowncmd="$chownprog $2"
- shift
- shift
- continue;;
-
- -g) chgrpcmd="$chgrpprog $2"
- shift
- shift
- continue;;
-
- -s) stripcmd="$stripprog"
- shift
- continue;;
-
- -t=*) transformarg=`echo $1 | sed 's/-t=//'`
- shift
- continue;;
-
- -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
- shift
- continue;;
-
- *) if [ x"$src" = x ]
- then
- src=$1
- else
- # this colon is to work around a 386BSD /bin/sh bug
- :
- dst=$1
- fi
- shift
- continue;;
- esac
-done
-
-if [ x"$src" = x ]
-then
- echo "install: no input file specified"
- exit 1
+doit=${DOITPROG-}
+if test -z "$doit"; then
+ doit_exec=exec
else
- true
+ doit_exec=$doit
fi
-if [ x"$dir_arg" != x ]; then
- dst=$src
- src=""
-
- if [ -d $dst ]; then
- instcmd=:
- chmodcmd=""
- else
- instcmd=mkdir
- fi
-else
-
-# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
-# might cause directories to be created, which would be especially bad
-# if $src (and thus $dsttmp) contains '*'.
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+ test "$posix_glob" != "?" || {
+ if (set -f) 2>/dev/null; then
+ posix_glob=
+ else
+ posix_glob=:
+ fi
+ }
+'
- if [ -f $src -o -d $src ]
- then
- true
- else
- echo "install: $src does not exist"
- exit 1
- fi
+posix_mkdir=
- if [ x"$dst" = x ]
- then
- echo "install: no destination specified"
- exit 1
- else
- true
- fi
+# Desired mode of installed file.
+mode=0755
-# If destination is a directory, append the input filename; if your system
-# does not like double slashes in filenames, you may need to add some logic
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
- if [ -d $dst ]
- then
- dst="$dst"/`basename $src`
- else
- true
- fi
-fi
+src=
+dst=
+dir_arg=
+dst_arg=
-## this sed command emulates the dirname command
-dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+copy_on_change=false
+no_target_directory=
-# Make sure that the destination directory exists.
-# this part is taken from Noah Friedman's mkinstalldirs script
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
-# Skip lots of stat calls in the usual case.
-if [ ! -d "$dstdir" ]; then
-defaultIFS='
-'
-IFS="${IFS-${defaultIFS}}"
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
-oIFS="${IFS}"
-# Some sh's can't handle IFS=/ for some reason.
-IFS='%'
-set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
-IFS="${oIFS}"
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
-pathcomp=''
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
-while [ $# -ne 0 ] ; do
- pathcomp="${pathcomp}${1}"
- shift
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
- if [ ! -d "${pathcomp}" ] ;
- then
- $mkdirprog "${pathcomp}"
- else
- true
- fi
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
- pathcomp="${pathcomp}/"
-done
-fi
+ -C) copy_on_change=true;;
-if [ x"$dir_arg" != x ]
-then
- $doit $instcmd $dst &&
+ -d) dir_arg=true;;
- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
-else
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
-# If we're going to rename the final executable, determine the name now.
+ --help) echo "$usage"; exit $?;;
- if [ x"$transformarg" = x ]
- then
- dstfile=`basename $dst`
- else
- dstfile=`basename $dst $transformbasename |
- sed $transformarg`$transformbasename
- fi
+ -m) mode=$2
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
-# don't allow the sed command to completely eliminate the filename
+ -o) chowncmd="$chownprog $2"
+ shift;;
- if [ x"$dstfile" = x ]
- then
- dstfile=`basename $dst`
- else
- true
- fi
+ -s) stripcmd=$stripprog;;
-# Make a temp file name in the proper directory.
+ -t) dst_arg=$2
+ # Protect names problematic for `test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
- dsttmp=$dstdir/#inst.$$#
+ -T) no_target_directory=true;;
-# Move or copy the file name to the temp name
+ --version) echo "$0 $scriptversion"; exit $?;;
- $doit $instcmd $src $dsttmp &&
+ --) shift
+ break;;
- trap "rm -f ${dsttmp}" 0 &&
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
-# and set any options; do chmod last to preserve setuid bits
+ *) break;;
+ esac
+ shift
+done
-# If any of these fail, we abort the whole thing. If we want to
-# ignore errors from any of these, just make sure not to ignore
-# errors from the above "$doit $instcmd $src $dsttmp" command.
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ # Protect names problematic for `test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ done
+fi
- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
-# Now rename the file to the real destination.
+if test -z "$dir_arg"; then
+ do_exit='(exit $ret); exit $ret'
+ trap "ret=129; $do_exit" 1
+ trap "ret=130; $do_exit" 2
+ trap "ret=141; $do_exit" 13
+ trap "ret=143; $do_exit" 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
- $doit $rmcmd -f $dstdir/$dstfile &&
- $doit $mvcmd $dsttmp $dstdir/$dstfile
+for src
+do
+ # Protect names problematic for `test' and other utilities.
+ case $src in
+ -* | [=\(\)!]) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+ dst=$dst_arg
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
-fi &&
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writeable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ eval "$initialize_posix_glob"
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob set -f
+ set fnord $dstdir
+ shift
+ $posix_glob set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+ eval "$initialize_posix_glob" &&
+ $posix_glob set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ $posix_glob set +f &&
+
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
-exit 0
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/io.cpp b/io.cpp
index da1ebb0c..1ee36e72 100644
--- a/io.cpp
+++ b/io.cpp
@@ -128,7 +128,7 @@ io_buffer_t *io_buffer_t::create(bool is_input, int fd)
bool success = true;
if (fd == -1)
{
- fd = is_input ? 0 : 1;
+ fd = is_input ? STDIN_FILENO : STDOUT_FILENO;
}
io_buffer_t *buffer_redirect = new io_buffer_t(fd, is_input);
@@ -202,6 +202,17 @@ void io_chain_t::push_back(const shared_ptr<io_data_t> &element)
std::vector<shared_ptr<io_data_t> >::push_back(element);
}
+void io_chain_t::push_front(const shared_ptr<io_data_t> &element)
+{
+ assert(element.get() != NULL);
+ this->insert(this->begin(), element);
+}
+
+void io_chain_t::append(const io_chain_t &chain)
+{
+ this->insert(this->end(), chain.begin(), chain.end());
+}
+
void io_remove(io_chain_t &list, const shared_ptr<const io_data_t> &element)
{
list.remove(element);
diff --git a/io.h b/io.h
index 6a98f380..17e2b342 100644
--- a/io.h
+++ b/io.h
@@ -2,12 +2,16 @@
#define FISH_IO_H
#include <vector>
-#if __cplusplus > 199711L
-// C++11
+
+// Note that we have to include something to get any _LIBCPP_VERSION defined so we can detect libc++
+// So it's key that vector go above. If we didn't need vector for other reasons, we might include ciso646, which does nothing
+
+#if defined(_LIBCPP_VERSION) || __cplusplus > 199711L
+// C++11 or libc++ (which is a C++11-only library, but the memory header works OK in C++03)
#include <memory>
using std::shared_ptr;
#else
-// C++03
+// C++03 or libstdc++
#include <tr1/memory>
using std::tr1::shared_ptr;
#endif
@@ -188,6 +192,8 @@ public:
void remove(const shared_ptr<const io_data_t> &element);
void push_back(const shared_ptr<io_data_t> &element);
+ void push_front(const shared_ptr<io_data_t> &element);
+ void append(const io_chain_t &chain);
shared_ptr<const io_data_t> get_io_for_fd(int fd) const;
shared_ptr<io_data_t> get_io_for_fd(int fd);
diff --git a/mimedb.cpp b/mimedb.cpp
index 9b66bb0a..fdf5da12 100644
--- a/mimedb.cpp
+++ b/mimedb.cpp
@@ -1332,7 +1332,7 @@ int main(int argc, char *argv[])
exit(0);
case 'v':
- printf(_("%s, version %s\n"), MIMEDB, PACKAGE_VERSION);
+ printf(_("%s, version %s\n"), MIMEDB, FISH_BUILD_VERSION);
exit(0);
case '?':
diff --git a/osx/launch_fish.scpt b/osx/launch_fish.scpt
index dc39dd52..3c1ae69e 100644
--- a/osx/launch_fish.scpt
+++ b/osx/launch_fish.scpt
Binary files differ
diff --git a/parse_util.cpp b/parse_util.cpp
index 6f291345..5b807059 100644
--- a/parse_util.cpp
+++ b/parse_util.cpp
@@ -381,6 +381,11 @@ static void job_or_process_extent(const wchar_t *buff,
break;
}
+
+ default:
+ {
+ break;
+ }
}
}
@@ -411,35 +416,34 @@ void parse_util_token_extent(const wchar_t *buff,
const wchar_t **prev_begin,
const wchar_t **prev_end)
{
- const wchar_t *begin, *end;
- long pos;
-
const wchar_t *a = NULL, *b = NULL, *pa = NULL, *pb = NULL;
CHECK(buff,);
assert(cursor_pos >= 0);
- parse_util_cmdsubst_extent(buff, cursor_pos, &begin, &end);
+ const wchar_t *cmdsubst_begin, *cmdsubst_end;
+ parse_util_cmdsubst_extent(buff, cursor_pos, &cmdsubst_begin, &cmdsubst_end);
- if (!end || !begin)
+ if (!cmdsubst_end || !cmdsubst_begin)
{
return;
}
- pos = cursor_pos - (begin - buff);
+ /* pos is equivalent to cursor_pos within the range of the command substitution {begin, end} */
+ long offset_within_cmdsubst = cursor_pos - (cmdsubst_begin - buff);
- a = buff + pos;
+ a = cmdsubst_begin + offset_within_cmdsubst;
b = a;
- pa = buff + pos;
+ pa = cmdsubst_begin + offset_within_cmdsubst;
pb = pa;
- assert(begin >= buff);
- assert(begin <= (buff+wcslen(buff)));
- assert(end >= begin);
- assert(end <= (buff+wcslen(buff)));
+ assert(cmdsubst_begin >= buff);
+ assert(cmdsubst_begin <= (buff+wcslen(buff)));
+ assert(cmdsubst_end >= cmdsubst_begin);
+ assert(cmdsubst_end <= (buff+wcslen(buff)));
- const wcstring buffcpy = wcstring(begin, end-begin);
+ const wcstring buffcpy = wcstring(cmdsubst_begin, cmdsubst_end-cmdsubst_begin);
tokenizer_t tok(buffcpy.c_str(), TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS);
for (; tok_has_next(&tok); tok_next(&tok))
@@ -460,9 +464,9 @@ void parse_util_token_extent(const wchar_t *buff,
cursor is between two tokens, so we set it to a zero element
string and break
*/
- if (tok_begin > pos)
+ if (tok_begin > offset_within_cmdsubst)
{
- a = b = (wchar_t *)buff + pos;
+ a = b = cmdsubst_begin + offset_within_cmdsubst;
break;
}
@@ -470,9 +474,9 @@ void parse_util_token_extent(const wchar_t *buff,
If cursor is inside the token, this is the token we are
looking for. If so, set a and b and break
*/
- if ((tok_last_type(&tok) == TOK_STRING) && (tok_end >= pos))
+ if ((tok_last_type(&tok) == TOK_STRING) && (tok_end >= offset_within_cmdsubst))
{
- a = begin + tok_get_pos(&tok);
+ a = cmdsubst_begin + tok_get_pos(&tok);
b = a + wcslen(tok_last(&tok));
break;
}
@@ -482,7 +486,7 @@ void parse_util_token_extent(const wchar_t *buff,
*/
if (tok_last_type(&tok) == TOK_STRING)
{
- pa = begin + tok_get_pos(&tok);
+ pa = cmdsubst_begin + tok_get_pos(&tok);
pb = pa + wcslen(tok_last(&tok));
}
}
diff --git a/parser.cpp b/parser.cpp
index f9d4ba5a..de15c520 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -152,9 +152,9 @@ The fish parser. Contains functions for parsing and evaluating code.
#define INVALID_END_ERR_MSG _( L"'end' command outside of block")
/**
- Error message for Posix-style assignment
+ Error message for Posix-style assignment: foo=bar
*/
-#define COMMAND_ASSIGN_ERR_MSG _( L"Unknown command '%ls'. Did you mean 'set %ls %ls'? For information on assigning values to variables, see the help section on the set command by typing 'help set'.")
+#define COMMAND_ASSIGN_ERR_MSG _( L"Unknown command '%ls'. Did you mean 'set %ls %ls'? See the help section on the set command by typing 'help set'.")
/**
Error for invalid redirection token
@@ -1165,9 +1165,9 @@ int parser_t::is_help(const wchar_t *s, int min_match) const
(len >= (size_t)min_match && (wcsncmp(L"--help", s, len) == 0));
}
-job_t *parser_t::job_create(void)
+job_t *parser_t::job_create()
{
- job_t *res = new job_t(acquire_job_id());
+ job_t *res = new job_t(acquire_job_id(), this->block_io);
this->my_job_list.push_front(res);
job_set_flag(res,
@@ -1253,6 +1253,9 @@ void parser_t::parse_job_argument_list(process_t *p,
wcstring unmatched;
int unmatched_pos=0;
+ /* The set of IO redirections that we construct for the process */
+ io_chain_t process_io_chain;
+
/*
Test if this is the 'count' command. We need to special case
count in the shell, since it should display a help message on
@@ -1557,7 +1560,7 @@ void parser_t::parse_job_argument_list(process_t *p,
if (new_io.get() != NULL)
{
- j->io.push_back(new_io);
+ process_io_chain.push_back(new_io);
}
}
@@ -1611,7 +1614,9 @@ void parser_t::parse_job_argument_list(process_t *p,
}
}
- return;
+ /* Store our IO chain. The existing chain should be empty. */
+ assert(p->io_chain().empty());
+ p->set_io_chain(process_io_chain);
}
/*
@@ -2005,9 +2010,8 @@ int parser_t::parse_job(process_t *p,
if (! has_command && ! use_implicit_cd)
{
- int tmp;
const wchar_t *cmd = args.at(0).completion.c_str();
-
+
/*
We couldn't find the specified command.
@@ -2026,19 +2030,39 @@ int parser_t::parse_job(process_t *p,
and zsh).
*/
- if (wcschr(cmd, L'='))
+ const wchar_t * const equals_ptr = wcschr(cmd, L'=');
+ if (equals_ptr != NULL)
{
- wchar_t *cpy = wcsdup(cmd);
- wchar_t *valpart = wcschr(cpy, L'=');
- *valpart++=0;
-
- debug(0,
- COMMAND_ASSIGN_ERR_MSG,
- cmd,
- cpy,
- valpart);
- free(cpy);
-
+ /* 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'."),
+ cmd,
+ next_str.c_str(),
+ name_str.c_str(),
+ val_str.c_str(),
+ next_str.c_str(),
+ ellipsis_str.c_str());
+ }
+ else
+ {
+ debug(0,
+ COMMAND_ASSIGN_ERR_MSG,
+ cmd,
+ name_str.c_str(),
+ val_str.c_str());
+ }
}
else if (cmd[0]==L'$' || cmd[0] == VARIABLE_EXPAND || cmd[0] == VARIABLE_EXPAND_SINGLE)
{
@@ -2048,15 +2072,17 @@ int parser_t::parse_job(process_t *p,
if (val)
{
debug(0,
- _(L"Variables may not be used as commands. Instead, define a function like 'function %ls; %ls $argv; end'. See the help section for the function command by typing 'help function'."),
+ _(L"Variables may not be used as commands. Instead, define a function like 'function %ls; %ls $argv; end' or use the eval builtin instead, like 'eval %ls'. See the help section for the function command by typing 'help function'."),
cmd+1,
val,
+ cmd,
cmd);
}
else
{
debug(0,
- _(L"Variables may not be used as commands. Instead, define a function. See the help section for the function command by typing 'help function'."),
+ _(L"Variables may not be used as commands. Instead, define a function or use the eval builtin instead, like 'eval %ls'. See the help section for the function command by typing 'help function'."),
+ cmd,
cmd);
}
}
@@ -2086,7 +2112,7 @@ int parser_t::parse_job(process_t *p,
event_fire_generic(L"fish_command_not_found", &event_args);
}
- tmp = current_tokenizer_pos;
+ int tmp = current_tokenizer_pos;
current_tokenizer_pos = tok_get_pos(tok);
fwprintf(stderr, L"%ls", parser_t::current_line());
@@ -2254,7 +2280,7 @@ void parser_t::skipped_exec(job_t * j)
{
if (!current_block->outer->skip)
{
- exec(*this, j);
+ exec_job(*this, j);
return;
}
parser_t::pop_block();
@@ -2267,7 +2293,7 @@ void parser_t::skipped_exec(job_t * j)
const if_block_t *ib = static_cast<const if_block_t*>(current_block);
if (ib->if_expr_evaluated && ! ib->any_branch_taken)
{
- exec(*this, j);
+ exec_job(*this, j);
return;
}
}
@@ -2276,7 +2302,7 @@ void parser_t::skipped_exec(job_t * j)
{
if (current_block->type() == SWITCH)
{
- exec(*this, j);
+ exec_job(*this, j);
return;
}
}
@@ -2316,7 +2342,6 @@ static bool job_should_skip_elseif(const job_t *job, const block_t *current_bloc
void parser_t::eval_job(tokenizer_t *tok)
{
ASSERT_IS_MAIN_THREAD();
- job_t *j;
int start_pos = job_start_pos = tok_get_pos(tok);
long long t1=0, t2=0, t3=0;
@@ -2339,7 +2364,7 @@ void parser_t::eval_job(tokenizer_t *tok)
{
case TOK_STRING:
{
- j = this->job_create();
+ job_t *j = this->job_create();
job_set_flag(j, JOB_FOREGROUND, 1);
job_set_flag(j, JOB_TERMINAL, job_get_flag(j, JOB_CONTROL));
job_set_flag(j, JOB_TERMINAL, job_get_flag(j, JOB_CONTROL) \
@@ -2414,7 +2439,7 @@ void parser_t::eval_job(tokenizer_t *tok)
if (j->first_process->type==INTERNAL_BUILTIN && !j->first_process->next)
was_builtin = 1;
scoped_push<int> tokenizer_pos_push(&current_tokenizer_pos, job_begin_pos);
- exec(*this, j);
+ exec_job(*this, j);
/* Only external commands require a new fishd barrier */
if (!was_builtin)
@@ -3527,8 +3552,8 @@ int parser_t::test(const wchar_t *buff, int *block_level, wcstring *out, const w
}
else
{
- err = 1;
- if (out)
+ // Only print errors once
+ if (out && ! err)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
@@ -3538,6 +3563,7 @@ int parser_t::test(const wchar_t *buff, int *block_level, wcstring *out, const w
print_errors(*out, prefix);
}
+ err = 1;
}
break;
diff --git a/parser.h b/parser.h
index 0c90641b..8b43b83f 100644
--- a/parser.h
+++ b/parser.h
@@ -352,6 +352,9 @@ private:
void print_errors(wcstring &target, const wchar_t *prefix);
void print_errors_stderr();
+ /** Create a job */
+ job_t *job_create();
+
public:
std::vector<profile_item_t*> profile_items;
@@ -457,9 +460,6 @@ public:
/** Return a description of the given blocktype */
const wchar_t *get_block_desc(int block) const;
- /** Create a job */
- job_t *job_create();
-
/** Removes a job */
bool job_remove(job_t *job);
diff --git a/path.cpp b/path.cpp
index 73cfc017..4649e805 100644
--- a/path.cpp
+++ b/path.cpp
@@ -315,6 +315,7 @@ bool path_can_be_implicit_cd(const wcstring &path, wcstring *out_path, const wch
if (string_prefixes_string(L"/", exp_path) ||
string_prefixes_string(L"./", exp_path) ||
string_prefixes_string(L"../", exp_path) ||
+ string_suffixes_string(L"/", exp_path) ||
exp_path == L"..")
{
/* These paths can be implicit cd, so see if you cd to the path. Note that a single period cannot (that's used for sourcing files anyways) */
@@ -367,6 +368,7 @@ bool path_get_config(wcstring &path)
return ! result.empty();
}
+__attribute__((unused))
static void replace_all(wcstring &str, const wchar_t *needle, const wchar_t *replacement)
{
size_t needle_len = wcslen(needle);
@@ -380,24 +382,62 @@ static void replace_all(wcstring &str, const wchar_t *needle, const wchar_t *rep
void path_make_canonical(wcstring &path)
{
-
- /* Remove double slashes */
- size_t size;
- do
+ // Ignore trailing slashes, unless it's the first character
+ size_t len = path.size();
+ while (len > 1 && path.at(len - 1) == L'/')
+ len--;
+
+ // Turn runs of slashes into a single slash
+ size_t trailing = 0;
+ bool prev_was_slash = false;
+ for (size_t leading = 0; leading < len; leading++)
{
- size = path.size();
- replace_all(path, L"//", L"/");
- }
- while (path.size() != size);
+ wchar_t c = path.at(leading);
+ bool is_slash = (c == '/');
+ if (! prev_was_slash || ! is_slash)
+ {
+ // This is either the first slash in a run, or not a slash at all
+ path.at(trailing++) = c;
+ }
+ prev_was_slash = is_slash;
+ }
+ assert(trailing <= len);
+ if (trailing < len)
+ path.resize(trailing);
+}
- /* Remove trailing slashes, except don't remove the first one */
- while (size-- > 1)
+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)
{
- if (path.at(size) != L'/')
+ 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++;
}
- /* Now size is either -1 (if the entire string was slashes) or is the index of the last non-slash character. Either way this will set it to the correct size. */
- path.resize(size+1);
+
+ // We matched if we consumed all of the characters in both strings
+ return idx1 == len1 && idx2 == len2;
}
bool path_is_valid(const wcstring &path, const wcstring &working_directory)
@@ -433,7 +473,7 @@ bool path_is_valid(const wcstring &path, const wcstring &working_directory)
bool paths_are_same_file(const wcstring &path1, const wcstring &path2)
{
- if (path1 == path2)
+ if (paths_are_equivalent(path1, path2))
return true;
struct stat s1, s2;
diff --git a/path.h b/path.h
index a566501e..b822f6e9 100644
--- a/path.h
+++ b/path.h
@@ -73,6 +73,9 @@ bool path_can_be_implicit_cd(const wcstring &path,
*/
void path_make_canonical(wcstring &path);
+/** Check if two paths are equivalent, which means to ignore runs of multiple slashes (or trailing slashes) */
+bool paths_are_equivalent(const wcstring &p1, const wcstring &p2);
+
bool path_is_valid(const wcstring &path, const wcstring &working_directory);
/** Returns whether the two paths refer to the same file */
diff --git a/postfork.cpp b/postfork.cpp
index 6553104b..713e2247 100644
--- a/postfork.cpp
+++ b/postfork.cpp
@@ -37,6 +37,8 @@
/** pipe error */
#define LOCAL_PIPE_ERROR "An error occurred while setting up pipe"
+static bool log_redirections = false;
+
/* Cover for debug_safe that can take an int. The format string should expect a %s */
static void debug_safe_int(int level, const char *format, int val)
{
@@ -105,8 +107,8 @@ int set_child_group(job_t *j, process_t *p, int print_errors)
return res;
}
-/** Make sure the fd used by each redirection is not used by a pipe. */
-static void free_redirected_fds_from_pipes(io_chain_t &io_chain)
+/** Make sure the fd used by each redirection is not used by a pipe. Note that while this does not modify the vector, it does modify the IO redirections within (gulp) */
+static void free_redirected_fds_from_pipes(const io_chain_t &io_chain)
{
size_t max = io_chain.size();
for (size_t i = 0; i < max; i++)
@@ -164,9 +166,9 @@ static void free_redirected_fds_from_pipes(io_chain_t &io_chain)
\return 0 on sucess, -1 on failiure
*/
-static int handle_child_io(io_chain_t &io_chain)
+static int handle_child_io(const io_chain_t &io_chain)
{
-
+ //fprintf(stderr, "child IO for %d\n", getpid());
close_unused_internal_pipes(io_chain);
free_redirected_fds_from_pipes(io_chain);
for (size_t idx = 0; idx < io_chain.size(); idx++)
@@ -183,6 +185,7 @@ static int handle_child_io(io_chain_t &io_chain)
{
case IO_CLOSE:
{
+ if (log_redirections) fprintf(stderr, "%d: close %d\n", getpid(), io->fd);
if (close(io->fd))
{
debug_safe_int(0, "Failed to close file descriptor %s", io->fd);
@@ -232,13 +235,17 @@ static int handle_child_io(io_chain_t &io_chain)
case IO_FD:
{
+ int old_fd = static_cast<const io_fd_t *>(io)->old_fd;
+ if (log_redirections) fprintf(stderr, "%d: fd dup %d to %d\n", getpid(), old_fd, io->fd);
+
/*
This call will sometimes fail, but that is ok,
this is just a precausion.
*/
close(io->fd);
- if (dup2(static_cast<const io_fd_t *>(io)->old_fd, io->fd) == -1)
+
+ if (dup2(old_fd, io->fd) == -1)
{
debug_safe_int(1, FD_ERROR, io->fd);
safe_perror("dup2");
@@ -262,6 +269,7 @@ static int handle_child_io(io_chain_t &io_chain)
io->pipe_fd[0],
io->pipe_fd[1]);
*/
+ if (log_redirections) fprintf(stderr, "%d: %s dup %d to %d\n", getpid(), io->io_mode == IO_BUFFER ? "buffer" : "pipe", io_pipe->pipe_fd[write_pipe_idx], io->fd);
if (dup2(io_pipe->pipe_fd[write_pipe_idx], io->fd) != io->fd)
{
debug_safe(1, LOCAL_PIPE_ERROR);
@@ -284,7 +292,7 @@ static int handle_child_io(io_chain_t &io_chain)
}
-int setup_child_process(job_t *j, process_t *p)
+int setup_child_process(job_t *j, process_t *p, const io_chain_t &io_chain)
{
bool ok=true;
@@ -295,7 +303,7 @@ int setup_child_process(job_t *j, process_t *p)
if (ok)
{
- ok = (0 == handle_child_io(j->io));
+ ok = (0 == handle_child_io(io_chain));
if (p != 0 && ! ok)
{
exit_without_destructors(1);
@@ -371,7 +379,7 @@ pid_t execute_fork(bool wait_for_threads_to_die)
}
#if FISH_USE_POSIX_SPAWN
-bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_file_actions_t *actions, job_t *j, process_t *p)
+bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_file_actions_t *actions, job_t *j, process_t *p, const io_chain_t &io_chain)
{
/* Initialize the output */
if (posix_spawnattr_init(attr) != 0)
@@ -436,19 +444,19 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_fil
err = posix_spawnattr_setsigmask(attr, &sigmask);
/* Make sure that our pipes don't use an fd that the redirection itself wants to use */
- free_redirected_fds_from_pipes(j->io);
+ free_redirected_fds_from_pipes(io_chain);
/* Close unused internal pipes */
std::vector<int> files_to_close;
- get_unused_internal_pipes(files_to_close, j->io);
+ get_unused_internal_pipes(files_to_close, io_chain);
for (size_t i = 0; ! err && i < files_to_close.size(); i++)
{
err = posix_spawn_file_actions_addclose(actions, files_to_close.at(i));
}
- for (size_t idx = 0; idx < j->io.size(); idx++)
+ for (size_t idx = 0; idx < io_chain.size(); idx++)
{
- shared_ptr<const io_data_t> io = j->io.at(idx);
+ const shared_ptr<const io_data_t> io = io_chain.at(idx);
if (io->io_mode == IO_FD)
{
diff --git a/postfork.h b/postfork.h
index ba82918a..439cedff 100644
--- a/postfork.h
+++ b/postfork.h
@@ -53,13 +53,13 @@ int set_child_group(job_t *j, process_t *p, int print_errors);
\param j the job to set up the IO for
\param p the child process to set up
- \param io_chain the IO chain to use (ignores the job's iochain)
+ \param io_chain the IO chain to use
\return 0 on sucess, -1 on failiure. When this function returns,
signals are always unblocked. On failiure, signal handlers, io
redirections and process group of the process is undefined.
*/
-int setup_child_process(job_t *j, process_t *p);
+int setup_child_process(job_t *j, process_t *p, const io_chain_t &io_chain);
/* Call fork(), optionally waiting until we are no longer multithreaded. If the forked child doesn't do anything that could allocate memory, take a lock, etc. (like call exec), then it's not necessary to wait for threads to die. If the forked child may do those things, it should wait for threads to die.
*/
@@ -73,7 +73,7 @@ void safe_report_exec_error(int err, const char *actual_cmd, const char * const
#if FISH_USE_POSIX_SPAWN
/* Initializes and fills in a posix_spawnattr_t; on success, the caller should destroy it via posix_spawnattr_destroy */
-bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_file_actions_t *actions, job_t *j, process_t *p);
+bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_file_actions_t *actions, job_t *j, process_t *p, const io_chain_t &io_chain);
#endif
#endif
diff --git a/proc.cpp b/proc.cpp
index d0412414..1ca70099 100644
--- a/proc.cpp
+++ b/proc.cpp
@@ -339,9 +339,7 @@ int job_signal(job_t *j, int signal)
}
else
{
- process_t *p;
-
- for (p = j->first_process; p; p=p->next)
+ for (process_t *p = j->first_process; p; p=p->next)
{
if (! p->completed)
{
@@ -539,14 +537,14 @@ process_t::~process_t()
delete this->next;
}
-job_t::job_t(job_id_t jobid) :
+job_t::job_t(job_id_t jobid, const io_chain_t &bio) :
command_str(),
command_narrow(),
+ block_io(bio),
first_process(NULL),
pgid(0),
tmodes(),
job_id(jobid),
- io(),
flags(0)
{
}
@@ -558,6 +556,17 @@ job_t::~job_t()
release_job_id(job_id);
}
+/* Return all the IO redirections. Start with the block IO, then walk over the processes */
+io_chain_t job_t::all_io_redirections() const
+{
+ io_chain_t result = this->block_io;
+ for (process_t *p = this->first_process; p != NULL; p = p->next)
+ {
+ result.append(p->io_chain());
+ }
+ return result;
+}
+
/* This is called from a signal handler */
void job_handle_signal(int signal, siginfo_t *info, void *con)
{
@@ -876,9 +885,10 @@ static int select_try(job_t *j)
FD_ZERO(&fds);
- for (size_t idx = 0; idx < j->io.size(); idx++)
+ const io_chain_t chain = j->all_io_redirections();
+ for (size_t idx = 0; idx < chain.size(); idx++)
{
- const io_data_t *io = j->io.at(idx).get();
+ const io_data_t *io = chain.at(idx).get();
if (io->io_mode == IO_BUFFER)
{
CAST_INIT(const io_pipe_t *, io_pipe, io);
@@ -917,9 +927,10 @@ static void read_try(job_t *j)
/*
Find the last buffer, which is the one we want to read from
*/
- for (size_t idx = 0; idx < j->io.size(); idx++)
+ const io_chain_t chain = j->all_io_redirections();
+ for (size_t idx = 0; idx < chain.size(); idx++)
{
- io_data_t *d = j->io.at(idx).get();
+ io_data_t *d = chain.at(idx).get();
if (d->io_mode == IO_BUFFER)
{
buff = static_cast<io_buffer_t *>(d);
diff --git a/proc.h b/proc.h
index 1d4d210d..aff7983b 100644
--- a/proc.h
+++ b/proc.h
@@ -134,6 +134,8 @@ private:
/* narrow copy of argv0 so we don't have to convert after fork */
narrow_string_rep_t argv0_narrow;
+ io_chain_t process_io_chain;
+
/* No copying */
process_t(const process_t &rhs);
void operator=(const process_t &rhs);
@@ -190,6 +192,17 @@ public:
return argv0_narrow.get();
}
+ /* IO chain getter and setter */
+ const io_chain_t &io_chain() const
+ {
+ return process_io_chain;
+ }
+
+ void set_io_chain(const io_chain_t &chain)
+ {
+ this->process_io_chain = chain;
+ }
+
/** actual command to pass to exec in case of EXTERNAL or INTERNAL_EXEC. */
wcstring actual_cmd;
@@ -272,6 +285,7 @@ void release_job_id(job_id_t jobid);
A struct represeting a job. A job is basically a pipeline of one
or more processes and a couple of flags.
*/
+class parser_t;
class job_t
{
/**
@@ -284,13 +298,16 @@ class job_t
/* narrow copy so we don't have to convert after fork */
narrow_string_rep_t command_narrow;
+ /* The IO chain associated with the block */
+ const io_chain_t block_io;
+
/* No copying */
job_t(const job_t &rhs);
void operator=(const job_t &);
public:
- job_t(job_id_t jobid);
+ job_t(job_id_t jobid, const io_chain_t &bio);
~job_t();
/** Returns whether the command is empty. */
@@ -350,13 +367,16 @@ public:
*/
const job_id_t job_id;
- /** List of all IO redirections for this job. */
- io_chain_t io;
-
/**
Bitset containing information about the job. A combination of the JOB_* constants.
*/
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; }
+
+ /* Fetch all the IO redirections associated with the job */
+ io_chain_t all_io_redirections() const;
};
/**
diff --git a/reader.cpp b/reader.cpp
index 8febb799..228fa918 100644
--- a/reader.cpp
+++ b/reader.cpp
@@ -111,7 +111,7 @@ commence.
fish specific commands, meaning it will work even if fish is not
installed. This is used by read_i.
*/
-#define DEFAULT_PROMPT L"echo -n \"$USER@\"(hostname|cut -d . -f 1)' '(pwd)'> '"
+#define DEFAULT_PROMPT L"echo -n \"$USER@\"(hostname|cut -d . -f 1)' '(__fish_pwd)'> '"
/**
The name of the function that prints the fish prompt
@@ -127,7 +127,7 @@ commence.
/**
The default title for the reader. This is used by reader_readline.
*/
-#define DEFAULT_TITLE L"echo $_ \" \"; pwd"
+#define DEFAULT_TITLE L"echo $_ \" \"; __fish_pwd"
/**
The maximum number of characters to read from the keyboard without
@@ -249,8 +249,8 @@ public:
/** Do what we need to do whenever our command line changes */
void command_line_changed(void);
- /** Expand abbreviations at the current cursor position. */
- bool expand_abbreviation_as_necessary();
+ /** Expand abbreviations at the current cursor position, minus backtrack_amt. */
+ bool expand_abbreviation_as_necessary(size_t cursor_backtrack);
/** The current position of the cursor in buff. */
size_t buff_pos;
@@ -392,11 +392,12 @@ static volatile int interrupted=0;
static bool is_backslashed(const wcstring &str, size_t pos);
static wchar_t unescaped_quote(const wcstring &str, size_t pos);
-/**
- Stores the previous termios mode so we can reset the modes when
- we execute programs and when the shell exits.
-*/
-static struct termios saved_modes;
+/** Mode on startup, which we restore on exit */
+static struct termios terminal_mode_on_startup;
+
+/** Mode we use to execute programs */
+static struct termios terminal_mode_for_executing_programs;
+
static void reader_super_highlight_me_plenty(size_t pos);
@@ -415,7 +416,7 @@ static void term_donate()
while (1)
{
- if (tcsetattr(0,TCSANOW,&saved_modes))
+ if (tcsetattr(0, TCSANOW, &terminal_mode_for_executing_programs))
{
if (errno != EINTR)
{
@@ -660,7 +661,7 @@ bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t curso
const wcstring subcmd = wcstring(cmdsub_begin, cmdsub_end - cmdsub_begin);
const wchar_t *subcmd_cstr = subcmd.c_str();
- /* Get the token before the cursor */
+ /* Get the token containing the cursor */
const wchar_t *subcmd_tok_begin = NULL, *subcmd_tok_end = NULL;
assert(cursor_pos >= subcmd_offset);
size_t subcmd_cursor_pos = cursor_pos - subcmd_offset;
@@ -776,15 +777,16 @@ bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t curso
return result;
}
-/* Expand abbreviations. This may change the command line but does NOT repaint it. This is to allow the caller to coalesce repaints. */
-bool reader_data_t::expand_abbreviation_as_necessary()
+/* Expand abbreviations at the current cursor position, minus the given cursor backtrack. This may change the command line but does NOT repaint it. This is to allow the caller to coalesce repaints. */
+bool reader_data_t::expand_abbreviation_as_necessary(size_t cursor_backtrack)
{
bool result = false;
if (this->expand_abbreviations)
{
/* Try expanding abbreviations */
wcstring new_cmdline;
- if (reader_expand_abbreviation_in_command(this->command_line, this->buff_pos, &new_cmdline))
+ size_t cursor_pos = this->buff_pos - mini(this->buff_pos, cursor_backtrack);
+ if (reader_expand_abbreviation_in_command(this->command_line, cursor_pos, &new_cmdline))
{
/* We expanded an abbreviation! The cursor moves by the difference in the command line lengths. */
size_t new_buff_pos = this->buff_pos + new_cmdline.size() - this->command_line.size();
@@ -801,8 +803,8 @@ bool reader_data_t::expand_abbreviation_as_necessary()
/** Sorts and remove any duplicate completions in the list. */
static void sort_and_make_unique(std::vector<completion_t> &l)
{
- sort(l.begin(), l.end());
- l.erase(std::unique(l.begin(), l.end()), l.end());
+ sort(l.begin(), l.end(), completion_t::is_alphabetically_less_than);
+ l.erase(std::unique(l.begin(), l.end(), completion_t::is_alphabetically_equal_to), l.end());
}
@@ -961,28 +963,37 @@ void reader_init()
{
VOMIT_ON_FAILURE(pthread_key_create(&generation_count_key, NULL));
- tcgetattr(0,&shell_modes); /* get the current terminal modes */
- memcpy(&saved_modes,
- &shell_modes,
- sizeof(saved_modes)); /* save a copy so we can reset the terminal later */
+ /* Save the initial terminal mode */
+ tcgetattr(STDIN_FILENO, &terminal_mode_on_startup);
+ /* Set the mode used for program execution, initialized to the current mode */
+ memcpy(&terminal_mode_for_executing_programs, &terminal_mode_on_startup, sizeof terminal_mode_for_executing_programs);
+ terminal_mode_for_executing_programs.c_iflag &= ~IXON; /* disable flow control */
+ terminal_mode_for_executing_programs.c_iflag &= ~IXOFF; /* disable flow control */
+
+ /* Set the mode used for the terminal, initialized to the current mode */
+ memcpy(&shell_modes, &terminal_mode_on_startup, sizeof shell_modes);
shell_modes.c_lflag &= ~ICANON; /* turn off canonical mode */
shell_modes.c_lflag &= ~ECHO; /* turn off echo mode */
+ shell_modes.c_iflag &= ~IXON; /* disable flow control */
+ shell_modes.c_iflag &= ~IXOFF; /* disable flow control */
shell_modes.c_cc[VMIN]=1;
shell_modes.c_cc[VTIME]=0;
+#if defined(_POSIX_VDISABLE)
// 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
}
void reader_destroy()
{
- tcsetattr(0, TCSANOW, &saved_modes);
+ tcsetattr(0, TCSANOW, &terminal_mode_on_startup);
pthread_key_delete(generation_count_key);
}
@@ -1078,34 +1089,38 @@ static void remove_backward()
/**
Insert the characters of the string into the command line buffer
and print them to the screen using syntax highlighting, etc.
+ Optionally also expand abbreviations.
+ Returns true if the string changed.
*/
-static int insert_string(const wcstring &str)
+static bool insert_string(const wcstring &str, bool should_expand_abbreviations = false)
{
size_t len = str.size();
if (len == 0)
- return 0;
+ return false;
data->command_line.insert(data->buff_pos, str);
data->buff_pos += len;
data->command_line_changed();
data->suppress_autosuggestion = false;
+ if (should_expand_abbreviations)
+ data->expand_abbreviation_as_necessary(1);
+
/* Syntax highlight. Note we must have that buff_pos > 0 because we just added something nonzero to its length */
assert(data->buff_pos > 0);
reader_super_highlight_me_plenty(data->buff_pos-1);
-
reader_repaint();
- return 1;
-}
+ return true;
+}
/**
Insert the character into the command line buffer and print it to
the screen using syntax highlighting, etc.
*/
-static int insert_char(wchar_t c)
+static bool insert_char(wchar_t c, bool should_expand_abbreviations = false)
{
- return insert_string(wcstring(&c, 1));
+ return insert_string(wcstring(1, c), should_expand_abbreviations);
}
@@ -1274,11 +1289,11 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
wcstring prefix_esc;
char *foo;
- shared_ptr<io_buffer_t> in(io_buffer_t::create(true, 3));
- shared_ptr<io_buffer_t> out(io_buffer_t::create(false, 4));
+ shared_ptr<io_buffer_t> in_buff(io_buffer_t::create(true, 3));
+ shared_ptr<io_buffer_t> out_buff(io_buffer_t::create(false, 4));
// The above may fail e.g. if we have too many open fds
- if (in.get() == NULL || out.get() == NULL)
+ if (in_buff.get() == NULL || out_buff.get() == NULL)
return;
wchar_t *escaped_separator;
@@ -1350,26 +1365,26 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
free(escaped_separator);
foo = wcs2str(msg.c_str());
- in->out_buffer_append(foo, strlen(foo));
+ in_buff->out_buffer_append(foo, strlen(foo));
free(foo);
term_donate();
parser_t &parser = parser_t::principal_parser();
io_chain_t io_chain;
- io_chain.push_back(out);
- io_chain.push_back(in);
+ io_chain.push_back(out_buff);
+ io_chain.push_back(in_buff);
parser.eval(cmd, io_chain, TOP);
term_steal();
- out->read();
+ out_buff->read();
- int nil=0;
- out->out_buffer_append((char *)&nil, 1);
+ const char zero = 0;
+ out_buff->out_buffer_append(&zero, 1);
- const char *outbuff = out->out_buffer_ptr();
- if (outbuff)
+ const char *out_data = out_buff->out_buffer_ptr();
+ if (out_data)
{
- const wcstring str = str2wcstring(outbuff);
+ const wcstring str = str2wcstring(out_data);
size_t idx = str.size();
while (idx--)
{
@@ -1637,35 +1652,50 @@ static bool reader_can_replace(const wcstring &in, int flags)
/* Compare two completions, ordering completions with better match types first */
bool compare_completions_by_match_type(const completion_t &a, const completion_t &b)
{
- /* Compare match types */
- int match_compare = a.match.compare(b.match);
- if (match_compare != 0)
+ /* Compare match types, unless both completions are prefix (#923) in which case we always want to compare them alphabetically */
+ if (a.match.type != fuzzy_match_prefix || b.match.type != fuzzy_match_prefix)
{
- return match_compare < 0;
+ int match_compare = a.match.compare(b.match);
+ if (match_compare != 0)
+ {
+ return match_compare < 0;
+ }
}
/* Compare using file comparison */
return wcsfilecmp(a.completion.c_str(), b.completion.c_str()) < 0;
}
-/* Order completions such that case insensitive completions come first. */
-static void prioritize_completions(std::vector<completion_t> &comp)
+/* Determine the best match type for a set of completions */
+static fuzzy_match_type_t get_best_match_type(const std::vector<completion_t> &comp)
{
- /* Determine the best match type */
- size_t i;
fuzzy_match_type_t best_type = fuzzy_match_none;
- for (i=0; i < comp.size(); i++)
+ for (size_t i=0; i < comp.size(); i++)
{
const completion_t &el = comp.at(i);
if (el.match.type < best_type)
+ {
best_type = el.match.type;
+ }
+ }
+ /* If the best type is an exact match, reduce it to prefix match. Otherwise a tab completion will only show one match if it matches a file exactly. (see issue #959) */
+ if (best_type == fuzzy_match_exact)
+ {
+ best_type = fuzzy_match_prefix;
}
+ return best_type;
+}
- /* Throw out completions whose match types are not the best. */
- i = comp.size();
+/* Order completions such that case insensitive completions come first. */
+static void prioritize_completions(std::vector<completion_t> &comp)
+{
+ fuzzy_match_type_t best_type = get_best_match_type(comp);
+
+ /* Throw out completions whose match types are less suitable than the best. */
+ size_t i = comp.size();
while (i--)
{
- if (comp.at(i).match.type != best_type)
+ if (comp.at(i).match.type > best_type)
{
comp.erase(comp.begin() + i);
}
@@ -1682,18 +1712,17 @@ static const completion_t *cycle_competions(const std::vector<completion_t> &com
if (size == 0)
return NULL;
+ // 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;
- for (;;)
+ size_t remaining = comp.size();
+ while (remaining--)
{
/* Bump the index */
idx = (idx + 1) % size;
- /* Bail if we've looped */
- if (idx == start_idx)
- break;
-
/* Get the completion */
const completion_t &c = comp.at(idx);
@@ -1780,24 +1809,14 @@ static bool handle_completions(const std::vector<completion_t> &comp)
if (!done)
{
-
- /* Determine the type of the best match(es) */
- fuzzy_match_type_t best_match_type = fuzzy_match_none;
- for (size_t i=0; i < comp.size(); i++)
- {
- const completion_t &el = comp.at(i);
- if (el.match.type < best_match_type)
- {
- best_match_type = el.match.type;
- }
- }
+ fuzzy_match_type_t best_match_type = get_best_match_type(comp);
/* Determine whether we are going to replace the token or not. If any commands of the best type do not require replacement, then ignore all those that want to use replacement */
bool will_replace_token = true;
for (size_t i=0; i< comp.size(); i++)
{
const completion_t &el = comp.at(i);
- if (el.match.type == best_match_type && !(el.flags & COMPLETE_REPLACES_TOKEN))
+ if (el.match.type <= best_match_type && !(el.flags & COMPLETE_REPLACES_TOKEN))
{
will_replace_token = false;
break;
@@ -1809,8 +1828,8 @@ static bool handle_completions(const std::vector<completion_t> &comp)
for (size_t i=0; i < comp.size(); i++)
{
const completion_t &el = comp.at(i);
- /* Only use completions with the best match type */
- if (el.match.type != best_match_type)
+ /* Ignore completions with a less suitable match type than the best. */
+ if (el.match.type > best_match_type)
continue;
/* Only use completions that match replace_token */
@@ -2153,7 +2172,7 @@ static void set_command_line_and_position(const wcstring &new_str, size_t pos)
reader_repaint();
}
-void reader_replace_current_token(const wchar_t *new_token)
+static void reader_replace_current_token(const wchar_t *new_token)
{
const wchar_t *begin, *end;
@@ -2161,7 +2180,7 @@ void reader_replace_current_token(const wchar_t *new_token)
/* Find current token */
const wchar_t *buff = data->command_line.c_str();
- parse_util_token_extent((wchar_t *)buff, data->buff_pos, &begin, &end, 0, 0);
+ parse_util_token_extent(buff, data->buff_pos, &begin, &end, 0, 0);
if (!begin || !end)
return;
@@ -2312,6 +2331,13 @@ static void handle_token_history(int forward, int reset)
}
}
+ break;
+
+ default:
+ {
+ break;
+ }
+
}
}
}
@@ -2809,7 +2835,7 @@ int exit_status()
static void handle_end_loop()
{
job_t *j;
- int job_count=0;
+ int stopped_jobs_count=0;
int is_breakpoint=0;
block_t *b;
parser_t &parser = parser_t::principal_parser();
@@ -2828,14 +2854,14 @@ static void handle_end_loop()
job_iterator_t jobs;
while ((j = jobs.next()))
{
- if (!job_is_completed(j))
+ if (!job_is_completed(j) && (job_is_stopped(j)))
{
- job_count++;
+ stopped_jobs_count++;
break;
}
}
- if (!reader_exit_forced() && !data->prev_end_loop && job_count && !is_breakpoint)
+ if (!reader_exit_forced() && !data->prev_end_loop && stopped_jobs_count && !is_breakpoint)
{
writestr(_(L"There are stopped jobs. A second attempt to exit will enforce their termination.\n"));
@@ -3013,7 +3039,7 @@ const wchar_t *reader_readline(void)
/* The command line before completion */
wcstring cycle_command_line;
- size_t cycle_cursor_pos;
+ size_t cycle_cursor_pos = 0;
data->search_buff.clear();
data->search_mode = NO_SEARCH;
@@ -3114,10 +3140,17 @@ const wchar_t *reader_readline(void)
case R_END_OF_LINE:
{
- while (buff[data->buff_pos] &&
- buff[data->buff_pos] != L'\n')
+ if (data->buff_pos < data->command_length())
{
- data->buff_pos++;
+ while (buff[data->buff_pos] &&
+ buff[data->buff_pos] != L'\n')
+ {
+ data->buff_pos++;
+ }
+ }
+ else
+ {
+ accept_autosuggestion(true);
}
reader_repaint();
@@ -3432,7 +3465,7 @@ const wchar_t *reader_readline(void)
if (command_test_result == 0 || command_test_result == PARSER_TEST_INCOMPLETE)
{
/* This command is valid, but an abbreviation may make it invalid. If so, we will have to test again. */
- bool abbreviation_expanded = data->expand_abbreviation_as_necessary();
+ bool abbreviation_expanded = data->expand_abbreviation_as_necessary(1);
if (abbreviation_expanded)
{
/* It's our reponsibility to rehighlight and repaint. But everything we do below triggers a repaint. */
@@ -3510,9 +3543,9 @@ const wchar_t *reader_readline(void)
data->search_buff.append(data->command_line);
data->history_search = history_search_t(*data->history, data->search_buff, HISTORY_SEARCH_TYPE_CONTAINS);
- /* Skip the autosuggestion as history */
+ /* Skip the autosuggestion as history unless it was truncated */
const wcstring &suggest = data->autosuggestion;
- if (! suggest.empty())
+ if (! suggest.empty() && ! data->screen.autosuggestion_is_truncated)
{
data->history_search.skip_matches(wcstring_list_t(&suggest, 1 + &suggest));
}
@@ -3773,20 +3806,53 @@ 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;
+ }
+ data->command_line_changed();
+ reader_super_highlight_me_plenty(data->buff_pos);
+ reader_repaint();
+ break;
+ }
+
/* Other, if a normal character, we add it to the command */
default:
{
if ((!wchar_private(c)) && (((c>31) || (c==L'\n'))&& (c != 127)))
{
- /* Expand abbreviations on space */
- if (c == L' ')
- {
- data->expand_abbreviation_as_necessary();
- }
+ /* Expand abbreviations after space */
+ bool should_expand_abbreviations = (c == L' ');
/* Regular character */
- insert_char(c);
+ insert_char(c, should_expand_abbreviations);
}
else
{
diff --git a/reader.h b/reader.h
index 0ead2aa4..28340ad7 100644
--- a/reader.h
+++ b/reader.h
@@ -217,11 +217,6 @@ void reader_set_exit_on_interrupt(bool flag);
int exit_status();
/**
- Replace the current token with the specified string
-*/
-void reader_replace_current_token(const wchar_t *new_token);
-
-/**
The readers interrupt signal handler. Cancels all currently running blocks.
*/
void reader_handle_int(int signal);
diff --git a/screen.cpp b/screen.cpp
index 9cae7d36..5ebe8605 100644
--- a/screen.cpp
+++ b/screen.cpp
@@ -92,11 +92,9 @@ public:
specified position of the specified wide character string. All of
\c seq must match, but str may be longer than seq.
*/
-static int try_sequence(const char *seq, const wchar_t *str)
+static size_t try_sequence(const char *seq, const wchar_t *str)
{
- int i;
-
- for (i=0;; i++)
+ for (size_t i=0; ; i++)
{
if (!seq[i])
return i;
@@ -121,29 +119,6 @@ static size_t next_tab_stop(size_t in)
return ((in/tab_width)+1)*tab_width;
}
-// PCA for term256 support, let's just detect the escape codes directly
-static int is_term256_escape(const wchar_t *str)
-{
- // An escape code looks like this: \x1b[38;5;<num>m
- // or like this: \x1b[48;5;<num>m
-
- // parse out the required prefix
- int len = try_sequence("\x1b[38;5;", str);
- if (! len) len = try_sequence("\x1b[48;5;", str);
- if (! len) return 0;
-
- // now try parsing out a string of digits
- // we need at least one
- if (! iswdigit(str[len])) return 0;
- while (iswdigit(str[len])) len++;
-
- // look for the terminating m
- if (str[len++] != L'm') return 0;
-
- // success
- return len;
-}
-
/* Like fish_wcwidth, but returns 0 for control characters instead of -1 */
static int fish_wcwidth_min_0(wchar_t wc)
{
@@ -157,6 +132,178 @@ static bool allow_soft_wrap(void)
return !! auto_right_margin;
}
+
+/* Returns the number of characters in the escape code starting at 'code' (which should initially contain \x1b) */
+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)
+ {
+ /*
+ Detect these terminfo color escapes with parameter
+ value 0..7, all of which don't move the cursor
+ */
+ char * const esc[] =
+ {
+ set_a_foreground,
+ set_a_background,
+ 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);
+ if (len)
+ {
+ resulting_length = len;
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (cur_term != NULL)
+ {
+ /*
+ Detect these semi-common terminfo escapes without any
+ parameter values, all of which don't move the cursor
+ */
+ char * const esc2[] =
+ {
+ enter_bold_mode,
+ exit_attribute_mode,
+ enter_underline_mode,
+ exit_underline_mode,
+ enter_standout_mode,
+ exit_standout_mode,
+ flash_screen,
+ enter_subscript_mode,
+ exit_subscript_mode,
+ enter_superscript_mode,
+ exit_superscript_mode,
+ enter_blink_mode,
+ enter_italics_mode,
+ exit_italics_mode,
+ enter_reverse_mode,
+ enter_shadow_mode,
+ exit_shadow_mode,
+ enter_standout_mode,
+ exit_standout_mode,
+ enter_secure_mode
+ };
+
+
+
+ for (size_t p=0; p < sizeof esc2 / sizeof *esc2 && !found; p++)
+ {
+ if (!esc2[p])
+ continue;
+ /*
+ Test both padded and unpadded version, just to
+ be safe. Most versions of tparm don't actually
+ seem to do anything these days.
+ */
+ size_t len = maxi(try_sequence(tparm(esc2[p]), code), try_sequence(esc2[p], code));
+ if (len)
+ {
+ resulting_length = len;
+ found = true;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ if (code[1] == L'k')
+ {
+ /* This looks like the escape sequence for setting a screen name */
+ const env_var_t term_name = env_get_string(L"TERM");
+ if (!term_name.missing() && string_prefixes_string(L"screen", term_name))
+ {
+ const wchar_t * const screen_name_end_sentinel = L"\x1b\\";
+ const wchar_t *screen_name_end = wcsstr(&code[2], screen_name_end_sentinel);
+ if (screen_name_end != NULL)
+ {
+ const wchar_t *escape_sequence_end = screen_name_end + wcslen(screen_name_end_sentinel);
+ resulting_length = escape_sequence_end - code;
+ }
+ else
+ {
+ /* Consider just <esc>k to be the code */
+ resulting_length = 2;
+ }
+ found = true;
+ }
+ }
+ }
+
+ if (! found)
+ {
+ /* Generic VT100 one byte sequence: CSI followed by something in the range @ through _ */
+ if (code[1] == L'[' && (code[2] >= L'@' && code[2] <= L'_'))
+ {
+ resulting_length = 3;
+ 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 */
+ if (code[1] == L'[')
+ {
+ // Start at 2 to skip over <esc>[
+ size_t cursor = 2;
+ for (; code[cursor] != L'\0'; cursor++)
+ {
+ /* 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'~')
+ {
+ cursor++;
+ break;
+ }
+ }
+ /* curs now indexes just beyond the end of the sequence (or at the terminating zero) */
+ found = true;
+ resulting_length = cursor;
+ }
+ }
+
+ if (! found)
+ {
+ /* Generic VT100 two byte sequence: <esc> followed by something in the range @ through _ */
+ if (code[1] >= L'@' && code[1] <= L'_')
+ {
+ resulting_length = 2;
+ found = true;
+ }
+ }
+
+ return resulting_length;
+}
+
/* Information about a prompt layout */
struct prompt_layout_t
{
@@ -178,7 +325,7 @@ struct prompt_layout_t
static prompt_layout_t calc_prompt_layout(const wchar_t *prompt)
{
size_t current_line_width = 0;
- size_t j, k;
+ size_t j;
prompt_layout_t prompt_layout = {};
prompt_layout.line_count = 1;
@@ -187,134 +334,12 @@ static prompt_layout_t calc_prompt_layout(const wchar_t *prompt)
{
if (prompt[j] == L'\x1b')
{
- /*
- This is the start of an escape code. Try to guess its width.
- */
- size_t p;
- int len=0;
- bool found = false;
-
- /*
- Detect these terminfo color escapes with parameter
- value 0..7, all of which don't move the cursor
- */
- char * const esc[] =
- {
- set_a_foreground,
- set_a_background,
- set_foreground,
- set_background,
- }
- ;
-
- /*
- Detect these semi-common terminfo escapes without any
- parameter values, all of which don't move the cursor
- */
- char * const esc2[] =
- {
- enter_bold_mode,
- exit_attribute_mode,
- enter_underline_mode,
- exit_underline_mode,
- enter_standout_mode,
- exit_standout_mode,
- flash_screen,
- enter_subscript_mode,
- exit_subscript_mode,
- enter_superscript_mode,
- exit_superscript_mode,
- enter_blink_mode,
- enter_italics_mode,
- exit_italics_mode,
- enter_reverse_mode,
- enter_shadow_mode,
- exit_shadow_mode,
- enter_standout_mode,
- exit_standout_mode,
- enter_secure_mode
- }
- ;
-
- for (p=0; p < sizeof esc / sizeof *esc && !found; p++)
- {
- if (!esc[p])
- continue;
-
- for (k=0; k<8; k++)
- {
- len = try_sequence(tparm(esc[p],k), &prompt[j]);
- if (len)
- {
- j += (len-1);
- found = true;
- break;
- }
- }
- }
-
- /* PCA for term256 support, let's just detect the escape codes directly */
- if (! found)
- {
- len = is_term256_escape(&prompt[j]);
- if (len)
- {
- j += (len - 1);
- found = true;
- }
- }
-
-
- for (p=0; p < (sizeof(esc2)/sizeof(char *)) && !found; p++)
- {
- if (!esc2[p])
- continue;
- /*
- Test both padded and unpadded version, just to
- be safe. Most versions of tparm don't actually
- seem to do anything these days.
- */
- len = maxi(try_sequence(tparm(esc2[p]), &prompt[j]),
- try_sequence(esc2[p], &prompt[j]));
-
- if (len)
- {
- j += (len-1);
- found = true;
- }
- }
-
- if (!found)
+ /* This is the start of an escape code. Skip over it if it's at least one character long. */
+ size_t escape_len = escape_code_length(&prompt[j]);
+ if (escape_len > 0)
{
- if (prompt[j+1] == L'k')
- {
- const env_var_t term_name = env_get_string(L"TERM");
- if (!term_name.missing() && string_prefixes_string(L"screen", term_name))
- {
- const wchar_t *end;
- j+=2;
- found = true;
- end = wcsstr(&prompt[j], L"\x1b\\");
- if (end)
- {
- /*
- You'd thing this should be
- '(end-prompt)+2', in order to move j
- past the end of the string, but there is
- a 'j++' at the end of each lap, so j
- should always point to the last menged
- character, e.g. +1.
- */
- j = (end-prompt)+1;
- }
- else
- {
- break;
- }
- }
- }
+ j += escape_len - 1;
}
-
}
else if (prompt[j] == L'\t')
{
@@ -1035,7 +1060,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. */
@@ -1245,6 +1270,9 @@ void s_write(screen_t *s,
/* Compute a layout */
const screen_layout_t layout = compute_layout(s, screen_width, left_prompt, right_prompt, explicit_command_line, autosuggestion, indent);
+ /* Determine whether, if we have an autosuggestion, it was truncated */
+ s->autosuggestion_is_truncated = ! autosuggestion.empty() && autosuggestion != layout.autosuggestion;
+
/* Clear the desired screen */
s->desired.resize(0);
s->desired.cursor.x = s->desired.cursor.y = 0;
@@ -1402,6 +1430,7 @@ screen_t::screen_t() :
last_right_prompt_width(),
actual_width(SCREEN_WIDTH_UNINITIALIZED),
soft_wrap_location(INVALID_LOCATION),
+ autosuggestion_is_truncated(false),
need_clear_lines(false),
need_clear_screen(false),
actual_lines_before_reset(0),
diff --git a/screen.h b/screen.h
index 1dcb34bd..1d9fde2c 100644
--- a/screen.h
+++ b/screen.h
@@ -140,6 +140,9 @@ 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;
/**
This flag is set to true when there is reason to suspect that
@@ -155,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.
@@ -224,5 +227,7 @@ enum screen_reset_mode_t
void s_reset(screen_t *s, screen_reset_mode_t mode);
+/* Returns the length of an escape code. Exposed for testing purposes only. */
+size_t escape_code_length(const wchar_t *code);
#endif
diff --git a/share/completions/apt-get.fish b/share/completions/apt-get.fish
index 1f87d694..4037df08 100644
--- a/share/completions/apt-get.fish
+++ b/share/completions/apt-get.fish
@@ -2,7 +2,7 @@
function __fish_apt_no_subcommand --description 'Test if apt has yet to be given the subcommand'
for i in (commandline -opc)
- if contains -- $i update upgrade dselect-upgrade dist-upgrade install remove source build-dep check clean autoclean
+ if contains -- $i update upgrade dselect-upgrade dist-upgrade install remove purge source build-dep check clean autoclean
return 1
end
end
@@ -11,7 +11,7 @@ end
function __fish_apt_use_package --description 'Test if apt command should have packages as potential completion'
for i in (commandline -opc)
- if contains -- $i contains install remove build-dep
+ if contains -- $i contains install remove purge build-dep
return 0
end
end
diff --git a/share/completions/git.fish b/share/completions/git.fish
index 3532ef65..d4b9fcf3 100644
--- a/share/completions/git.fish
+++ b/share/completions/git.fish
@@ -53,7 +53,7 @@ function __fish_git_using_command
end
# aliased command
- set -l aliased (command git config --get "alias.$cmd[2]" | sed 's/ .*$//')
+ set -l aliased (command git config --get "alias.$cmd[2]" ^ /dev/null | sed 's/ .*$//')
if [ $argv[1] = "$aliased" ]
return 0
end
@@ -328,6 +328,8 @@ complete -f -c git -n '__fish_git_using_command stash' -a apply -d 'Apply a sing
complete -f -c git -n '__fish_git_using_command stash' -a clear -d 'Remove all stashed states'
complete -f -c git -n '__fish_git_using_command stash' -a drop -d 'Remove a single stashed state from the stash list'
complete -f -c git -n '__fish_git_using_command stash' -a create -d 'Create a stash'
+complete -f -c git -n '__fish_git_using_command stash' -a save -d 'Save a new stash'
+complete -f -c git -n '__fish_git_using_command stash' -a branch -d 'Create a new branch from a stash'
# TODO other options
### config
diff --git a/share/completions/make.fish b/share/completions/make.fish
index 05845e10..dfe5090a 100644
--- a/share/completions/make.fish
+++ b/share/completions/make.fish
@@ -6,7 +6,7 @@
# complicated to do.
set -l is_assignment "commandline -ct|sgrep '..*='"
-set -l complete_file_assignment '(commandline -ct)(complete --do-complete=this_command_does_not_exist\ (commandline -ct|sed -e \'s/.*=//\'))'
+set -l complete_file_assignment '(commandline -ct|sed -e \'s/=.*/=/\')(complete --do-complete=this_command_does_not_exist\ (commandline -ct|sed -e \'s/.*=//\'))'
complete -c make --condition $is_assignment -a $complete_file_assignment
complete -x -c make -a "(__fish_print_make_targets)" --description "Target"
diff --git a/share/completions/perl.fish b/share/completions/perl.fish
index 4754f645..6266981d 100644
--- a/share/completions/perl.fish
+++ b/share/completions/perl.fish
@@ -1,6 +1,8 @@
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)"
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'
@@ -26,8 +28,8 @@ begin
complete -c perl -s i -n $noopt -x --description 'Edit files in-place'
complete -c perl -s I -n $noopt -r --description 'Include path'
complete -c perl -s l -n $noopt --description 'Automatic line ending processing'
- complete -c perl -s m -n $noopt -x --description 'Require module'
- complete -c perl -s M -n $noopt -x --description 'Use module'
+ complete -c perl -s m -n $noopt -x --description 'Require module' -a $modules
+ complete -c perl -s M -n $noopt -x --description 'Use module' -a $modules
complete -c perl -s n -n $noopt --description 'Loop script'
complete -c perl -s p -n $noopt --description 'Loop script, print $_'
complete -c perl -s s -n $noopt --description 'Define custom switches'
diff --git a/share/completions/psql.fish b/share/completions/psql.fish
new file mode 100644
index 00000000..5b67a33d
--- /dev/null
+++ b/share/completions/psql.fish
@@ -0,0 +1,66 @@
+
+function __fish_complete_pg_database
+ psql -AtqwlF \t ^/dev/null | awk 'NF > 1 { print $1 }'
+end
+
+function __fish_complete_pg_user
+ psql -Atqwc 'select usename from pg_user' template1 ^/dev/null
+end
+
+complete -c psql --no-files -a '(__fish_complete_pg_database)'
+
+
+#
+# General options:
+#
+
+complete -c psql -s d -l dbname -a '(__fish_complete_pg_database)' --description "database name to connect to"
+complete -c psql -s c -l command --description "run only single command (SQL or internal) and exit"
+complete -c psql -s f -l file -r --description "execute commands from file, then exit"
+complete -c psql -s l -l list --description "list available databases, then exit"
+
+# complete -c psql -s v -l set=, --variable=NAME=VALUE
+# set psql variable NAME to VALUE
+
+complete -c psql -s X -l no-psqlrc --description "do not read startup file (~/.psqlrc)"
+complete -c psql -s 1 -l single-transaction --description "execute command file as a single transaction"
+complete -c psql -l help --description "show this help, then exit"
+complete -c psql -l version --description "output version information, then exit"
+
+#
+# Input and output options:
+#
+
+complete -c psql -s a, -l echo-all --description "echo all input from script"
+complete -c psql -s e, -l echo-queries --description "echo commands sent to server"
+complete -c psql -s E, -l echo-hidden --description "display queries that internal commands generate"
+complete -c psql -s L, -l log-file --description "send session log to file"
+complete -c psql -s n, -l no-readline --description "disable enhanced command line editing (readline)"
+complete -c psql -s o, -l output --description "send query results to file (or |pipe)"
+complete -c psql -s q, -l quiet --description "run quietly (no messages, only query output)"
+complete -c psql -s s, -l single-step --description "single-step mode (confirm each query)"
+complete -c psql -s S, -l single-line --description "single-line mode (end of line terminates SQL command)"
+
+#
+# Output format options:
+#
+
+complete -c psql -s A, -l no-align --description "unaligned table output mode"
+complete -c psql -s H, -l html --description "HTML table output mode"
+complete -c psql -s P, -l pset --description "set printing option VAR to ARG (see \pset command)"
+complete -c psql -s t, -l tuples-only --description "print rows only"
+complete -c psql -s T, -l table-attr --description "set HTML table tag attributes (e.g., width, border)"
+complete -c psql -s x, -l expanded --description "turn on expanded table output"
+complete -c psql -s F, -l field-separator --description "set field separator (default: '|')"
+complete -c psql -s R, -l record-separator --description "set record separator (default: newline)"
+
+
+#
+# Connection options
+#
+
+complete -c psql -s h -l host -a '(__fish_print_hostnames)' --description "database server host or socket directory"
+complete -c psql -s p -l port -x --description "database server port"
+complete -c psql -s U -l username -a '(__fish_complete_pg_user)' --description "database user name"
+complete -c psql -s w -l no-password --description "never prompt for password"
+complete -c psql -s W -l password --description "force password prompt (should happen automatically)"
diff --git a/share/completions/rsync.fish b/share/completions/rsync.fish
index 5a758175..f749aaa5 100644
--- a/share/completions/rsync.fish
+++ b/share/completions/rsync.fish
@@ -105,6 +105,22 @@ complete -c rsync -l version --description "Display version and exit"
complete -c rsync -l help --description "Display help and exit"
#
+# Hostname completion
+#
+complete -c rsync -d Hostname -a "
+
+(__fish_print_hostnames):
+
+(
+ #Prepend any username specified in the completion to the hostname
+ commandline -ct |sed -ne 's/\(.*@\).*/\1/p'
+)(__fish_print_hostnames):
+
+(__fish_print_users)@\tUsername
+
+"
+
+#
# Remote path
#
complete -c rsync -d "Remote path" -n "commandline -ct|sgrep -q :" -a "
diff --git a/share/completions/scp.fish b/share/completions/scp.fish
index 104cf521..f7e131f5 100644
--- a/share/completions/scp.fish
+++ b/share/completions/scp.fish
@@ -10,17 +10,12 @@ __fish_complete_ssh scp
complete -c scp -d Hostname -a "
-(
- #Find a suitable hostname from the knownhosts files
- cat ~/.ssh/known_hosts{,2} ^/dev/null|cut -d ' ' -f 1| cut -d , -f 1
-):
+(__fish_print_hostnames):
(
#Prepend any username specified in the completion to the hostname
commandline -ct |sed -ne 's/\(.*@\).*/\1/p'
-)(
- cat ~/.ssh/known_hosts{,2} ^/dev/null|cut -d ' ' -f 1| cut -d , -f 1
-):
+)(__fish_print_hostnames):
(__fish_print_users)@\tUsername
diff --git a/share/completions/useradd.fish b/share/completions/useradd.fish
index 3d12d51a..dec568c8 100644
--- a/share/completions/useradd.fish
+++ b/share/completions/useradd.fish
@@ -9,14 +9,14 @@ complete -c useradd -s c -l comment --description 'A comment about this user' -r
complete -c useradd -s d -l home --description 'Home directory for the new user' -x -a '(__fish_complete_directories)'
complete -c useradd -s G -l groups --description 'Supplementary groups' -xa '(__fish_append , (cat /etc/group|cut -d : -f 1))'
complete -c useradd -s h -l help --description 'Display help message and exit'
-complete -c useradd -s m -l create-home --description 'The user's home directory will be created if it does not exist'
+complete -c useradd -s m -l create-home --description 'The user\'s home directory will be created if it does not exist'
complete -c useradd -s n --description 'A group having the same name as the user being added to the system will be created by default (when -g is not specified)'
complete -c useradd -s K -l key --description 'Overrides default key/value pairs from /etc/login'
complete -c useradd -s o -l non-unique --description 'Allow the creation of a user account with a duplicate (non-unique) UID'
complete -c useradd -s p -l password --description 'The encrypted password, as returned by crypt(3)' -r
-complete -c useradd -s u -l uid --description 'The numerical value of the user's ID' -r
-complete -c useradd -s b -l base-dir --description 'The initial path prefix for a new user's home directory' -r -a '(__fish_complete_directories)'
+complete -c useradd -s u -l uid --description 'The numerical value of the user\'s ID' -r
+complete -c useradd -s b -l base-dir --description 'The initial path prefix for a new user\'s home directory' -r -a '(__fish_complete_directories)'
complete -c useradd -s e -l expiredate --description 'The date on which the user account is disabled' -r
complete -c useradd -s f -l inactive --description 'The number of days after a password has expired before the account will be disabled' -r
-complete -c useradd -s g -l gid --description 'The group name or ID for a new user's initial group' -x -a '(cat /etc/group|cut -d : -f 1,3|sed -e "s/:/\n/")'
-complete -c useradd -s s -l shell --description 'Name of the new user's login shell' -x -a '(cat /etc/shells)'
+complete -c useradd -s g -l gid --description 'The group name or ID for a new user\'s initial group' -x -a '(cat /etc/group|cut -d : -f 1,3|sed -e "s/:/\n/")'
+complete -c useradd -s s -l shell --description 'Name of the new user\'s login shell' -x -a '(cat /etc/shells)'
diff --git a/share/completions/vim-addons.fish b/share/completions/vim-addons.fish
new file mode 100644
index 00000000..67d5f48c
--- /dev/null
+++ b/share/completions/vim-addons.fish
@@ -0,0 +1,54 @@
+
+# Completion for vim-addons
+# =========================
+#
+# Adrien Grellier <adrien.grellier@laposte.net>
+#
+
+function __fish_vim-addons_subcommand --description 'Test if vim-addons has yet to be given the subcommand'
+ for i in (commandline -opc)
+ if contains -- $i list status install remove disable amend files show
+ return 1
+ end
+ end
+ return 0
+end
+
+# Commands
+# --------
+# list
+complete -c vim-addons -n "__fish_vim-addons_subcommand" -a "list" -f -d "list the names of the addons available in the system"
+# status
+complete -c vim-addons -n "__fish_vim-addons_subcommand" -a "status" -f -d "show the status of the addons available in the system"
+complete -c vim-addons -n "contains status (commandline -poc)" -a "(vim-addons list)" -x
+# install
+complete -c vim-addons -n "__fish_vim-addons_subcommand" -a "install" -x -d "install one or more addons under ~/.vim"
+complete -c vim-addons -n "contains install (commandline -poc)" -a "(vim-addons status | awk '\$2 != \"installed\" && \$1 != \"#\" { print \$1}')" -x
+# remove
+complete -c vim-addons -n "__fish_vim-addons_subcommand" -a "remove" -x -d "remove one or more addons from ~/.vim"
+complete -c vim-addons -n "contains remove (commandline -poc)" -a "(vim-addons status | awk '\$2 != \"removed\" && \$1 != \"#\" { print \$1}')" -x
+# disable
+complete -c vim-addons -n "__fish_vim-addons_subcommand" -a "disable" -x -d "disable one or more addons to be used by the current user"
+complete -c vim-addons -n "contains disable (commandline -poc)" -a "(vim-addons status | awk '\$2 != \"disable\" && \$1 != \"#\" { print \$1}')" -x
+# amend
+complete -c vim-addons -n "__fish_vim-addons_subcommand" -a "amend" -x -d "undo the effects of a previous disable command"
+complete -c vim-addons -n "contains amend (commandline -poc)" -a "(vim-addons list)" -x
+# files
+complete -c vim-addons -n "__fish_vim-addons_subcommand" -a "files" -x -d "list, one per line, the files composing the specified addons"
+complete -c vim-addons -n "contains files (commandline -poc)" -a "(vim-addons list)" -x
+# show
+complete -c vim-addons -n "__fish_vim-addons_subcommand" -a "show" -x -d "displays detailed information about the specified addons"
+complete -c vim-addons -n "contains show (commandline -poc)" -a "(vim-addons list)" -x
+
+
+# Options
+# --------
+complete -c vim-addons -s h -l help -d "show this usage message and exit"
+complete -c vim-addons -s q -l query -d "be quiet and make the output more parseable"
+complete -c vim-addons -s r -l registry-dir -d "set the registry directory"
+complete -c vim-addons -s s -l source-dir -d "set the addons source directory"
+complete -c vim-addons -s t -l target-dir -d "set the addons target directory"
+complete -c vim-addons -s v -l verbose -d "increase verbosity"
+complete -c vim-addons -s y -l system-dir -d "set the system-wide target directory"
+complete -c vim-addons -s w -l system-wide -d "set target directory to the system-wide one"
+
diff --git a/share/config.fish b/share/config.fish
index 056fd34f..6b62a01c 100644
--- a/share/config.fish
+++ b/share/config.fish
@@ -57,41 +57,47 @@ if test -d /usr/xpg4/bin
end
end
-# Add a handler for when fish_user_path changes, so we can apply the same changes to PATH
-# Invoke it immediately to apply the current value of fish_user_path
-function __fish_reconstruct_path -d "Update PATH when fish_user_paths changes" --on-variable fish_user_paths
- set -l local_path $PATH
- set -l x
- for x in $__fish_added_user_paths
- if set -l idx (contains --index $x $local_path)
- set -e local_path[$idx]
- end
- end
-
- set -e __fish_added_user_paths
- for x in $fish_user_paths[-1..1]
- if not contains $x $local_path
- set local_path $x $local_path
- set -g __fish_added_user_paths $__fish_added_user_paths $x
- end
- end
- set -xg PATH $local_path
-end
-__fish_reconstruct_path
-
# OS X-ism: Load the path files out of /etc/paths and /etc/paths.d/*
+set -g __fish_tmp_path $PATH
function __fish_load_path_helper_paths
+ # We want to rearrange the path to reflect this order. Delete that path component if it exists and then prepend it.
+ # Since we are prepending but want to preserve the order of the input file, we reverse the array, append, and then reverse it again
+ set __fish_tmp_path $__fish_tmp_path[-1..1]
while read -l new_path_comp
- if not contains $new_path_comp $PATH
- set PATH $PATH $new_path_comp
- end
+ set -l where (contains -i $new_path_comp $__fish_tmp_path)
+ and set -e __fish_tmp_path[$where]
+ set __fish_tmp_path $new_path_comp $__fish_tmp_path
end
+ set __fish_tmp_path $__fish_tmp_path[-1..1]
end
-if test -r /etc/paths ; __fish_load_path_helper_paths < /etc/paths ; end
+test -r /etc/paths ; and __fish_load_path_helper_paths < /etc/paths
for pathfile in /etc/paths.d/* ; __fish_load_path_helper_paths < $pathfile ; end
+set -xg PATH $__fish_tmp_path
+set -e __fish_tmp_path
functions -e __fish_load_path_helper_paths
+# Add a handler for when fish_user_path changes, so we can apply the same changes to PATH
+# Invoke it immediately to apply the current value of fish_user_path
+function __fish_reconstruct_path -d "Update PATH when fish_user_paths changes" --on-variable fish_user_paths
+ set -l local_path $PATH
+ set -l x
+ for x in $__fish_added_user_paths
+ set -l idx (contains --index $x $local_path)
+ and set -e local_path[$idx]
+ end
+
+ set -e __fish_added_user_paths
+ for x in $fish_user_paths[-1..1]
+ if not contains $x $local_path
+ set local_path $x $local_path
+ set -g __fish_added_user_paths $__fish_added_user_paths $x
+ end
+ end
+ set -xg PATH $local_path
+end
+__fish_reconstruct_path
+
#
# Launch debugger on SIGTRAP
#
@@ -109,3 +115,16 @@ function __fish_on_interactive --on-event fish_prompt
functions -e __fish_on_interactive
end
+# "." command for compatibility with old fish versions.
+function . --description 'Evaluate contents of file (deprecated, see "source")' --no-scope-shadowing
+ if begin
+ test (count $argv) -eq 0
+ # Uses tty directly, as isatty depends on "."
+ and tty 0>&0 >/dev/null
+ end
+ echo "source: '.' command is deprecated, and doesn't work with STDIN anymore. Did you mean 'source' or './'?" >&2
+ return 1
+ else
+ source $argv
+ end
+end
diff --git a/share/functions/__fish_complete_ls.fish b/share/functions/__fish_complete_ls.fish
index 652a02d3..1fe39659 100644
--- a/share/functions/__fish_complete_ls.fish
+++ b/share/functions/__fish_complete_ls.fish
@@ -4,7 +4,7 @@
# Test if we are using GNU ls
-function __fish_complete_ls -d "Compleletions for ls and its aliases"
+function __fish_complete_ls -d "Completions for ls and its aliases"
set -l is_gnu
command ls --version >/dev/null ^/dev/null; and set is_gnu --is-gnu
diff --git a/share/functions/__fish_config_interactive.fish b/share/functions/__fish_config_interactive.fish
index d7961861..d9ee0700 100644
--- a/share/functions/__fish_config_interactive.fish
+++ b/share/functions/__fish_config_interactive.fish
@@ -213,28 +213,37 @@ function __fish_config_interactive -d "Initializations that should be performed
commandline -f repaint
end
+
+ # Notify vte-based terminals when $PWD changes (issue #906)
+ if test "$VTE_VERSION" -ge 3405
+ function __update_vte_cwd --on-variable PWD --description 'Notify VTE of change to $PWD'
+ status --is-command-substitution; and return
+ printf '\033]7;file://%s\a' (pwd | __fish_urlencode)
+ end
+ end
+
# The first time a command is not found, look for command-not-found
# This is not cheap so we try to avoid doing it during startup
- function fish_command_not_found_setup --on-event fish_command_not_found
+ function __fish_command_not_found_setup --on-event fish_command_not_found
# Remove fish_command_not_found_setup so we only execute this once
- functions --erase fish_command_not_found_setup
+ functions --erase __fish_command_not_found_setup
# First check in /usr/lib, this is where modern Ubuntus place this command
if test -f /usr/lib/command-not-found
- function fish_command_not_found_handler --on-event fish_command_not_found
- /usr/lib/command-not-found $argv
+ function __fish_command_not_found_handler --on-event fish_command_not_found
+ /usr/lib/command-not-found -- $argv
end
# Ubuntu Feisty places this command in the regular path instead
else if type -p command-not-found > /dev/null 2> /dev/null
- function fish_command_not_found_handler --on-event fish_command_not_found
- command-not-found $argv
+ function __fish_command_not_found_handler --on-event fish_command_not_found
+ command-not-found -- $argv
end
# Use standard fish command not found handler otherwise
else
- function fish_command_not_found_handler --on-event fish_command_not_found
+ function __fish_command_not_found_handler --on-event fish_command_not_found
echo fish: Unknown command "'$argv'" >&2
end
end
- fish_command_not_found_handler $argv
+ __fish_command_not_found_handler $argv
end
end
diff --git a/share/functions/__fish_git_prompt.fish b/share/functions/__fish_git_prompt.fish
index ea4df57a..4ca32c6e 100644
--- a/share/functions/__fish_git_prompt.fish
+++ b/share/functions/__fish_git_prompt.fish
@@ -1,13 +1,14 @@
-# based off of the git-completion script that ships with git
+# based off of the git-prompt script that ships with git
#
# Written by Kevin Ballard <kevin@sb.org>
+# Updated by Brian Gernhardt <brian@gernhardtsoftware.com>
#
-# This is heavily based off of the git-completion.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>.
# The act of porting the code, along with any new code, are Copyright (C) 2012
# Kevin Ballard <kevin@sb.org>.
#
-# By virtue of being based on the git-completion.bash script, this script is
+# By virtue of being based on the git-prompt.bash script, this script is
# distributed under the GNU General Public License, version 2.0.
#
# This script vends a function __fish_git_prompt which takes a format string,
@@ -15,18 +16,15 @@
# function.
#
# The behavior of __fish_git_prompt is very heavily based off of the bash
-# script's __fish_git_prompt function. As such, usage and customization is very
-# similar, although some extra flexibility is provided in this script.
+# script's __git_ps1 function. As such, usage and customization is very
+# similar, although some extra features are provided in this script.
+# Due to differences between bash and fish, the PROMPT_COMMAND style where
+# passing two or three arguments causes the fucnction to set PS1 is not
+# supported. More information on the additional features is found after the
+# bash-compatable documentation.
#
# The argument to __fish_git_prompt will be displayed only if you are currently
-# in a git repository. The %s token will be the name of the branch. If HEAD is
-# not a branch, it attempts to show the relevant tag. The tag search is
-# controlled by the __fish_git_prompt_describe_style variable, with the
-# following values:
-# default (or unset) Any tag that exactly matches HEAD
-# contains Nearest annotated tag that contains HEAD
-# branch Nearest tag/branch that contains HEAD
-# describe Output of `git describe`
+# in a git repository. The %s token will be the name of the branch.
#
# In addition, if you set __fish_git_prompt_showdirtystate to a nonempty value,
# unstaged (*) and staged (+) changes will be shown next to the branch name.
@@ -41,81 +39,191 @@
#
# If you would like to see if there are untracked files, then you can set
# __fish_git_prompt_showuntrackedfiles to a nonempty value. If there are
-# untracked files, then a '%' will be shown next to the branch name.
+# untracked files, then a '%' will be shown next to the branch name. Once you
+# have set __fish_git_prompt_showuntrackedfiles, you can override it on a
+# per-repository basis by setting the bash.showUntrackedFiles config variable.
+# As before, this variable remains named 'bash' to preserve compatibility.
#
# If you would like to see the difference between HEAD and its upstream, set
# __fish_git_prompt_showupstream to 'auto'. A "<" indicates you are behind, ">"
-# indicates you are ahead, and "<>" indicates you have diverged. You can
-# further control behavior by setting __fish_git_prompt_showupstream to a
-# space-separated list of values:
-# verbose show number of commits head/behind (+/-) upstream
+# indicates you are ahead, "<>" indicates you have diverged and "=" indicates
+# that there is no difference. You can further control behavior by setting
+# __fish_git_prompt_showupstream to a space-separated list of values:
+#
+# verbose show number of commits ahead/behind (+/-) upstream
+# 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
# git always compare HEAD to @{upstream}
# svn always compare HEAD to your SVN upstream
+# none disables (fish only, useful with show_informative_status)
+#
# By default, __fish_git_prompt will compare HEAD to your SVN upstream if it
# can find one, or @{upstream} otherwise. Once you have set
# __fish_git_prompt_showupstream, you can override it on a per-repository basis
# by setting the bash.showUpstream config variable. As before, this variable
# remains named 'bash' to preserve compatibility.
#
-# This fish-compatible version of __fish_git_prompt includes some additional
-# features on top of the above-documented bash-compatible features:
+# If you would like to see more information about the identity of commits
+# checked out as a detached HEAD, set __fish_git_prompt_describe_style to
+# one of the following values:
#
-# The color for the branch name and each individual optional component can be
-# specified using __fish_git_prompt_color_<name>, where <name> is 'prefix',
-# 'suffix', 'bare', 'merging', 'branch', 'dirtystate', 'stagedstate',
-# 'invalidstate', 'stashstate', 'untrackedfiles', and 'upstream'. The variable
-# __fish_git_prompt_color is used for any component that does not have an
-# individual color set. Colors are specified as arguments to `set_color`.
+# contains relative to newer annotated tag (v1.6.3.2~35)
+# branch relative to newer tag or branch (master~4)
+# describe relative to older annotated tag (v1.6.3.1-13-gdd42c2f)
+# default exactly matching tag
#
-# The characters used for the optional features can be configured using
-# __fish_git_prompt_char_<token>, where <token> is one of 'dirtystate',
-# 'stagedstate', 'invalidstate', 'stashstate', 'untrackedfiles',
-# 'upstream_equal', 'upstream_behind', 'upstream_ahead', and
-# 'upstream_diverged'.
+# If you would like a colored hint about the current dirty state, set
+# __fish_git_prompt_showcolorhints to a nonempty value. The default colors are
+# based on the colored output of "git status -sb"
-set -g ___fish_git_prompt_status_order stagedstate invalidstate dirtystate untrackedfiles
+
+# __fish_git_prompt includes some additional features on top of the
+# above-documented bash-compatible features:
+#
+#
+# An "informative git prompt" mode similar to the scripts for bash and zsh
+# can be activated by setting __fish_git_prompt_show_informative_status
+# This works more like the "informative git prompt" scripts for bash and zsh,
+# giving prompts like (master↑1↓2|●3✖4✚5…6) where master is the current branch,
+# you have 1 commit your upstream doesn't and it has 2 you don't, and you have
+# 3 staged, 4 unmerged, 5 dirty, and 6 untracked files. If you have no
+# changes, it displays (master|✔).
+#
+# Setting __fish_git_prompt_show_informative_status changes several defaults.
+# The default mode for __fish_git_prompt_showupstream changes to informative
+# and the following characters have their defaults changed. (The characters
+# and colors can still be customized as described below.)
+#
+# upstream_prefix ()
+# upstream_ahead (↑)
+# upstream_behind (↓)
+# stateseparator (|)
+# dirtystate (✚)
+# invalidstate (✖)
+# stagedstate (●)
+# untrackedfiles (…)
+# cleanstate (✔)
+#
+#
+# The color for each component of the prompt can specified using
+# __fish_git_prompt_color_<name>, where <name> is one of the following and the
+# values are specified as arguments to `set_color`. The variable
+# __fish_git_prompt_color is used for any component that does not have an
+# individual color set.
+#
+# prefix Anything before %s in the format string
+# suffix Anything after %s in the format string
+# bare Marker for a bare repository
+# merging Current operation (|MERGING, |REBASE, etc.)
+# branch Branch name
+# flags Optional flags (see below)
+# upstream Upstream name and flags (with showupstream)
+#
+#
+# The following optional flags have both colors, as above, and custom
+# characters via __fish_git_prompt_char_<name>. The default character is
+# shown in parenthesis. The default color for these flags can be also be set
+# via the __fish_git_prompt_color_flags variable.
+#
+# __fish_git_prompt_showdirtystate
+# dirtystate unstaged changes (*)
+# stagedstate staged changes (+)
+# invalidstate HEAD invalid (#, colored as stagedstate)
+#
+# __fish_git_prompt_showstashstate
+# stashstate stashed changes ($)
+#
+# __fish_git_prompt_showuntrackedfiles
+# untrackedfiles untracked files (%)
+#
+# __fish_git_prompt_showupstream (all colored as upstream)
+# upstream_equal Branch matches upstream (=)
+# upstream_behind Upstream has more commits (<)
+# upstream_ahead Branch has more commits (>)
+# upstream_diverged Upstream and branch have new commits (<>)
+#
+# __fish_git_prompt_show_informative_status
+# (see also the flags for showdirtystate and showuntrackedfiles, above)
+# cleanstate Working directory has no changes (✔)
+#
+#
+# The separator between the branch name and flags can also be customized via
+# __fish_git_prompt_char_stateseparator. It can only be colored by
+# __fish_git_prompt_color. It normally defaults to a space ( ) and defaults
+# to a vertical bar (|) when __fish_git_prompt_show_informative_status is set.
+#
+# 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 ().
+#
+#
+# Turning on __fish_git_prompt_showcolorhints changes the colors as follows to
+# more closely match the behavior in bash. Note that setting any of these
+# colors manually will override these defaults.
+#
+# branch Defaults to green
+# branch_detached New color, when head is detached, default red
+# dirtystate Defaults to red
+# stagedstate Defaults to green
+# flags Defaults to --bold blue
function __fish_git_prompt_show_upstream --description "Helper function for __fish_git_prompt"
- # Ask git-config for some config options
- set -l svn_remote
- set -l svn_prefix
+ set -l show_upstream $__fish_git_prompt_showupstream
+ set -l svn_prefix # For better SVN upstream information
+ set -l informative
+
+ set -l svn_url_pattern
+ set -l count
set -l upstream git
set -l legacy
set -l verbose
- set -l informative
- set -l svn_url_pattern
- set -l show_upstream $__fish_git_prompt_showupstream
- git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showUpstream)$' ^/dev/null | tr '\0\n' '\n ' | while read -l key value
+
+ # Default to informative if show_informative_status is set
+ if test -n "$__fish_git_prompt_show_informative_status"
+ set informative 1
+ end
+
+ set -l svn_remote
+ # get some config options from git-config
+ command git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' ^/dev/null | tr '\0\n' '\n ' | while read -l key value
switch $key
- case bash.showUpstream bash.showupstream
+ case bash.showupstream
set show_upstream $value
test -n "$show_upstream"; or return
case svn-remote.'*'.url
set svn_remote $svn_remote $value
- set -l remote_prefix (/bin/sh -c 'echo "${1%.url}"' -- $key)
- set svn_prefix $svn_prefix $remote_prefix
+ # Avoid adding \| to the beginning to avoid needing #?? later
if test -n "$svn_url_pattern"
- set svn_url_pattern $svn_url_pattern"\|$value"
+ set svn_url_pattern $svn_url_pattern"\\|$value"
else
set svn_url_pattern $value
end
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 svn_prefix $svn_prefix $remote_prefix
end
end
# parse configuration variables
+ # and clear informative default when needed
for option in $show_upstream
switch $option
case git svn
set upstream $option
+ set -e informative
case verbose
set verbose 1
+ set -e informative
case informative
set informative 1
case legacy
set legacy 1
+ set -e informative
+ case none
+ return
end
end
@@ -151,26 +259,27 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
end
else
set upstream (/bin/sh -c 'val=${1#/branches}; echo "${val#/}"' -- $svn_upstream)
- set -l fetch_val (git config "$cur_prefix".fetch)
+
+ # 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
end
end
- else if test $upstream = svn+git
+ else if test $upstream = svn+git
set upstream '@{upstream}'
end
end
# Find how many commits we are ahead/behind our upstream
- set -l count
if test -z "$legacy"
- set count (git rev-list --count --left-right $upstream...HEAD ^/dev/null)
+ set count (command git rev-list --count --left-right $upstream...HEAD ^/dev/null)
else
# produce equivalent output to --count for older versions of git
set -l os
- set -l commits (git rev-list --left-right $upstream...HEAD ^/dev/null; set os $status)
+ set -l commits (command git rev-list --left-right $upstream...HEAD ^/dev/null; set os $status)
if test $os -eq 0
set -l behind (count (for arg in $commits; echo $arg; end | grep '^<'))
set -l ahead (count (for arg in $commits; echo $arg; end | grep -v '^<'))
@@ -194,7 +303,7 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
case '*' # diverged from upstream
echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_diverged$ahead-$behind"
end
- else if test -n informative
+ else if test -n "$informative"
echo $count | read -l behind ahead
switch "$count"
case '' # no upstream
@@ -222,54 +331,74 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi
end
function __fish_git_prompt --description "Prompt function for Git"
- set -l git_dir (__fish_git_prompt_git_dir)
- test -n "$git_dir"; or return
+ set -l repo_info (command git rev-parse --git-dir --is-inside-git-dir --is-bare-repository --is-inside-work-tree --short HEAD ^/dev/null)
+ test -n "$repo_info"; or return
+
+ set -l git_dir $repo_info[1]
+ set -l inside_gitdir $repo_info[2]
+ set -l bare_repo $repo_info[3]
+ set -l inside_worktree $repo_info[4]
+ set -l short_sha
+ if test (count $repo_info) = 5
+ set short_sha $repo_info[5]
+ end
- set -l r (__fish_git_prompt_current_operation $git_dir)
- set -l b (__fish_git_prompt_current_branch $git_dir)
+ set -l rbc (__fish_git_prompt_operation_branch_bare $repo_info)
+ set -l r $rbc[1] # current operation
+ set -l b $rbc[2] # current branch
+ set -l detached $rbc[3]
set -l w #dirty working directory
set -l i #staged changes
set -l s #stashes
set -l u #untracked
- set -l c (__fish_git_prompt_current_branch_bare)
+ set -l c $rbc[4] # bare repository
set -l p #upstream
set -l informative_status
__fish_git_prompt_validate_chars
- if test "true" = (git rev-parse --is-inside-work-tree ^/dev/null)
-
+ if test "true" = $inside_worktree
if test -n "$__fish_git_prompt_show_informative_status"
- set informative_status "|"(__fish_git_prompt_informative_status)
+ set informative_status "$___fish_git_prompt_char_stateseparator"(__fish_git_prompt_informative_status)
else
if test -n "$__fish_git_prompt_showdirtystate"
- set -l config (git config --bool bash.showDirtyState)
+ set -l config (command git config --bool bash.showDirtyState)
if test "$config" != "false"
set w (__fish_git_prompt_dirty)
- set i (__fish_git_prompt_staged)
+ set i (__fish_git_prompt_staged $short_sha)
end
end
- if test -n "$__fish_git_prompt_showstashstate"
- git rev-parse --verify refs/stash >/dev/null ^&1; and set s $___fish_git_prompt_char_stashstate
+ if test -n "$__fish_git_prompt_showstashstate" -a -r $git_dir/refs/stash
+ set s $___fish_git_prompt_char_stashstate
end
if test -n "$__fish_git_prompt_showuntrackedfiles"
- set -l files (git ls-files --others --exclude-standard)
- if test -n "$files"
- set u $___fish_git_prompt_char_untrackedfiles
+ set -l config (command git config --bool bash.showUntrackedFiles)
+ if test "$config" != false
+ if command git ls-files --others --exclude-standard --error-unmatch -- '*' >/dev/null ^/dev/null
+ set u $___fish_git_prompt_char_untrackedfiles
+ end
end
end
end
- if test -n "$__fish_git_prompt_showupstream"
+ if test -n "$__fish_git_prompt_showupstream" -o "$__fish_git_prompt_show_informative_status"
set p (__fish_git_prompt_show_upstream)
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"
+ if test $detached = yes
+ set branch_color $___fish_git_prompt_color_branch_detached
+ set branch_done $___fish_git_prompt_color_branch_detached_done
+ end
+ end
+
if test -n "$w"
set w "$___fish_git_prompt_color_dirtystate$w$___fish_git_prompt_color_dirtystate_done"
end
@@ -284,7 +413,7 @@ function __fish_git_prompt --description "Prompt function for Git"
end
set b (/bin/sh -c 'echo "${1#refs/heads/}"' -- $b)
if test -n "$b"
- set b "$___fish_git_prompt_color_branch$b$___fish_git_prompt_color_branch_done"
+ set b "$branch_color$b$branch_done"
end
if test -n "$c"
set c "$___fish_git_prompt_color_bare$c$___fish_git_prompt_color_bare_done"
@@ -297,9 +426,10 @@ function __fish_git_prompt --description "Prompt function for Git"
end
# Formatting
+ set -l space "$___fish_git_prompt_color$___fish_git_prompt_char_stateseparator$___fish_git_prompt_color_done"
set -l f "$w$i$s$u"
if test -n "$f"
- set f " $f"
+ set f "$space$f"
end
set -l format $argv[1]
if test -z "$format"
@@ -312,10 +442,12 @@ end
### helper functions
function __fish_git_prompt_staged --description "__fish_git_prompt helper, tells whether or not the current branch has staged files"
+ set -l short_sha $argv[1]
+
set -l staged
- if git rev-parse --quiet --verify HEAD >/dev/null
- git diff-index --cached --quiet HEAD --; or set staged $___fish_git_prompt_char_stagedstate
+ if test -n "$short_sha"
+ command git diff-index --cached --quiet HEAD --; or set staged $___fish_git_prompt_char_stagedstate
else
set staged $___fish_git_prompt_char_invalidstate
end
@@ -326,7 +458,7 @@ function __fish_git_prompt_dirty --description "__fish_git_prompt helper, tells
set -l dirty
set -l os
- git diff --no-ext-diff --quiet --exit-code
+ command git diff --no-ext-diff --quiet --exit-code
set os $status
if test $os -ne 0
set dirty $___fish_git_prompt_char_dirtystate
@@ -334,15 +466,17 @@ function __fish_git_prompt_dirty --description "__fish_git_prompt helper, tells
echo $dirty
end
+set -g ___fish_git_prompt_status_order stagedstate invalidstate dirtystate untrackedfiles
+
function __fish_git_prompt_informative_status
- set -l changedFiles (git diff --name-status | cut -c 1-2)
- set -l stagedFiles (git diff --staged --name-status | cut -c 1-2)
+ set -l changedFiles (command git diff --name-status | cut -c 1-2)
+ set -l stagedFiles (command git diff --staged --name-status | cut -c 1-2)
set -l dirtystate (math (count $changedFiles) - (count (echo $changedFiles | grep "U")))
set -l invalidstate (count (echo $stagedFiles | grep "U"))
set -l stagedstate (math (count $stagedFiles) - $invalidstate)
- set -l untrackedfiles (count (git ls-files --others --exclude-standard))
+ set -l untrackedfiles (count (command git ls-files --others --exclude-standard))
set -l info
@@ -352,7 +486,7 @@ function __fish_git_prompt_informative_status
for i in $___fish_git_prompt_status_order
if [ $$i != "0" ]
set -l color_var ___fish_git_prompt_color_$i
- set -l color_done_var ___fish_git_prompt_color_$i
+ set -l color_done_var ___fish_git_prompt_color_{$i}_done
set -l symbol_var ___fish_git_prompt_char_$i
set -l color $$color_var
@@ -374,63 +508,40 @@ function __fish_git_prompt_informative_status
end
-function __fish_git_prompt_current_branch_bare --description "__fish_git_prompt helper, tells wheter or not the current branch is bare"
- set -l bare
-
- if test "true" = (git rev-parse --is-inside-git-dir ^/dev/null)
- if test "true" = (git rev-parse --is-bare-repository ^/dev/null)
- set bare "BARE:"
- end
+# Keeping these together avoids many duplicated checks
+function __fish_git_prompt_operation_branch_bare --description "__fish_git_prompt helper, returns the current Git operation and branch"
+ # This function is passed the full repo_info array
+ set -l git_dir $argv[1]
+ set -l inside_gitdir $argv[2]
+ set -l bare_repo $argv[3]
+ set -l short_sha
+ if test (count $argv) = 5
+ set short_sha $argv[5]
end
- echo $bare
-end
-function __fish_git_prompt_current_branch --description "__fish_git_prompt helper, returns the current Git branch"
- set -l git_dir $argv[1]
set -l branch
-
+ set -l operation
+ set -l detached no
+ set -l bare
+ set -l step
+ set -l total
set -l os
- set branch (git symbolic-ref HEAD ^/dev/null; set os $status)
- if test $os -ne 0
- set branch (switch "$__fish_git_prompt_describe_style"
- case contains
- git describe --contains HEAD
- case branch
- git describe --contains --all HEAD
- case describe
- git describe HEAD
- case default '*'
- git describe --tags --exact-match HEAD
- end ^/dev/null; set os $status)
- if test $os -ne 0
- set branch (cut -c1-7 $git_dir/HEAD ^/dev/null; set os $status)
- if test $os -ne 0
- set branch unknown
- end
- end
- set branch "($branch)"
- end
- # Let user know they're inside the git dir of a non-bare repo
- if test "true" = (git rev-parse --is-inside-git-dir ^/dev/null)
- if test "false" = (git rev-parse --is-bare-repository ^/dev/null)
- set branch "GIT_DIR!"
+ if test -d $git_dir/rebase-merge
+ set branch (cat $git_dir/rebase-merge/head-name ^/dev/null)
+ set step (cat $git_dir/rebase-merge/msgnum ^/dev/null)
+ set total (cat $git_dir/rebase-merge/end ^/dev/null)
+ if test -f $git_dir/rebase-merge/interactive
+ set operation "|REBASE-i"
+ else
+ set operation "|REBASE-m"
end
- end
- echo $branch
-end
-
-function __fish_git_prompt_current_operation --description "__fish_git_prompt helper, returns the current Git operation being performed"
- set -l operation
-
- set -l git_dir $argv[1]
- if test -f $git_dir/rebase-merge/interactive
- set operation "|REBASE-i"
- else if test -d $git_dir/rebase-merge
- set operation "|REBASE-m"
else
if test -d $git_dir/rebase-apply
+ set step (cat $git_dir/rebase-apply/next ^/dev/null)
+ set total (cat $git_dir/rebase-apply/last ^/dev/null)
if test -f $git_dir/rebase-apply/rebasing
+ set branch (cat $git_dir/rebase-apply/head-name ^/dev/null)
set operation "|REBASE"
else if test -f $git_dir/rebase-apply/applying
set operation "|AM"
@@ -441,15 +552,55 @@ function __fish_git_prompt_current_operation --description "__fish_git_prompt he
set operation "|MERGING"
else if test -f $git_dir/CHERRY_PICK_HEAD
set operation "|CHERRY-PICKING"
+ else if test -f $git_dir/REVERT_HEAD
+ set operation "|REVERTING"
else if test -f $git_dir/BISECT_LOG
set operation "|BISECTING"
end
end
- echo $operation
-end
-function __fish_git_prompt_git_dir --description "__fish_git_prompt helper, returns .git dir if any"
- echo (git rev-parse --git-dir ^/dev/null)
+ if test -n "$step" -a -n "$total"
+ set operation "$operation $step/$total"
+ end
+
+ if test -z "$branch"
+ set branch (command git symbolic-ref HEAD ^/dev/null; set os $status)
+ if test $os -ne 0
+ set detached yes
+ set branch (switch "$__fish_git_prompt_describe_style"
+ case contains
+ command git describe --contains HEAD
+ case branch
+ command git describe --contains --all HEAD
+ case describe
+ command git describe HEAD
+ case default '*'
+ command git describe --tags --exact-match HEAD
+ end ^/dev/null; set os $status)
+ if test $os -ne 0
+ if test -n "$short_sha"
+ set branch $short_sha...
+ else
+ set branch unknown
+ end
+ end
+ set branch "($branch)"
+ end
+ end
+
+ if test "true" = $inside_gitdir
+ if test "true" = $bare_repo
+ set bare "BARE:"
+ else
+ # Let user know they're inside the git dir of a non-bare repo
+ set branch "GIT_DIR!"
+ end
+ end
+
+ echo $operation
+ echo $branch
+ echo $detached
+ echo $bare
end
function __fish_git_prompt_set_char
@@ -457,28 +608,34 @@ function __fish_git_prompt_set_char
set -l char $argv[2]
set -l user_variable $$user_variable_name
+ if test (count $argv) -ge 3
+ if test -n "$__fish_git_prompt_show_informative_status"
+ set char $argv[3]
+ end
+ end
+
set -l variable _$user_variable_name
set -l variable_done "$variable"_done
if not set -q $variable
set -g $variable (set -q $user_variable_name; and echo $user_variable; or echo $char)
end
-
end
function __fish_git_prompt_validate_chars --description "__fish_git_prompt helper, checks char variables"
- __fish_git_prompt_set_char __fish_git_prompt_char_cleanstate '.'
- __fish_git_prompt_set_char __fish_git_prompt_char_dirtystate '*'
- __fish_git_prompt_set_char __fish_git_prompt_char_stagedstate '+'
- __fish_git_prompt_set_char __fish_git_prompt_char_invalidstate '#'
- __fish_git_prompt_set_char __fish_git_prompt_char_stashstate '$'
- __fish_git_prompt_set_char __fish_git_prompt_char_untrackedfiles '%'
- __fish_git_prompt_set_char __fish_git_prompt_char_upstream_equal '='
- __fish_git_prompt_set_char __fish_git_prompt_char_upstream_behind '<'
- __fish_git_prompt_set_char __fish_git_prompt_char_upstream_ahead '>'
- __fish_git_prompt_set_char __fish_git_prompt_char_upstream_diverged '<>'
- __fish_git_prompt_set_char __fish_git_prompt_char_upstream_prefix ' '
+ __fish_git_prompt_set_char __fish_git_prompt_char_cleanstate '✔'
+ __fish_git_prompt_set_char __fish_git_prompt_char_dirtystate '*' '✚'
+ __fish_git_prompt_set_char __fish_git_prompt_char_invalidstate '#' '✖'
+ __fish_git_prompt_set_char __fish_git_prompt_char_stagedstate '+' '●'
+ __fish_git_prompt_set_char __fish_git_prompt_char_stashstate '$'
+ __fish_git_prompt_set_char __fish_git_prompt_char_stateseparator ' ' '|'
+ __fish_git_prompt_set_char __fish_git_prompt_char_untrackedfiles '%' '…'
+ __fish_git_prompt_set_char __fish_git_prompt_char_upstream_ahead '>' '↑'
+ __fish_git_prompt_set_char __fish_git_prompt_char_upstream_behind '<' '↓'
+ __fish_git_prompt_set_char __fish_git_prompt_char_upstream_diverged '<>'
+ __fish_git_prompt_set_char __fish_git_prompt_char_upstream_equal '='
+ __fish_git_prompt_set_char __fish_git_prompt_char_upstream_prefix ''
end
@@ -487,6 +644,19 @@ function __fish_git_prompt_set_color
set -l user_variable $$user_variable_name
set -l user_variable_bright
+ set -l default default_done
+ switch (count $argv)
+ case 1 # No defaults given, use prompt color
+ set default $___fish_git_prompt_color
+ set default_done $___fish_git_prompt_color_done
+ case 2 # One default given, use normal for done
+ set default "$argv[2]"
+ set default_done (set_color normal)
+ case 3 # Both defaults given
+ set default "$argv[2]"
+ 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]
@@ -498,59 +668,86 @@ function __fish_git_prompt_set_color
if not set -q $variable
if test -n "$user_variable"
if test -n "$user_variable_bright"
- set -g $variable (set_color -o $user_variable)
+ set -g $variable (set_color --bold $user_variable)
else
set -g $variable (set_color $user_variable)
end
set -g $variable_done (set_color normal)
else
- set -g $variable ''
- set -g $variable_done ''
+ set -g $variable $default
+ set -g $variable_done $default_done
end
end
end
+
function __fish_git_prompt_validate_colors --description "__fish_git_prompt helper, checks color variables"
- __fish_git_prompt_set_color __fish_git_prompt_color
+ # Base color defaults to nothing (must be done first)
+ __fish_git_prompt_set_color __fish_git_prompt_color '' ''
+
+ # Normal colors
__fish_git_prompt_set_color __fish_git_prompt_color_prefix
__fish_git_prompt_set_color __fish_git_prompt_color_suffix
__fish_git_prompt_set_color __fish_git_prompt_color_bare
__fish_git_prompt_set_color __fish_git_prompt_color_merging
- __fish_git_prompt_set_color __fish_git_prompt_color_branch
__fish_git_prompt_set_color __fish_git_prompt_color_cleanstate
- __fish_git_prompt_set_color __fish_git_prompt_color_dirtystate
- __fish_git_prompt_set_color __fish_git_prompt_color_stagedstate
__fish_git_prompt_set_color __fish_git_prompt_color_invalidstate
- __fish_git_prompt_set_color __fish_git_prompt_color_stashstate
- __fish_git_prompt_set_color __fish_git_prompt_color_untrackedfiles
__fish_git_prompt_set_color __fish_git_prompt_color_upstream
+ # Colors with defaults with showcolorhints
+ if test -n "$__fish_git_prompt_showcolorhints"
+ __fish_git_prompt_set_color __fish_git_prompt_color_flags (set_color --bold blue)
+ __fish_git_prompt_set_color __fish_git_prompt_color_branch (set_color green)
+ __fish_git_prompt_set_color __fish_git_prompt_color_dirtystate (set_color red)
+ __fish_git_prompt_set_color __fish_git_prompt_color_stagedstate (set_color green)
+ else
+ __fish_git_prompt_set_color __fish_git_prompt_color_flags
+ __fish_git_prompt_set_color __fish_git_prompt_color_branch
+ __fish_git_prompt_set_color __fish_git_prompt_color_dirtystate $___fish_git_prompt_color_flags $___fish_git_prompt_color_flags_done
+ __fish_git_prompt_set_color __fish_git_prompt_color_stagedstate $___fish_git_prompt_color_flags $___fish_git_prompt_color_flags_done
+ end
+
+ # Branch_detached has a default, but is only used with showcolorhints
+ __fish_git_prompt_set_color __fish_git_prompt_color_branch_detached (set_color red)
+
+ # Colors that depend on flags color
+ __fish_git_prompt_set_color __fish_git_prompt_color_stashstate $___fish_git_prompt_color_flags $___fish_git_prompt_color_flags_done
+ __fish_git_prompt_set_color __fish_git_prompt_color_untrackedfiles $___fish_git_prompt_color_flags $___fish_git_prompt_color_flags_done
+
end
set -l varargs
-for var in repaint describe_style showdirtystate showstashstate showuntrackedfiles showupstream
+for var in repaint describe_style show_informative_status showdirtystate showstashstate showuntrackedfiles showupstream
set varargs $varargs --on-variable __fish_git_prompt_$var
end
function __fish_git_prompt_repaint $varargs --description "Event handler, repaints prompt when functionality changes"
if status --is-interactive
+ if test $argv[3] = __fish_git_prompt_show_informative_status
+ # Clear characters that have different defaults with/without informative status
+ for name in cleanstate dirtystate invalidstate stagedstate stateseparator untrackedfiles upstream_ahead upstream_behind
+ set -e ___fish_git_prompt_char_$name
+ end
+ end
+
commandline -f repaint ^/dev/null
end
end
set -l varargs
-for var in '' _prefix _suffix _bare _merging _branch _dirtystate _stagedstate _invalidstate _stashstate _untrackedfiles _upstream
+for var in '' _prefix _suffix _bare _merging _cleanstate _invalidstate _upstream _flags _branch _dirtystate _stagedstate _branch_detached _stashstate _untrackedfiles
set varargs $varargs --on-variable __fish_git_prompt_color$var
end
+set varargs $varargs --on-variable __fish_git_prompt_showcolorhints
function __fish_git_prompt_repaint_color $varargs --description "Event handler, repaints prompt when any color changes"
if status --is-interactive
set -l var $argv[3]
set -e _$var
set -e _{$var}_done
- if test $var = __fish_git_prompt_color
+ if test $var = __fish_git_prompt_color -o $var = __fish_git_prompt_color_flags -o $var = __fish_git_prompt_showcolorhints
# reset all the other colors too
- for name in prefix suffix bare merging branch dirtystate stagedstate invalidstate stashstate untrackedfiles upstream
+ for name in prefix suffix bare merging branch dirtystate stagedstate invalidstate stashstate untrackedfiles upstream flags
set -e ___fish_git_prompt_color_$name
set -e ___fish_git_prompt_color_{$name}_done
end
@@ -558,8 +755,9 @@ function __fish_git_prompt_repaint_color $varargs --description "Event handler,
commandline -f repaint ^/dev/null
end
end
+
set -l varargs
-for var in dirtystate stagedstate invalidstate stashstate untrackedfiles upstream_equal upstream_behind upstream_ahead upstream_diverged
+for var in cleanstate dirtystate invalidstate stagedstate stashstate stateseparator untrackedfiles upstream_ahead upstream_behind upstream_diverged upstream_equal upstream_prefix
set varargs $varargs --on-variable __fish_git_prompt_char_$var
end
function __fish_git_prompt_repaint_char $varargs --description "Event handler, repaints prompt when any char changes"
diff --git a/share/functions/__fish_list_current_token.fish b/share/functions/__fish_list_current_token.fish
index 878ac9d1..a88978cc 100644
--- a/share/functions/__fish_list_current_token.fish
+++ b/share/functions/__fish_list_current_token.fish
@@ -6,6 +6,7 @@
function __fish_list_current_token -d "List contents of token under the cursor if it is a directory, otherwise list the contents of the current directory"
set val (eval echo (commandline -t))
+ printf "\n"
if test -d $val
ls $val
else
diff --git a/share/functions/__fish_print_hostnames.fish b/share/functions/__fish_print_hostnames.fish
index 423f9952..2c737a69 100644
--- a/share/functions/__fish_print_hostnames.fish
+++ b/share/functions/__fish_print_hostnames.fish
@@ -13,11 +13,13 @@ function __fish_print_hostnames -d "Print a list of known hostnames"
end
# Print hosts with known ssh keys
- cat ~/.ssh/known_hosts{,2} ^/dev/null | grep -v '^|' | cut -d ' ' -f 1| cut -d , -f 1
+ # Does not match hostnames with @directives specified
+ sgrep -Eoh '^[^#@|, ]*' ~/.ssh/known_hosts{,2} ^/dev/null
# Print hosts from ssh configuration file
if [ -e ~/.ssh/config ]
- sgrep -i '^ *host' ~/.ssh/config | grep -v '[*?]' | cut -d ' ' -f 2
+ # Ignore lines containing wildcards
+ sgrep -Eoi '^ *host[^*]*$' ~/.ssh/config | cut -d '=' -f 2 | tr ' ' '\n'
end
end
diff --git a/share/functions/__fish_print_make_targets.fish b/share/functions/__fish_print_make_targets.fish
index bda806f4..5be984b8 100644
--- a/share/functions/__fish_print_make_targets.fish
+++ b/share/functions/__fish_print_make_targets.fish
@@ -3,6 +3,6 @@ function __fish_print_make_targets
# Some seds (e.g. on Mac OS X), don't support \n in the RHS
# Use a literal newline instead
# http://sed.sourceforge.net/sedfaq4.html#s4.1
- sgrep -h -E '^[^#%=$[:space:]][^#%=$]*:([^=]|$)' $files | cut -d ":" -f 1 | sed -e 's/^ *//;s/ *$//;s/ */\\
+ sgrep -h -E '^[^#%=$[:space:]][^#%=$]*:([^=]|$)' $files ^/dev/null | cut -d ":" -f 1 | sed -e 's/^ *//;s/ *$//;s/ */\\
/g' ^/dev/null
end
diff --git a/share/functions/__fish_print_mounted.fish b/share/functions/__fish_print_mounted.fish
index a7cfc0de..482559a8 100644
--- a/share/functions/__fish_print_mounted.fish
+++ b/share/functions/__fish_print_mounted.fish
@@ -1,4 +1,7 @@
function __fish_print_mounted --description 'Print mounted devices'
- cat /etc/mtab | cut -d " " -f 1-2|tr " " \n|sed -e "s/[0-9\.]*:\//\//"|sgrep "^/"
-
+ if test (uname) = Darwin
+ mount | cut -d " " -f 1-2|tr " " \n|sed -e "s/[0-9\.]*:\//\//"|sgrep "^/"
+ else
+ cat /etc/mtab | cut -d " " -f 1-2|tr " " \n|sed -e "s/[0-9\.]*:\//\//"|sgrep "^/"
+ end
end
diff --git a/share/functions/__fish_print_packages.fish b/share/functions/__fish_print_packages.fish
index 95a822c7..decf410d 100644
--- a/share/functions/__fish_print_packages.fish
+++ b/share/functions/__fish_print_packages.fish
@@ -2,7 +2,7 @@
function __fish_print_packages
# apt-cache is much, much faster than rpm, and can do this in real
- # time. We use it if available.
+ # time. We use it if available.
switch (commandline -tc)
case '-**'
@@ -13,27 +13,24 @@ function __fish_print_packages
set -l package (_ Package)
if type -f apt-cache >/dev/null
- # Apply the following filters to output of apt-cache:
- # 1) Remove package names with parentesis in them, since these seem to not correspond to actual packages as reported by rpm
- # 2) Remove package names that are .so files, since these seem to not correspond to actual packages as reported by rpm
- # 3) Remove path information such as /usr/bin/, as rpm packages do not have paths
-
- apt-cache --no-generate pkgnames (commandline -tc)|sgrep -v \( |sgrep -v '\.so\(\.[0-9]\)*$'|sed -e 's/\/.*\///'|sed -e 's/$/'\t$package'/'
+ # Do not generate the cache as apparently sometimes this is slow.
+ # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=547550
+ apt-cache --no-generate pkgnames (commandline -tc) ^/dev/null | sed -e 's/$/'\t$package'/'
return
end
- # Pkg is fast on FreeBSD and provides versioning info which we want for
- # installed packages
- if begin
- type -f pkg > /dev/null
- and test (uname) = "FreeBSD"
- end
- pkg query "%n-%v"
- return
- end
+ # Pkg is fast on FreeBSD and provides versioning info which we want for
+ # installed packages
+ if begin
+ type -f pkg > /dev/null
+ and test (uname) = "FreeBSD"
+ end
+ pkg query "%n-%v"
+ return
+ end
- # yum is slow, just like rpm, so go to the background
+ # yum is slow, just like rpm, so go to the background
if type -f /usr/share/yum-cli/completion-helper.py >/dev/null
# If the cache is less than six hours old, we do not recalculate it
@@ -49,11 +46,11 @@ function __fish_print_packages
end
# Remove package version information from output and pipe into cache file
- /usr/share/yum-cli/completion-helper.py list all -d 0 -C >$cache_file | cut -d '.' -f 1 | sed '1d' | sed '/^\s/d' | sed -e 's/$/'\t$package'/' &
+ /usr/share/yum-cli/completion-helper.py list all -d 0 -C >$cache_file | cut -d '.' -f 1 | sed '1d' | sed '/^\s/d' | sed -e 's/$/'\t$package'/' &
end
# Rpm is too slow for this job, so we set it up to do completions
- # as a background job and cache the results.
+ # as a background job and cache the results.
if type -f rpm >/dev/null
diff --git a/share/functions/__fish_pwd.fish b/share/functions/__fish_pwd.fish
new file mode 100644
index 00000000..28272871
--- /dev/null
+++ b/share/functions/__fish_pwd.fish
@@ -0,0 +1,10 @@
+switch (uname)
+case 'CYGWIN_*'
+ function __fish_pwd --description "Show current path"
+ pwd | sed -e 's-^/cygdrive/\(.\)/\?-\u\1:/-'
+ end
+case '*'
+ function __fish_pwd --description "Show current path"
+ pwd
+ end
+end \ No newline at end of file
diff --git a/share/functions/__fish_urlencode.fish b/share/functions/__fish_urlencode.fish
new file mode 100644
index 00000000..ebf5ba5d
--- /dev/null
+++ b/share/functions/__fish_urlencode.fish
@@ -0,0 +1,9 @@
+function __fish_urlencode --description "URL-encode stdin"
+ while read f
+ set lines (echo "$f" | sed -E -e 's/./\n\\0/g;/^$/d;s/\n//')
+ if [ (count $lines) -gt 0 ]
+ printf '%%%02x' "'"$lines"'" | sed -e 's/%2[fF]/\//g';
+ end
+ end
+ echo
+end
diff --git a/share/functions/eval.fish b/share/functions/eval.fish
index 432364ea..939b17c9 100644
--- a/share/functions/eval.fish
+++ b/share/functions/eval.fish
@@ -1,4 +1,3 @@
-
function eval -S -d "Evaluate parameters as a command"
# If we are in an interactive shell, eval should enable full
@@ -20,7 +19,20 @@ function eval -S -d "Evaluate parameters as a command"
status --job-control full
end
- echo "begin; $argv ;end eval2_inner <&3 3<&-" | . 3<&0
+ # rfish: To eval 'foo', we construct a block "begin ; foo; end <&3 3<&-"
+ # The 'eval2_inner' is a param to 'begin' itself; I believe it does nothing.
+ # Note the redirections are also within the quotes.
+ #
+ # We then pipe this to 'source 3<&0' which dup2's 3 to stdin.
+ #
+ # You might expect that the dup2(3, stdin) should overwrite stdin,
+ # and therefore prevent 'source' from reading the piped-in block. This doesn't happen
+ # because when you pipe to a builtin, we don't overwrite stdin with the read end
+ # of the block; instead we set a separate fd in a variable 'builtin_stdin', which is
+ # what it reads from. So builtins are magic in that, in pipes, their stdin
+ # is not fd 0.
+
+ echo "begin; $argv "\n" ;end eval2_inner <&3 3<&-" | source 3<&0
set -l res $status
status --job-control $mode
diff --git a/share/functions/fish_default_key_bindings.fish b/share/functions/fish_default_key_bindings.fish
index 3a9b4785..44821f36 100644
--- a/share/functions/fish_default_key_bindings.fish
+++ b/share/functions/fish_default_key_bindings.fish
@@ -35,6 +35,7 @@ function fish_default_key_bindings -d "Default (Emacs-like) key bindings for fis
# 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
+ bind \e\[3\;2~ backward-delete-char # Mavericks Terminal.app shift-delete
bind \e\eOC nextd-or-forward-word
bind \e\eOD prevd-or-backward-word
@@ -69,11 +70,19 @@ function fish_default_key_bindings -d "Default (Emacs-like) key bindings for fis
bind \cb backward-char
bind \ct transpose-chars
bind \et transpose-words
+ bind \eu upcase-word
+ # This clashes with __fish_list_current_token
+ # bind \el downcase-word
+ bind \ec capitalize-word
bind \e\x7f backward-kill-word
bind \eb backward-word
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\;9C forward-word #iTerm2
+ bind \e\[1\;9D backward-word #iTerm2
bind \ed forward-kill-word
bind -k ppage beginning-of-history
bind -k npage end-of-history
@@ -81,13 +90,13 @@ function fish_default_key_bindings -d "Default (Emacs-like) key bindings for fis
bind \e\> end-of-buffer
bind \el __fish_list_current_token
- bind \ew 'set tok (commandline -pt); if test $tok[1]; echo; whatis $tok[1]; commandline -f repaint; end'
+ bind \ew 'set tok (commandline -pt); if test $tok[1]; echo; whatis $tok[1]; commandline -f repaint; end'
bind \cl 'clear; commandline -f repaint'
bind \cc 'commandline ""'
bind \cu backward-kill-line
bind \ed kill-word
bind \cw backward-kill-path-component
- bind \ed 'set -l cmd (commandline); if test -z "$cmd"; echo; dirh; commandline -f repaint; else; commandline -f kill-word; end'
+ 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
# This will make sure the output of the current command is paged using the less pager when you press Meta-p
diff --git a/share/functions/help.fish b/share/functions/help.fish
index ef147e72..04992e35 100644
--- a/share/functions/help.fish
+++ b/share/functions/help.fish
@@ -54,8 +54,11 @@ function help --description 'Show help for the fish shell'
end
end
+ # If the OS appears to be Windows (graphical), try to use cygstart
+ if type cygstart > /dev/null
+ set fish_browser cygstart
# If xdg-open is available, just use that
- if type xdg-open > /dev/null
+ else if type xdg-open > /dev/null
set fish_browser xdg-open
end
diff --git a/share/functions/hostname.fish b/share/functions/hostname.fish
new file mode 100644
index 00000000..8caaca7c
--- /dev/null
+++ b/share/functions/hostname.fish
@@ -0,0 +1,10 @@
+# Query for USERDOMAIN to shorten waiting times when OS isn't Windows.
+set -q USERDOMAIN
+and switch (uname)
+case 'CYGWIN_*'
+ # Cygwin's hostname is broken when computer name contains Unicode
+ # characters. This hack "fixes" hostname in Cygwin.
+ function hostname --description "Show or set the system's host name"
+ echo $USERDOMAIN
+ end
+end
diff --git a/share/functions/ls.fish b/share/functions/ls.fish
index 1db74622..dd4fb3a6 100644
--- a/share/functions/ls.fish
+++ b/share/functions/ls.fish
@@ -14,7 +14,7 @@ if command ls --version 1>/dev/null 2>/dev/null
if not set -q LS_COLORS
if type -f dircolors >/dev/null
- eval (dircolors -c)
+ eval (dircolors -c | sed 's/>&\/dev\/null$//')
end
end
diff --git a/share/functions/man.fish b/share/functions/man.fish
index cb11d655..2b9bab51 100644
--- a/share/functions/man.fish
+++ b/share/functions/man.fish
@@ -8,7 +8,7 @@ function man --description "Format and display the on-line manual pages"
set -l fish_manpath (dirname $__fish_datadir)/fish/man
if test -d "$fish_manpath"
# Notice local but exported variable
- set -lx MANPATH "$fish_manpath":(command man --path)
+ set -lx MANPATH "$fish_manpath":(command manpath)
# Invoke man with this manpath, and we're done
command man $argv
diff --git a/share/functions/open.fish b/share/functions/open.fish
index 885079e1..63d56237 100644
--- a/share/functions/open.fish
+++ b/share/functions/open.fish
@@ -14,7 +14,11 @@ if not test (uname) = Darwin
end
end
- if type -f xdg-open >/dev/null
+ if type -f cygstart >/dev/null
+ for i in $argv
+ cygstart $i
+ end
+ else if type -f xdg-open >/dev/null
for i in $argv
xdg-open $i
end
diff --git a/share/functions/prompt_pwd.fish b/share/functions/prompt_pwd.fish
index 716372f4..991b007b 100644
--- a/share/functions/prompt_pwd.fish
+++ b/share/functions/prompt_pwd.fish
@@ -1,9 +1,14 @@
-if test (uname) = Darwin
- function prompt_pwd --description "Print the current working directory, shortend to fit the prompt"
+switch (uname)
+case Darwin
+ function prompt_pwd --description "Print the current working directory, shortened to fit the prompt"
echo $PWD | sed -e "s|^$HOME|~|" -e 's|^/private||' -e 's-\([^/.]\)[^/]*/-\1/-g'
end
-else
- function prompt_pwd --description "Print the current working directory, shortend to fit the prompt"
+case 'CYGWIN_*'
+ function prompt_pwd --description "Print the current working directory, shortened to fit the prompt"
+ echo $PWD | sed -e "s|^$HOME|~|" -e 's|^/cygdrive/\(.\)|\1/:|' -e 's-\([^/.]\)[^/]*/-\1/-g' -e 's-^\([^/]\)/:/\?-\u\1:/-'
+ end
+case '*'
+ function prompt_pwd --description "Print the current working directory, shortened to fit the prompt"
echo $PWD | sed -e "s|^$HOME|~|" -e 's-\([^/.]\)[^/]*/-\1/-g'
end
end
diff --git a/share/tools/create_manpage_completions.py b/share/tools/create_manpage_completions.py
index 24650ac6..dc67f4c8 100755
--- a/share/tools/create_manpage_completions.py
+++ b/share/tools/create_manpage_completions.py
@@ -572,7 +572,7 @@ class TypeDarwinManParser(ManParser):
# Extract the description
desc_lines = []
while lines and not self.is_option(lines[0]):
- line = lines.pop(0).strip()
+ line = lossy_unicode(lines.pop(0).strip())
if line.startswith('.'):
line = self.groff_replace_escapes(line)
line = self.trim_groff(line).strip()
@@ -871,7 +871,7 @@ def get_paths_from_manpath():
sys.exit(-1)
result = []
for parent_path in parent_paths:
- for section in ['man1', 'man8']:
+ for section in ['man1', 'man6', 'man8']:
directory_path = os.path.join(parent_path, section)
try:
names = os.listdir(directory_path)
@@ -925,7 +925,7 @@ if __name__ == "__main__":
show_progress = True
elif opt in ('-c', '--cleanup-in'):
cleanup_directories.append(value)
- elif opt in ('-z'):
+ elif opt in ('-z',):
DEROFF_ONLY = True
else:
assert False, "unhandled option"
@@ -952,18 +952,4 @@ if __name__ == "__main__":
if e.errno != errno.EEXIST:
raise
- if True:
- parse_and_output_man_pages(file_paths, output_directory, show_progress)
- else:
- # Profiling code
- import cProfile, pstats
- cProfile.run('parse_and_output_man_pages(file_paths, output_directory, show_progress)', 'fooprof')
- p = pstats.Stats('fooprof')
- p.sort_stats('cumulative').print_stats(100)
-
- # Here we can write out all the parser infos
- if False:
- for name in PARSER_INFO:
- print('Parser ' + name + ':')
- print('\t' + ', '.join(PARSER_INFO[name]))
- print('')
+ parse_and_output_man_pages(file_paths, output_directory, show_progress)
diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py
index 4f07fd9d..f735a026 100755
--- a/share/tools/web_config/webconfig.py
+++ b/share/tools/web_config/webconfig.py
@@ -615,7 +615,7 @@ while PORT <= 9000:
Handler = FishConfigHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
# Success
- break;
+ break
except socket.error:
err_type, err_value = sys.exc_info()[:2]
# str(err_value) handles Python3 correctly
diff --git a/tests/test1.in b/tests/test1.in
index 4c261e10..c180159c 100644
--- a/tests/test1.in
+++ b/tests/test1.in
@@ -94,6 +94,11 @@ else
end
echo Test 5 $sta
+# Verify that we can turn stderr into stdout and then pipe it.
+# Note that the order here seems unspecified - 'errput' appears before 'output', why?
+echo Test redirections
+begin ; echo output ; echo errput 1>&2 ; end 2>&1 | tee /tmp/tee_test.txt ; cat /tmp/tee_test.txt
+
# echo tests
echo 'abc\ndef'
diff --git a/tests/test1.out b/tests/test1.out
index 13219ff3..c6ecbb30 100644
--- a/tests/test1.out
+++ b/tests/test1.out
@@ -18,6 +18,11 @@ Test pass
Test 3 pass
Test 4 pass
Test 5 pass
+Test redirections
+errput
+output
+errput
+output
abc\ndef
abc
def
diff --git a/tokenizer.cpp b/tokenizer.cpp
index 6d99b46c..1ef0bf5d 100644
--- a/tokenizer.cpp
+++ b/tokenizer.cpp
@@ -37,6 +37,12 @@ segments.
#define PARAN_ERROR _( L"Unexpected end of string, parenthesis do not match" )
/**
+ Error string for mismatched square brackets
+*/
+#define SQUARE_BRACKET_ERROR _( L"Unexpected end of string, square brackets do not match" )
+
+
+/**
Error string for invalid redirections
*/
#define REDIRECT_ERROR _( L"Invalid input/output redirection" )
@@ -87,7 +93,7 @@ int tok_get_error(tokenizer_t *tok)
}
-tokenizer_t::tokenizer_t(const wchar_t *b, tok_flags_t flags) : buff(NULL), orig_buff(NULL), last_type(0), last_pos(0), has_next(false), accept_unfinished(false), show_comments(false), last_quote(0), error(0), squash_errors(false), cached_lineno_offset(0), cached_lineno_count(0)
+tokenizer_t::tokenizer_t(const wchar_t *b, tok_flags_t flags) : buff(NULL), orig_buff(NULL), last_type(TOK_NONE), last_pos(0), has_next(false), accept_unfinished(false), show_comments(false), last_quote(0), error(0), squash_errors(false), cached_lineno_offset(0), cached_lineno_count(0)
{
/* We can only generate error messages on the main thread due to wgettext() thread safety issues. */
@@ -110,7 +116,7 @@ tokenizer_t::tokenizer_t(const wchar_t *b, tok_flags_t flags) : buff(NULL), orig
tok_next(this);
}
-int tok_last_type(tokenizer_t *tok)
+enum token_type tok_last_type(tokenizer_t *tok)
{
CHECK(tok, TOK_ERROR);
CHECK(tok->buff, TOK_ERROR);
@@ -237,7 +243,6 @@ static void read_string(tokenizer_t *tok)
while (1)
{
-
if (!myal(*tok->buff))
{
if (*tok->buff == L'\\')
@@ -390,7 +395,19 @@ static void read_string(tokenizer_t *tok)
if ((!tok->accept_unfinished) && (mode != mode_regular_text))
{
- TOK_CALL_ERROR(tok, TOK_UNTERMINATED_SUBSHELL, PARAN_ERROR);
+ switch (mode)
+ {
+ case mode_subshell:
+ TOK_CALL_ERROR(tok, TOK_UNTERMINATED_SUBSHELL, PARAN_ERROR);
+ break;
+ case mode_array_brackets:
+ case mode_array_brackets_and_subshell:
+ TOK_CALL_ERROR(tok, TOK_UNTERMINATED_SUBSHELL, SQUARE_BRACKET_ERROR); // TOK_UNTERMINATED_SUBSHELL is a lie but nobody actually looks at it
+ break;
+ default:
+ assert(0 && "Unexpected mode in read_string");
+ break;
+ }
return;
}
@@ -423,7 +440,7 @@ static void read_comment(tokenizer_t *tok)
*/
static void read_redirect(tokenizer_t *tok, int fd)
{
- int mode = -1;
+ enum token_type redirection_mode = TOK_NONE;
if ((*tok->buff == L'>') ||
(*tok->buff == L'^'))
@@ -432,11 +449,11 @@ static void read_redirect(tokenizer_t *tok, int fd)
if (*tok->buff == *(tok->buff-1))
{
tok->buff++;
- mode = 1;
+ redirection_mode = TOK_REDIRECT_APPEND;
}
else
{
- mode = 0;
+ redirection_mode = TOK_REDIRECT_OUT;
}
if (*tok->buff == L'|')
@@ -455,7 +472,7 @@ static void read_redirect(tokenizer_t *tok, int fd)
else if (*tok->buff == L'<')
{
tok->buff++;
- mode = 2;
+ redirection_mode = TOK_REDIRECT_IN;
}
else
{
@@ -476,7 +493,7 @@ static void read_redirect(tokenizer_t *tok, int fd)
}
else
{
- tok->last_type = TOK_REDIRECT_OUT + mode;
+ tok->last_type = redirection_mode;
}
}
@@ -624,6 +641,31 @@ void tok_next(tokenizer_t *tok)
}
+enum token_type tok_peek_next(tokenizer_t *tok, wcstring *out_next_string)
+{
+ if (out_next_string != NULL)
+ {
+ 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;
+}
+
const wchar_t *tok_string(tokenizer_t *tok)
{
return tok?tok->orig_buff:0;
diff --git a/tokenizer.h b/tokenizer.h
index 0f3ff369..dec206a5 100644
--- a/tokenizer.h
+++ b/tokenizer.h
@@ -76,7 +76,7 @@ struct tokenizer_t
wcstring last_token;
/** Type of last token*/
- int last_type;
+ enum token_type last_type;
/** Offset of last token*/
size_t last_pos;
@@ -122,7 +122,7 @@ void tok_next(tokenizer_t *tok);
/**
Returns the type of the last token. Must be one of the values in the token_type enum.
*/
-int tok_last_type(tokenizer_t *tok);
+enum token_type tok_last_type(tokenizer_t *tok);
/**
Returns the last token string. The string should not be freed by the caller.
@@ -147,12 +147,14 @@ int tok_get_pos(const tokenizer_t *tok);
/** Returns the extent of the current token */
size_t tok_get_extent(const tokenizer_t *tok);
+/** Returns the token type after the current one, without adjusting the position. Optionally returns the next string by reference. */
+enum token_type tok_peek_next(tokenizer_t *tok, wcstring *out_next_string);
+
/**
Returns the original string to tokenizer
*/
const wchar_t *tok_string(tokenizer_t *tok);
-
/**
Returns only the first token from the specified string. This is a
convenience function, used to retrieve the first token of a
diff --git a/user_doc.head.html b/user_doc.head.html
index 7ac670ce..958a9691 100644
--- a/user_doc.head.html
+++ b/user_doc.head.html
@@ -2,41 +2,158 @@
<head>
<title>fish user documentation</title>
<link href="doxygen.css" rel="stylesheet" type="text/css">
-<!--
-Override the default doxygen stylesheet to make the difference between different header levels larger
--->
+
<style type='text/css'>
-H1
+
+/* fish documentation CSS overrides */
+
+/* No scrollbar on the body. Our columns are independently scrollable */
+body
+{
+ overflow: hidden;
+}
+
+.fish_left_bar, .fish_right_bar, .fish_only_bar
+{
+ position: absolute;
+ top: 36px;
+ bottom: 0;
+ overflow-y: scroll;
+}
+
+.fish_left_bar
+{
+ width: 250px;
+ color: white;
+}
+.fish_left_bar a { color: white; }
+.fish_left_bar a:visited { color: inherit; }
+.fish_right_bar
+{
+ margin-left: 250px;
+ margin-right: 0px;
+ padding: 0 0 0 20px; /* 20 px on left */
+ background-color: white;
+ -moz-box-shadow: -5px 0px 5px -2px black;
+ -webkit-box-shadow: -5px 0px 5px -2px black;
+ box-shadow: -5px 0px 5px -2px black;
+}
+
+.fish_right_bar p
+{
+ margin-right: 8px;
+}
+
+.fish_left_big { width: 380px; }
+.fish_right_little { margin-left: 380px; }
+
+.fish_left_medium { width: 280; }
+.fish_right_medium { margin-left: 280; }
+
+.fish_left_little { width: 200px; }
+.fish_right_big { margin-left: 200px; }
+
+
+.fish_only_bar
+{
+ padding: 0px 20px;
+}
+
+h1, h2, h3 { color: #1E335E; }
+
+h1 { font-size: 150%; }
+h2 { font-size: 115%; }
+h3 { font-size: 105%; }
+
+/* Don't show the header */
+div.header { display: none; }
+
+h1.interior_title, h1.interior_title_borderless {
+ color: #333;
+}
+
+h1.interior_title {
+ padding-bottom: 10px;
+ border-bottom: 1px solid #AAA;
+}
+
+div.contents { margin: 0px; }
+
+div.qindex
{
- font-size: 180%;
+ height: 30px;
+ line-height: 30px;
+ text-align: center;
+ background-image: none;
+ color: white;
+ border: none;
}
-H2
+.fish_left_bar, div.header, div.qindex
{
- font-size: 150%;
+ background-color: #1E335E;
}
-H3
+
+div.qindex
{
- padding-left:10%;
- font-size: 120%;
+ border: none;
+ padding: 3px 0px;
+
+ /* Ensure the bottom border is visible over the left column */
+ position: relative;
+ z-index: 2;
}
-H4
+div.qindex a
{
- padding-left:10%;
- font-style: italic;
- font-weight: normal;
- font-size: 90%;
+ color: white;
}
+
+/* Hide the doxygen logo */
+.footer { display: none; }
+
+/* Don't let pre elements create a minimum width on the right bar */
+.fish_right_bar pre { white-space:pre-wrap; }
+
+/* Adjust list */
+.fish_left_bar ul {
+ padding-left: 27px;
+ padding-right: 10px;
+}
+.fish_left_bar ul li { margin-bottom: 5px; }
+
+/* Tighter lists for the little (command) bar */
+.fish_left_little ul li { margin-bottom: 0; }
+
+/* Adjust sublists */
+.fish_left_bar ul ul { padding-left: 17px; }
+.fish_left_bar ul ul li { margin-bottom: 0; }
+
+/* Link hover */
+.fish_left_bar a:hover {
+ text-decoration: none;
+ background-color: inherit;
+ color: #99BBFF;
+}
+
+/* Horizontal bar */
+hr {
+ height: 1px;
+ border: 0;
+ background-color: #AAA;
+}
+
</style>
</head>
<body>
<div class="qindex">
- <a class="qindex" href="http://fishshell.com/"><tt>fish</tt> home</a>
+ <a class="qindex" href="http://fishshell.com/"><tt>fish</tt> shell</a>
+|
+ <a class="qindex" href="index.html">Documentation</a>
|
- <a class="qindex" href="index.html">Main documentation page</a>
+ <a class="qindex" href="tutorial.html">Tutorial</a>
|
-<a class="qindex" href="design.html">Design document</a>
+<a class="qindex" href="design.html">Design</a>
|
<a class="qindex" href="commands.html">Commands</a>
|
diff --git a/wgetopt.cpp b/wgetopt.cpp
index 8e114117..08ccc3b1 100644
--- a/wgetopt.cpp
+++ b/wgetopt.cpp
@@ -638,6 +638,7 @@ _wgetopt_internal(int argc, wchar_t *const *argv, const wchar_t *optstring, cons
fwprintf(stderr, _(L"%ls: Invalid option -- %lc\n"), argv[0], c);
}
woptopt = c;
+ woptind++;
return '?';
}
if (temp[1] == ':')
diff --git a/wildcard.cpp b/wildcard.cpp
index 0edcfa85..621ece72 100644
--- a/wildcard.cpp
+++ b/wildcard.cpp
@@ -227,13 +227,14 @@ static bool wildcard_complete_internal(const wcstring &orig,
// Implement EXPAND_FUZZY_MATCH by short-circuiting everything if there are no remaining wildcards
if ((expand_flags & EXPAND_FUZZY_MATCH) && ! at_end_of_wildcard && ! wildcard_has(wc, true))
{
- fuzzy_match = string_fuzzy_match_string(wc, str);
- if (fuzzy_match.type != fuzzy_match_none)
+ string_fuzzy_match_t local_fuzzy_match = string_fuzzy_match_string(wc, str);
+ if (local_fuzzy_match.type != fuzzy_match_none)
{
has_match = true;
+ fuzzy_match = local_fuzzy_match;
/* If we're not a prefix or exact match, then we need to replace the token. Note that in this case we're not going to call ourselves recursively, so these modified flags won't "leak" except into the completion. */
- if (match_type_requires_full_replacement(fuzzy_match.type))
+ if (match_type_requires_full_replacement(local_fuzzy_match.type))
{
flags |= COMPLETE_REPLACES_TOKEN;
completion_string = orig.c_str();
@@ -310,23 +311,38 @@ static bool wildcard_complete_internal(const wcstring &orig,
return false;
/* Try all submatches */
- do
+ for (size_t i=0; str[i] != L'\0'; i++)
{
- res = wildcard_complete_internal(orig, str, wc+1, 0, desc, desc_func, out, expand_flags, flags);
- if (res)
- break;
+ const size_t before_count = out.size();
+ 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();
+ for (size_t j = before_count; j < after_count; j++)
+ {
+ if (out[j].match.type <= fuzzy_match_prefix)
+ {
+ has_prefix_match = true;
+ break;
+ }
+ }
+ if (has_prefix_match)
+ break;
+ }
}
- while (*str++ != 0);
return res;
}
else if (*wc == ANY_CHAR || *wc == *str)
{
- return wildcard_complete_internal(orig, str+1, wc+1, 0, desc, desc_func, out, expand_flags, flags);
+ return wildcard_complete_internal(orig, str+1, wc+1, false, desc, desc_func, out, expand_flags, flags);
}
else if (towlower(*wc) == towlower(*str))
{
- return wildcard_complete_internal(orig, str+1, wc+1, 0, desc, desc_func, out, expand_flags, flags | COMPLETE_REPLACES_TOKEN);
+ return wildcard_complete_internal(orig, str+1, wc+1, false, desc, desc_func, out, expand_flags, flags | COMPLETE_REPLACES_TOKEN);
}
return false;
}