mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-13 04:41:15 -03:00
Compare commits
167 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a928517e95 | ||
|
|
5ec9fcd8d4 | ||
|
|
ed5f90d22e | ||
|
|
5cfd3eb63a | ||
|
|
aad2848e80 | ||
|
|
320cb6857f | ||
|
|
9ac78e06b4 | ||
|
|
93e6f57dfc | ||
|
|
45c7836bec | ||
|
|
b8778ba4a2 | ||
|
|
b16511344e | ||
|
|
1054a2fd36 | ||
|
|
b86b84e2a9 | ||
|
|
52d1b6b97d | ||
|
|
9b4310b10f | ||
|
|
13a4ef80b3 | ||
|
|
0de2a1072f | ||
|
|
2e5693a6bc | ||
|
|
acc2353328 | ||
|
|
8423345e09 | ||
|
|
36d4283d17 | ||
|
|
acd8363c38 | ||
|
|
e8a31a13a1 | ||
|
|
3e82be4ac2 | ||
|
|
521546a986 | ||
|
|
708f80d855 | ||
|
|
8645aa94c8 | ||
|
|
043725cdd5 | ||
|
|
209a2576cd | ||
|
|
5284a133b0 | ||
|
|
2d26a262e7 | ||
|
|
2e81ade66a | ||
|
|
5eb1ef4b4a | ||
|
|
5d6415b6bf | ||
|
|
bd03c3fbc5 | ||
|
|
20bcbcc252 | ||
|
|
47a9f99523 | ||
|
|
7356987e6e | ||
|
|
6518b6c6b7 | ||
|
|
d5462fb3d7 | ||
|
|
d7283cdaa1 | ||
|
|
54360d8cfe | ||
|
|
0b0d0e7799 | ||
|
|
609100c196 | ||
|
|
9e922a6e02 | ||
|
|
a275618589 | ||
|
|
83c7931afb | ||
|
|
1155c4b413 | ||
|
|
7a1146ebb5 | ||
|
|
180c211dd2 | ||
|
|
848495d4cf | ||
|
|
87c51f2c10 | ||
|
|
b41fced062 | ||
|
|
71e835feec | ||
|
|
313cb0d248 | ||
|
|
0c4ede5627 | ||
|
|
034aaaa62b | ||
|
|
839cd2a1c7 | ||
|
|
adba0550d5 | ||
|
|
6d1c127687 | ||
|
|
7cca963b8f | ||
|
|
1fb8f4e277 | ||
|
|
98863541c3 | ||
|
|
87bfd1a01e | ||
|
|
95385eda80 | ||
|
|
c02f5ceb0f | ||
|
|
4ba1f9e398 | ||
|
|
294e78205c | ||
|
|
d437a84828 | ||
|
|
2f28e96956 | ||
|
|
00a8766635 | ||
|
|
097d2246c2 | ||
|
|
23c3101440 | ||
|
|
003ea83410 | ||
|
|
de87419df9 | ||
|
|
4e505efc50 | ||
|
|
b7d910a941 | ||
|
|
f05fe4e292 | ||
|
|
72e687296b | ||
|
|
c9c311fbdb | ||
|
|
b9b66791c1 | ||
|
|
9b0d45d4fa | ||
|
|
5709c81fe0 | ||
|
|
e35b91d38c | ||
|
|
4f4d34e664 | ||
|
|
f6047f02d6 | ||
|
|
71e69b6d75 | ||
|
|
60c47deca9 | ||
|
|
c10952c354 | ||
|
|
e73226d7e8 | ||
|
|
19e12e3747 | ||
|
|
e4ce5ca24f | ||
|
|
01fb830bf5 | ||
|
|
edcf15e3d7 | ||
|
|
9f05697dcc | ||
|
|
c18614552d | ||
|
|
9701d5cc7b | ||
|
|
50fc3d72df | ||
|
|
feaeca4999 | ||
|
|
d4fb9a0e65 | ||
|
|
2c38978115 | ||
|
|
520f810bf9 | ||
|
|
d441de33e5 | ||
|
|
46b791240a | ||
|
|
3bd24ddb17 | ||
|
|
26c1430e82 | ||
|
|
6c3900ff64 | ||
|
|
6192e2453e | ||
|
|
eab836864e | ||
|
|
225caa2fe8 | ||
|
|
4fe2a2921f | ||
|
|
7779132595 | ||
|
|
ca5a4ec1d5 | ||
|
|
49ed20c8cb | ||
|
|
a5f6382d77 | ||
|
|
b2f047421d | ||
|
|
dfe7813c02 | ||
|
|
ddbf63c46f | ||
|
|
c8fe0e53dd | ||
|
|
7bcae09674 | ||
|
|
2a5ad198bf | ||
|
|
960cc628b2 | ||
|
|
6b41240cd2 | ||
|
|
6e873719fd | ||
|
|
f4f9ed56ee | ||
|
|
9f23f619c9 | ||
|
|
1e234f492c | ||
|
|
f0ab1331a5 | ||
|
|
99b729eb4d | ||
|
|
9af0797334 | ||
|
|
6bef7b7be9 | ||
|
|
b0b2182535 | ||
|
|
fb979922b3 | ||
|
|
c4bd110fca | ||
|
|
b663b0e818 | ||
|
|
41f1232cf9 | ||
|
|
4a2aed1f8e | ||
|
|
2d46969d3e | ||
|
|
f382fa8e8a | ||
|
|
7ea2dc4488 | ||
|
|
56679d4776 | ||
|
|
070ef6fd5b | ||
|
|
075be74cc4 | ||
|
|
5a8be61954 | ||
|
|
7fdbbe0711 | ||
|
|
8af6bb4436 | ||
|
|
2bb52c65c2 | ||
|
|
37d91d0c29 | ||
|
|
8dfee7ff76 | ||
|
|
07de13f61f | ||
|
|
668de88e69 | ||
|
|
31432c3535 | ||
|
|
cdb82e45ac | ||
|
|
a90b521eb4 | ||
|
|
25e0a39165 | ||
|
|
d982427216 | ||
|
|
21521b2953 | ||
|
|
42458ff7ab | ||
|
|
a8c9019a39 | ||
|
|
100a0ea549 | ||
|
|
cbe2d4b5f1 | ||
|
|
7878dbc4f0 | ||
|
|
e16f6ca2aa | ||
|
|
c7e26e494e | ||
|
|
6e6b294a3f | ||
|
|
00303ed07f | ||
|
|
345950ac1b |
@@ -1,4 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!-- Sadly we can't enable the following two rules since doing so causes false
|
||||
positives in standard header files rather than just project specific
|
||||
source files. If we can find a way to enable these rules by also
|
||||
excluding system include files we should do so.
|
||||
<rule version="1">
|
||||
<pattern> wcwidth \(</pattern>
|
||||
<message>
|
||||
@@ -16,3 +21,4 @@
|
||||
<summary>Always use fish_wcswidth rather than wcswidth.</summary>
|
||||
</message>
|
||||
</rule>
|
||||
<--!>
|
||||
10
.cppcheck.suppressions
Normal file
10
.cppcheck.suppressions
Normal file
@@ -0,0 +1,10 @@
|
||||
// suppress all instances of varFuncNullUB: "Passing NULL after the last typed
|
||||
// argument to a variadic function leads to undefined behaviour." That's
|
||||
// because all the places we do this are valid and won't cause problems even
|
||||
// on a ILP64 platform because we're careful about using NULL rather than 0.
|
||||
varFuncNullUB
|
||||
// Suppress the warning about unmatched suppressions. At the moment these
|
||||
// warnings are emitted even when removing the suppression comment results in
|
||||
// the warning being suppressed. In other words this unmatchedSuppression
|
||||
// warnings are false positives.
|
||||
unmatchedSuppression
|
||||
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,5 +1,5 @@
|
||||
<!-- check if this problem is already solved! github.com/issues?q=is:issue+user:fish-shell -->
|
||||
- [ ] Have you checked if problem occurs with [fish 2.3.1](/fish-shell/fish-shell/releases/tag/2.3.1)?
|
||||
- [ ] Have you checked if problem occurs with [fish 2.4.0](/fish-shell/fish-shell/releases/tag/2.4.0)?
|
||||
- [ ] Tried fish without third-party customizations *(check `sh -c 'env HOME=$(mktemp -d) fish'`)*?
|
||||
|
||||
**fish version installed** *(`fish --version`)*:
|
||||
|
||||
14
.oclint
14
.oclint
@@ -51,3 +51,17 @@ disable-rules:
|
||||
# and is therefore just noise. Disable this rule.
|
||||
#
|
||||
- InvertedLogic
|
||||
#
|
||||
# The idea behind the "double negative" rule is sound since constructs
|
||||
# like "!!(var & flag)" should be written as "static_cast<bool>(var &
|
||||
# flag)". Unfortunately this rule has way too many false positives;
|
||||
# especially in the context of assert statements. So disable this rule.
|
||||
#
|
||||
- DoubleNegative
|
||||
#
|
||||
# Avoiding bitwise operators in a conditional is a good idea with one
|
||||
# exception: testing whether a bit flag is set. Which happens to be the
|
||||
# only time you'll see something like `if (j->flags & JOB_CONSTRUCTED)`
|
||||
# in fish source.
|
||||
#
|
||||
- BitwiseOperatorInConditional
|
||||
|
||||
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,3 +1,19 @@
|
||||
# fish next-2.x (released ???)
|
||||
|
||||
---
|
||||
|
||||
# fish 2.4.0 (released November 8, 2016)
|
||||
|
||||
There are no major changes between 2.4b1 and 2.4.0.
|
||||
|
||||
## Notable fixes and improvements
|
||||
- The documentation is now generated properly and with the correct version identifier.
|
||||
- Automatic cursor changes are now only enabled on the subset of XTerm versions known to support them, resolving a problem where older versions printed garbage to the terminal before and after every prompt (#3499).
|
||||
- Improved the title set in Apple Terminal.app.
|
||||
- Added completions for `defaults` and improved completions for `diskutil` (#3478).
|
||||
|
||||
---
|
||||
|
||||
# fish 2.4b1 (released October 18, 2016)
|
||||
|
||||
## Significant changes
|
||||
|
||||
38
Makefile.in
38
Makefile.in
@@ -286,7 +286,7 @@ prof: all
|
||||
# directory once Doxygen is done.
|
||||
#
|
||||
doc: $(HDR_FILES_SRC) Doxyfile.user $(HTML_SRC) $(HELP_SRC) doc.h $(HDR_FILES) lexicon_filter
|
||||
@echo " SED doxygen $(em)user_doc$(sgr0)"
|
||||
@echo " doxygen $(em)user_doc$(sgr0)"
|
||||
$v (cat Doxyfile.user; echo INPUT_FILTER=./lexicon_filter; echo PROJECT_NUMBER=$(FISH_BUILD_VERSION) | $(SED) "s/-.*//") | doxygen - && touch user_doc
|
||||
$v rm -f $(wildcard $(addprefix ./user_doc/html/,arrow*.png bc_s.png bdwn.png closed.png doc.png folder*.png ftv2*.png nav*.png open.png splitbar.png sync_*.png tab*.* doxygen.* dynsections.js jquery.js pages.html))
|
||||
|
||||
@@ -367,7 +367,7 @@ test_interactive: $(call filter_up_to,test_interactive,$(active_test_goals))
|
||||
# builtins
|
||||
#
|
||||
doc_src/commands.hdr:$(HELP_SRC) doc_src/commands.hdr.in |
|
||||
@echo " CAT AWK $(em)$@$(sgr0)"
|
||||
@echo " CAT AWK $(em)$@$(sgr0)"
|
||||
$v rm -f command_list.tmp command_list_toc.tmp $@
|
||||
$v for i in $(sort $(HELP_SRC)); do \
|
||||
echo "<hr>" >>command_list.tmp; \
|
||||
@@ -383,10 +383,10 @@ doc_src/commands.hdr:$(HELP_SRC) doc_src/commands.hdr.in |
|
||||
$v 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) | show-SED
|
||||
@echo " SED $(em)$@$(sgr0)"
|
||||
@echo " SED $(em)$@$(sgr0)"
|
||||
$v rm -f toc.tmp $@
|
||||
# Ugly hack to set the toc initial title for the main page
|
||||
$v echo '- <a href="index.html" id="toc-index">fish shell documentation - $FISH_BUILD_VERSION</a>' > toc.tmp
|
||||
$v echo '- <a href="index.html" id="toc-index">fish shell documentation - $(FISH_BUILD_VERSION)</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
|
||||
@@ -400,7 +400,7 @@ toc.txt: $(HDR_FILES:index.hdr=index.hdr.in) | show-SED
|
||||
$v mv toc.tmp $@
|
||||
|
||||
doc_src/index.hdr: toc.txt doc_src/index.hdr.in | show-AWK
|
||||
@echo " AWK CAT $(em)$@$(sgr0)"
|
||||
@echo " AWK CAT $(em)$@$(sgr0)"
|
||||
$v cat $@.in | $(AWK) '{if ($$0 ~ /@toc@/){ system("cat toc.txt");} else{ print $$0;}}' >$@
|
||||
|
||||
#
|
||||
@@ -415,7 +415,7 @@ doc_src/index.hdr: toc.txt doc_src/index.hdr.in | show-AWK
|
||||
lexicon.txt: doc_src/commands.hdr $(FUNCTIONS_DIR_FILES) $(COMPLETIONS_DIR_FILES) share/functions/__fish_config_interactive.fish | show-SED show-FGREP
|
||||
$v rm -f lexicon.tmp lexicon_catalog.tmp lexicon_catalog.txt $@
|
||||
# Scan sources for commands/functions/binaries/colours. If GNU sed was portable, this could be much smarter.
|
||||
@echo " SEDFGREP $(em)$@$(sgr0)"
|
||||
@echo " SEDFGREP $(em)$@$(sgr0)"
|
||||
$v $(SED) <command_list_toc.txt >>lexicon.tmp -n \
|
||||
-e "s|^.*>\([a-z][a-z_]*\)</a>|'\1'|w lexicon_catalog.tmp" \
|
||||
-e "s|'\(.*\)'|bltn \1|p"; mv lexicon_catalog.tmp lexicon_catalog.txt
|
||||
@@ -453,8 +453,7 @@ lexicon_filter: lexicon.txt lexicon_filter.in | show-SED
|
||||
WORDBL='[[:<:]]'; WORDBR='[[:>:]]'; \
|
||||
else \
|
||||
WORDBL='\\<'; WORDBR='\\>'; \
|
||||
fi
|
||||
$v $(SED) <lexicon.txt >>$@.tmp -n -e "s|^\([a-z][a-z][a-z][a-z]\) \([a-z_-]*\)$$|s,$$WORDBL\2$$WORDBR,@\1{\2},g|p" -e '$$G;s/.*\n/b tidy/p'
|
||||
fi; $(SED) <lexicon.txt >>$@.tmp -n -e "s|^\([a-z][a-z][a-z][a-z]\) \([a-z_-]*\)$$|s,$$WORDBL\2$$WORDBR,@\1{\2},g|p" -e '$$G;s/.*\n/b tidy/p';
|
||||
$v mv $@.tmp $@; test -x $@ || chmod a+x $@;
|
||||
|
||||
|
||||
@@ -475,7 +474,7 @@ doc.h: $(HDR_FILES)
|
||||
# the internal help function text.
|
||||
#
|
||||
%.doxygen:%.txt
|
||||
@echo " cat * $(em)$@$(sgr0)"
|
||||
@echo " cat * $(em)$@$(sgr0)"
|
||||
$v echo "/** \page " `basename $*` >$@;
|
||||
$v cat $*.txt >>$@;
|
||||
$v echo "*/" >>$@
|
||||
@@ -521,7 +520,7 @@ doc.h: $(HDR_FILES)
|
||||
# Create a template translation object
|
||||
#
|
||||
messages.pot: $(wildcard src/*.cpp src/*.h share/completions/*.fish share/functions/*.fish)
|
||||
@echo " xgettext $(em)$@$(sgr0)"
|
||||
@echo " xgettext $(em)$@$(sgr0)"
|
||||
xgettext -k_ -kN_ $(wildcard src/*.cpp src/*.h) -o messages.pot
|
||||
$v xgettext -j -k_ -kN_ -k--description -LShell --from-code=UTF-8 $(wildcard share/completions/*.fish share/functions/*.fish) share/fish.config -o messages.pot
|
||||
|
||||
@@ -650,6 +649,7 @@ install-force: all install-translations | show-datadir show-sysconfdir show-extr
|
||||
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish
|
||||
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/completions
|
||||
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/functions
|
||||
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/groff
|
||||
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/man/man1
|
||||
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/tools
|
||||
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/tools/web_config
|
||||
@@ -674,6 +674,7 @@ install-force: all install-translations | show-datadir show-sysconfdir show-extr
|
||||
$(INSTALL) -m 644 $$i $(DESTDIR)$(datadir)/fish/functions/; \
|
||||
done;
|
||||
@echo "Installing $(bo)man pages$(sgr0)";
|
||||
$v $(INSTALL) -m 644 share/groff/* $(DESTDIR)$(datadir)/fish/groff/
|
||||
$v for i in $(wildcard share/man/man1/*.1); do \
|
||||
$(INSTALL) -m 644 $$i $(DESTDIR)$(datadir)/fish/man/man1/; \
|
||||
done;
|
||||
@@ -817,7 +818,7 @@ $(PCRE2_LIB): $(PCRE2_H)
|
||||
$v $(MAKE) V=$(V) -C $(PCRE2_DIR) libpcre2-$(PCRE2_WIDTH).la
|
||||
|
||||
$(PCRE2_H):
|
||||
@echo " autoconf $(em)$@$(sgr0)"
|
||||
@echo " autoconf $(em)$@$(sgr0)"
|
||||
$v (cd $(PCRE2_DIR) && ./config.status)
|
||||
|
||||
#
|
||||
@@ -1019,14 +1020,13 @@ obj/expand.o: src/complete.h src/env.h src/exec.h src/expand.h
|
||||
obj/expand.o: src/parse_constants.h src/iothread.h src/parse_util.h
|
||||
obj/expand.o: src/tokenizer.h src/path.h src/proc.h src/io.h src/parse_tree.h
|
||||
obj/expand.o: src/util.h src/wildcard.h src/wutil.h
|
||||
obj/fallback.o: config.h src/signal.h src/fallback.h src/util.h
|
||||
obj/fallback.o: config.h src/signal.h src/common.h src/fallback.h src/util.h
|
||||
obj/fish.o: config.h src/builtin.h src/common.h src/fallback.h src/signal.h
|
||||
obj/fish.o: src/env.h src/event.h src/expand.h src/parse_constants.h
|
||||
obj/fish.o: src/fish_version.h src/function.h src/history.h src/wutil.h
|
||||
obj/fish.o: src/input.h src/input_common.h src/io.h src/parser.h
|
||||
obj/fish.o: src/parse_tree.h src/tokenizer.h src/proc.h src/path.h
|
||||
obj/fish.o: src/reader.h src/complete.h src/highlight.h src/color.h
|
||||
obj/fish.o: src/wildcard.h
|
||||
obj/fish.o: src/input.h src/io.h src/parser.h src/parse_tree.h
|
||||
obj/fish.o: src/tokenizer.h src/proc.h src/path.h src/reader.h src/complete.h
|
||||
obj/fish.o: src/highlight.h src/color.h
|
||||
obj/fish_indent.o: config.h src/color.h src/common.h src/fallback.h
|
||||
obj/fish_indent.o: src/signal.h src/env.h src/fish_version.h src/highlight.h
|
||||
obj/fish_indent.o: src/input.h src/output.h src/parse_constants.h
|
||||
@@ -1135,8 +1135,8 @@ obj/sanity.o: src/wutil.h src/kill.h src/proc.h src/io.h src/parse_tree.h
|
||||
obj/sanity.o: src/parse_constants.h src/tokenizer.h src/reader.h
|
||||
obj/sanity.o: src/complete.h src/highlight.h src/color.h src/env.h
|
||||
obj/sanity.o: src/sanity.h
|
||||
obj/screen.o: config.h src/common.h src/fallback.h src/signal.h src/env.h
|
||||
obj/screen.o: src/highlight.h src/color.h src/output.h src/pager.h
|
||||
obj/screen.o: config.h src/common.h src/fallback.h src/signal.h
|
||||
obj/screen.o: src/highlight.h src/color.h src/env.h src/output.h src/pager.h
|
||||
obj/screen.o: src/complete.h src/reader.h src/parse_constants.h src/screen.h
|
||||
obj/screen.o: src/util.h
|
||||
obj/signal.o: config.h src/signal.h src/common.h src/fallback.h src/event.h
|
||||
@@ -1145,7 +1145,7 @@ obj/signal.o: src/tokenizer.h src/reader.h src/complete.h src/highlight.h
|
||||
obj/signal.o: src/color.h src/env.h src/wutil.h
|
||||
obj/tokenizer.o: config.h src/common.h src/fallback.h src/signal.h
|
||||
obj/tokenizer.o: src/tokenizer.h src/wutil.h
|
||||
obj/utf8.o: config.h src/utf8.h
|
||||
obj/utf8.o: config.h src/common.h src/fallback.h src/signal.h src/utf8.h
|
||||
obj/util.o: config.h src/common.h src/fallback.h src/signal.h src/util.h
|
||||
obj/util.o: src/wutil.h
|
||||
obj/wcstringutil.o: config.h src/common.h src/fallback.h src/signal.h
|
||||
|
||||
@@ -35,10 +35,14 @@ for arg in $argv
|
||||
set cppcheck_args $cppcheck_args $arg
|
||||
else if string match -q -- '-I*' $arg
|
||||
set cppcheck_args $cppcheck_args $arg
|
||||
else if string match -q -- '-iquote*' $arg
|
||||
set cppcheck_args $cppcheck_args $arg
|
||||
end
|
||||
end
|
||||
|
||||
# Not sure when this became necessary but without these flags cppcheck no longer works on macOS.
|
||||
# It complains that "Cppcheck cannot find all the include files." It appears that cppcheck used
|
||||
# to, but no longer, recognizes the -iquote flag. So switch to hardcoding the appropriate -I flags.
|
||||
set cppcheck_args $cppcheck_args -I . -I ./src
|
||||
|
||||
if test "$machine_type" = "x86_64"
|
||||
set cppcheck_args -D__x86_64__ -D__LP64__ $cppcheck_args
|
||||
end
|
||||
@@ -49,7 +53,8 @@ else
|
||||
# We haven't been asked to lint all the source. If there are uncommitted
|
||||
# changes lint those, else lint the files in the most recent commit.
|
||||
# Select (cached files) (modified but not cached, and untracked files)
|
||||
set files (git diff-index --cached HEAD --name-only) (git ls-files --exclude-standard --others --modified)
|
||||
set files (git diff-index --cached HEAD --name-only)
|
||||
set files $files (git ls-files --exclude-standard --others --modified)
|
||||
if not set -q files[1]
|
||||
# No pending changes so lint the files in the most recent commit.
|
||||
set files (git diff-tree --no-commit-id --name-only -r HEAD)
|
||||
@@ -75,9 +80,12 @@ if set -q c_files[1]
|
||||
for c_file in $c_files
|
||||
switch $kernel_name
|
||||
case Darwin
|
||||
include-what-you-use -Xiwyu --no_default_mappings -Xiwyu --mapping_file=build_tools/iwyu.osx.imp $cppcheck_args --std=c++11 $c_file 2>&1
|
||||
include-what-you-use -Xiwyu --no_default_mappings -Xiwyu \
|
||||
--mapping_file=build_tools/iwyu.osx.imp --std=c++11 \
|
||||
$cppcheck_args $c_file 2>&1
|
||||
case Linux
|
||||
include-what-you-use -Xiwyu --mapping_file=build_tools/iwyu.linux.imp $cppcheck_args $c_file 2>&1
|
||||
include-what-you-use -Xiwyu --mapping_file=build_tools/iwyu.linux.imp \
|
||||
$cppcheck_args $c_file 2>&1
|
||||
case '*' # hope for the best
|
||||
include-what-you-use $cppcheck_args $c_file 2>&1
|
||||
end
|
||||
@@ -92,7 +100,25 @@ if set -q c_files[1]
|
||||
# The stderr to stdout redirection is because cppcheck, incorrectly IMHO, writes its
|
||||
# diagnostic messages to stderr. Anyone running this who wants to capture its output will
|
||||
# expect those messages to be written to stdout.
|
||||
cppcheck -q --verbose --std=posix --language=c++ --template "[{file}:{line}]: {severity} ({id}): {message}" --suppress=missingIncludeSystem --inline-suppr --enable=$cppchecks --rule-file=.cppcheck.rule $cppcheck_args $c_files 2>&1
|
||||
set -l cn (set_color normal)
|
||||
set -l cb (set_color --bold)
|
||||
set -l cu (set_color --underline)
|
||||
set -l cm (set_color magenta)
|
||||
set -l cbrm (set_color brmagenta)
|
||||
set -l template "[$cb$cu{file}$cn$cb:{line}$cn] $cbrm{severity}$cm ({id}):$cn\n {message}"
|
||||
set cppcheck_args -q --verbose --std=posix --language=c++ --template $template \
|
||||
--suppress=missingIncludeSystem --inline-suppr --enable=$cppchecks \
|
||||
--rule-file=.cppcheck.rules --suppressions-list=.cppcheck.suppressions $cppcheck_args
|
||||
|
||||
cppcheck $cppcheck_args $c_files 2>&1
|
||||
|
||||
echo
|
||||
echo ========================================
|
||||
echo 'Running `cppcheck --check-config` to identify missing includes similar problems.'
|
||||
echo 'Ignore unmatchedSuppression warnings as they are probably false positives we'
|
||||
echo 'cannot suppress.'
|
||||
echo ========================================
|
||||
cppcheck $cppcheck_args --check-config $c_files 2>&1
|
||||
end
|
||||
|
||||
if type -q oclint
|
||||
@@ -105,7 +131,7 @@ if set -q c_files[1]
|
||||
# output will expect those messages to be written to stdout.
|
||||
if test "$kernel_name" = "Darwin"
|
||||
if not test -f compile_commands.json
|
||||
xcodebuild >xcodebuild.log
|
||||
xcodebuild -alltargets >xcodebuild.log
|
||||
oclint-xcodebuild xcodebuild.log >/dev/null
|
||||
end
|
||||
if test $all = yes
|
||||
|
||||
5
debian/control
vendored
5
debian/control
vendored
@@ -13,7 +13,7 @@ Vcs-Browser: https://github.com/fish-shell/fish-shell
|
||||
Package: fish
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, fish-common (= ${source:Version}), passwd (>= 4.0.3-10), bc, gettext-base, man-db
|
||||
Recommends: xsel (>=1.2.0), xdg-utils
|
||||
Recommends: xsel (>=1.2.0)
|
||||
Description: friendly interactive shell
|
||||
Fish is a command-line shell for modern systems, focusing on user-friendliness,
|
||||
sensibility and discoverability in interactive use. The syntax is simple, but
|
||||
@@ -22,7 +22,8 @@ Description: friendly interactive shell
|
||||
Package: fish-common
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}
|
||||
Recommends: fish, python (>=2.6), xdg-utils
|
||||
Recommends: fish, python (>=2.6)
|
||||
Suggests: xdg-utils
|
||||
Replaces: fish (<= 2.1.1.dfsg-2)
|
||||
Description: friendly interactive shell (architecture-independent files)
|
||||
Fish is a command-line shell for modern systems, focusing on user-friendliness,
|
||||
|
||||
@@ -2,39 +2,34 @@
|
||||
|
||||
\subsection alias-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
alias
|
||||
alias NAME DEFINITION
|
||||
alias NAME=DEFINITION
|
||||
\endfish
|
||||
|
||||
\subsection alias-description Description
|
||||
|
||||
`alias` is a simple wrapper for the `function` builtin. It exists for backwards compatibility with Posix shells. For other uses, it is recommended to define a <a href='#function'>function</a>.
|
||||
`alias` is a simple wrapper for the `function` builtin, which creates a function wrapping a command. It has similar syntax to POSIX shell `alias`. For other uses, it is recommended to define a <a href='#function'>function</a>.
|
||||
|
||||
`fish` does not keep track of which functions have been defined using `alias`. They must be erased using `functions -e`.
|
||||
`fish` marks functions that have been created by `alias` by including the command used to create them in the function description. You can list `alias`-created functions by running `alias` without arguments. They must be erased using `functions -e`.
|
||||
|
||||
- `NAME` is the name of the alias
|
||||
|
||||
- `DEFINITION` is the actual command to execute. The string `$argv` will be appended.
|
||||
|
||||
You cannot create an alias to a function with the same name.
|
||||
|
||||
Note that spaces need to be escaped in the call to alias just like in the commandline _even inside the quotes_.
|
||||
|
||||
You cannot create an alias to a function with the same name. Note that spaces need to be escaped in the call to `alias` just like at the command line, _even inside quoted parts_.
|
||||
|
||||
\subsection alias-example Example
|
||||
|
||||
The following code will create `rmi`, which runs `rm` with additional arguments on every invocation.
|
||||
|
||||
\fish
|
||||
alias rmi "rm -i"
|
||||
alias rmi="rm -i"
|
||||
|
||||
# This is equivalent to entering the following function:
|
||||
|
||||
function rmi
|
||||
function rmi --wraps rm --description 'alias rmi=rm -i'
|
||||
rm -i $argv
|
||||
end
|
||||
|
||||
# This needs to have the spaces escaped or "Chrome.app..." will be seen as an argument to "/Applications/Google":
|
||||
|
||||
alias chrome='/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome banana'
|
||||
\endfish
|
||||
|
||||
@@ -13,6 +13,8 @@ If a `SECTION` is specified, the help for that command is shown.
|
||||
|
||||
If the BROWSER environment variable is set, it will be used to display the documentation. Otherwise, fish will search for a suitable browser.
|
||||
|
||||
If you prefer to use a different browser (other than as described above) for fish help, you can set the fish_help_browser variable. This variable may be set as an array, where the first element is the browser command and the rest are browser options.
|
||||
|
||||
Note that most builtin commands display their help in the terminal when given the `--help` option.
|
||||
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@ history ( -h | --help )
|
||||
|
||||
`history` is used to search, delete, and otherwise manipulate the history of interactive commands.
|
||||
|
||||
Note that for backwards compatibility each subcommand can also be specified as a long option. For example, rather than `history search` you can type `history --search`. Those long options are deprecated and will be removed in a future release.
|
||||
|
||||
The following operations (sub-commands) are available:
|
||||
|
||||
- `search` returns history items matching the search string. If no search string is provided it returns all history items. This is the default operation if no other operation is specified. You only have to explicitly say `history search` if you wish to search for one of the subcommands. The `--contains` search option will be used if you don't specify a different search option. Entries are ordered newest to oldest. If stdout is attached to a tty the output will be piped through your pager by the history function. The history builtin simply writes the results to stdout.
|
||||
@@ -60,9 +58,10 @@ history --search --contains "foo"
|
||||
history --delete --prefix "foo"
|
||||
# Interactively deletes commands which start with "foo" from the history.
|
||||
# You can select more than one entry by entering their IDs seperated by a space.
|
||||
\endfish
|
||||
|
||||
\subsection history-notes Notes
|
||||
|
||||
If you specify both `--prefix` and `--contains` the last flag seen is used.
|
||||
|
||||
\endfish
|
||||
Note that for backwards compatibility each subcommand can also be specified as a long option. For example, rather than `history search` you can type `history --search`. Those long options are deprecated and will be removed in a future release.
|
||||
|
||||
@@ -977,7 +977,7 @@ Some bindings are shared between emacs- and vi-mode because they aren't text edi
|
||||
|
||||
- @key{Alt,↑,Up} and @key{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.
|
||||
|
||||
- @key{Control,C} deletes the entire line.
|
||||
- @key{Control,C} cancels the entire line.
|
||||
|
||||
- @key{Control,D} delete one character to the right of the cursor. If the command line is empty, @key{Control,D} will exit fish.
|
||||
|
||||
@@ -987,6 +987,8 @@ Some bindings are shared between emacs- and vi-mode because they aren't text edi
|
||||
|
||||
- @key{Control,W} moves the previous path component (everything up to the previous "/") to the <a href="#killring">killring</a>.
|
||||
|
||||
- @key{Control,X} copies the current buffer to the system's clipboard, @key{Control,V} inserts the clipboard contents.
|
||||
|
||||
- @key{Alt,D} moves the next word to the <a href="#killring">killring</a>.
|
||||
|
||||
- @key{Alt,H} (or @key{F1}) shows the manual page for the current command, if one exists.
|
||||
@@ -1068,16 +1070,11 @@ Command mode is also known as normal mode.
|
||||
|
||||
- @key{[} and @key{]} search the command history for the previous/next token containing the token under the cursor before the search was started. See the <a href='#history'>history</a> section for more information on history searching.
|
||||
|
||||
- @key{Control, X} copies the current buffer to the system's clipboard, @key{Control, V} inserts the clipboard contents.
|
||||
- @key{Control,C} deletes the entire line.
|
||||
|
||||
- @key{Backspace} moves the cursor left.
|
||||
|
||||
\subsubsection vi-mode-insert Insert mode
|
||||
|
||||
- @key{Escape} or @key{Control,C} enters <a href="#vi-mode-command">command mode</a>.
|
||||
|
||||
- @key{Control,x} moves the cursor to the end of the line. If an autosuggestion is available, it will be accepted completely.
|
||||
- @key{Escape} enters <a href="#vi-mode-command">command mode</a>.
|
||||
|
||||
- @key{Backspace} removes one character to the left.
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ open FILES...
|
||||
|
||||
`open` opens a file in its default application, using the appropriate tool for the operating system. On GNU/Linux, this requires the common but optional `xdg-open` utility, from the `xdg-utils` package.
|
||||
|
||||
Note that this function will not be used if a command by this name exists (which is the case on macOS or Haiku).
|
||||
|
||||
|
||||
\subsection open-example Example
|
||||
|
||||
|
||||
@@ -2,33 +2,50 @@
|
||||
|
||||
\subsection status-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
status [OPTION]
|
||||
status
|
||||
status is-login
|
||||
status is-interactive
|
||||
status is-block
|
||||
status is-command-substitution
|
||||
status is-no-job-control
|
||||
status is-full-job-control
|
||||
status is-interactive-job-control
|
||||
status current-filename
|
||||
status current-line-number
|
||||
status print-stack-trace
|
||||
status job-control CONTROL-TYPE
|
||||
\endfish
|
||||
|
||||
\subsection status-description Description
|
||||
|
||||
With no arguments, `status` displays a summary of the current login and job control status of the shell.
|
||||
|
||||
The following options are available:
|
||||
The following operations (sub-commands) are available:
|
||||
|
||||
- `-c` or `--is-command-substitution` returns 0 if fish is currently executing a command substitution.
|
||||
- `is-command-sub` returns 0 if fish is currently executing a command substitution. Also `-c` or `--is-command-substitution`.
|
||||
|
||||
- `-b` or `--is-block` returns 0 if fish is currently executing a block of code.
|
||||
- `is-block` returns 0 if fish is currently executing a block of code. Also `-b` or `--is-block`.
|
||||
|
||||
- `-i` or `--is-interactive` returns 0 if fish is interactive - that is, connected to a keyboard.
|
||||
- `is-interactive` returns 0 if fish is interactive - that is, connected to a keyboard. Also `-i` or `--is-interactive`.
|
||||
|
||||
- `-l` or `--is-login` returns 0 if fish is a login shell - that is, if fish should perform login tasks such as setting up the PATH.
|
||||
- `is-login` returns 0 if fish is a login shell - that is, if fish should perform login tasks such as setting up the PATH. Also `-l` or `--is-login`.
|
||||
|
||||
- `--is-full-job-control` returns 0 if full job control is enabled.
|
||||
- `is-full-job-control` returns 0 if full job control is enabled. Also `--is-full-job-control` (no short flag).
|
||||
|
||||
- `--is-interactive-job-control` returns 0 if interactive job control is enabled.
|
||||
- `is-interactive-job-control` returns 0 if interactive job control is enabled. Also, `--is-interactive-job-control` (no short flag).
|
||||
|
||||
- `--is-no-job-control` returns 0 if no job control is enabled.
|
||||
- `is-no-job-control` returns 0 if no job control is enabled. Also `--is-no-job-control` (no short flag).
|
||||
|
||||
- `-f` or `--current-filename` prints the filename of the currently running script.
|
||||
- `current-filename` prints the filename of the currently running script. Also `-f` or `--current-filename`.
|
||||
|
||||
- `-n` or `--current-line-number` prints the line number of the currently running script.
|
||||
- `current-line-number` prints the line number of the currently running script. Also `-n` or `--current-line-number`.
|
||||
|
||||
- `-j CONTROLTYPE` or `--job-control=CONTROLTYPE` sets the job control type, which can be `none`, `full`, or `interactive`.
|
||||
- `job-control CONTROL-TYPE` sets the job control type, which can be `none`, `full`, or `interactive`. Also `-j CONTROL-TYPE` or `--job-control=CONTROL-TYPE`.
|
||||
|
||||
- `-t` or `--print-stack-trace` prints a stack trace of all function calls on the call stack.
|
||||
- `print-stack-trace` prints a stack trace of all function calls on the call stack. Also `-t` or `--print-stack-trace`.
|
||||
|
||||
\subsection status-notes Notes
|
||||
|
||||
For backwards compatibility each subcommand can also be specified as a long or short option. For example, rather than `status is-login` you can type `status --is-login`. The flag forms are deprecated and may be removed in a future release (but not before fish 3.0).
|
||||
|
||||
You can only specify one subcommand per invocation even if you use the flag form of the subcommand.
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
D01A2C9B16964C8200767098 /* Copy Files */,
|
||||
);
|
||||
dependencies = (
|
||||
9C7A55801DCD73930049C25D /* PBXTargetDependency */,
|
||||
D0F01A1315AA36280034B3B1 /* PBXTargetDependency */,
|
||||
D0F01A1715AA36300034B3B1 /* PBXTargetDependency */,
|
||||
D0A564EF168D09C000AF6161 /* PBXTargetDependency */,
|
||||
@@ -67,6 +68,72 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
63A2C0E91CC60F3B00973404 /* pcre2_find_bracket.c in Sources */ = {isa = PBXBuildFile; fileRef = 63A2C0E81CC5F9FB00973404 /* pcre2_find_bracket.c */; };
|
||||
9C7A55271DCD651F0049C25D /* fallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853E13B3ACEE0099B651 /* fallback.cpp */; };
|
||||
9C7A55281DCD65540049C25D /* builtin_commandline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853013B3ACEE0099B651 /* builtin_commandline.cpp */; };
|
||||
9C7A55291DCD65540049C25D /* builtin_complete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853113B3ACEE0099B651 /* builtin_complete.cpp */; };
|
||||
9C7A552A1DCD65540049C25D /* builtin_jobs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853213B3ACEE0099B651 /* builtin_jobs.cpp */; };
|
||||
9C7A552B1DCD65540049C25D /* builtin_set.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853313B3ACEE0099B651 /* builtin_set.cpp */; };
|
||||
9C7A552C1DCD65540049C25D /* builtin_set_color.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C861EA16CC7054003B5A04 /* builtin_set_color.cpp */; };
|
||||
9C7A552D1DCD65540049C25D /* builtin_ulimit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853413B3ACEE0099B651 /* builtin_ulimit.cpp */; };
|
||||
9C7A552E1DCD65540049C25D /* builtin_printf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0CA63F316FC275F00093BD4 /* builtin_printf.cpp */; };
|
||||
9C7A552F1DCD65820049C25D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855E13B3ACEE0099B651 /* util.cpp */; };
|
||||
9C7A55361DCD71330049C25D /* autoload.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C6FCC914CFA4B0004CE8AD /* autoload.cpp */; };
|
||||
9C7A55371DCD71330049C25D /* builtin_commandline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853013B3ACEE0099B651 /* builtin_commandline.cpp */; };
|
||||
9C7A55381DCD71330049C25D /* builtin_complete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853113B3ACEE0099B651 /* builtin_complete.cpp */; };
|
||||
9C7A55391DCD71330049C25D /* builtin_jobs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853213B3ACEE0099B651 /* builtin_jobs.cpp */; };
|
||||
9C7A553A1DCD71330049C25D /* builtin_set.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853313B3ACEE0099B651 /* builtin_set.cpp */; };
|
||||
9C7A553B1DCD71330049C25D /* builtin_set_color.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C861EA16CC7054003B5A04 /* builtin_set_color.cpp */; };
|
||||
9C7A553C1DCD71330049C25D /* builtin_ulimit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853413B3ACEE0099B651 /* builtin_ulimit.cpp */; };
|
||||
9C7A553D1DCD71330049C25D /* builtin_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0F3373A1506DE3C00ECEFC0 /* builtin_test.cpp */; };
|
||||
9C7A553E1DCD71330049C25D /* builtin_printf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0CA63F316FC275F00093BD4 /* builtin_printf.cpp */; };
|
||||
9C7A553F1DCD71330049C25D /* builtin_string.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D04F7F7B1BA4BF4000B0F227 /* builtin_string.cpp */; };
|
||||
9C7A55401DCD71330049C25D /* color.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0B6B0FE14E88BA400AD6C10 /* color.cpp */; };
|
||||
9C7A55411DCD71330049C25D /* common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853613B3ACEE0099B651 /* common.cpp */; };
|
||||
9C7A55421DCD71330049C25D /* event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853B13B3ACEE0099B651 /* event.cpp */; };
|
||||
9C7A55431DCD71330049C25D /* input_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854913B3ACEE0099B651 /* input_common.cpp */; };
|
||||
9C7A55441DCD71330049C25D /* io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854C13B3ACEE0099B651 /* io.cpp */; };
|
||||
9C7A55451DCD71330049C25D /* iothread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854D13B3ACEE0099B651 /* iothread.cpp */; };
|
||||
9C7A55461DCD71330049C25D /* parse_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855213B3ACEE0099B651 /* parse_util.cpp */; };
|
||||
9C7A55471DCD71330049C25D /* path.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855513B3ACEE0099B651 /* path.cpp */; };
|
||||
9C7A55481DCD71330049C25D /* parse_execution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D052D8091868F7FC003ABCBD /* parse_execution.cpp */; };
|
||||
9C7A55491DCD71330049C25D /* postfork.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D09B1C1914FC7B5B00F91077 /* postfork.cpp */; };
|
||||
9C7A554A1DCD71330049C25D /* screen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855A13B3ACEE0099B651 /* screen.cpp */; };
|
||||
9C7A554B1DCD71330049C25D /* signal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855C13B3ACEE0099B651 /* signal.cpp */; };
|
||||
9C7A554C1DCD71330049C25D /* utf8.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C9733718DE5449002D7C81 /* utf8.cpp */; };
|
||||
9C7A554D1DCD71330049C25D /* builtin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853513B3ACEE0099B651 /* builtin.cpp */; };
|
||||
9C7A554E1DCD71330049C25D /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854413B3ACEE0099B651 /* function.cpp */; };
|
||||
9C7A554F1DCD71330049C25D /* complete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853713B3ACEE0099B651 /* complete.cpp */; };
|
||||
9C7A55501DCD71330049C25D /* env.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853A13B3ACEE0099B651 /* env.cpp */; };
|
||||
9C7A55511DCD71330049C25D /* exec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853C13B3ACEE0099B651 /* exec.cpp */; };
|
||||
9C7A55521DCD71330049C25D /* wcstringutil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0F5B46319CFCDE80090665E /* wcstringutil.cpp */; };
|
||||
9C7A55531DCD71330049C25D /* expand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853D13B3ACEE0099B651 /* expand.cpp */; };
|
||||
9C7A55541DCD71330049C25D /* fallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853E13B3ACEE0099B651 /* fallback.cpp */; };
|
||||
9C7A55551DCD71330049C25D /* fish_version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D00F63F019137E9D00FCCDEC /* fish_version.cpp */; settings = {COMPILER_FLAGS = "-I$(DERIVED_FILE_DIR)"; }; };
|
||||
9C7A55561DCD71330049C25D /* highlight.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854713B3ACEE0099B651 /* highlight.cpp */; };
|
||||
9C7A55571DCD71330049C25D /* history.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854813B3ACEE0099B651 /* history.cpp */; };
|
||||
9C7A55581DCD71330049C25D /* kill.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854F13B3ACEE0099B651 /* kill.cpp */; };
|
||||
9C7A55591DCD71330049C25D /* parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855413B3ACEE0099B651 /* parser.cpp */; };
|
||||
9C7A555A1DCD71330049C25D /* parser_keywords.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855313B3ACEE0099B651 /* parser_keywords.cpp */; };
|
||||
9C7A555B1DCD71330049C25D /* proc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855713B3ACEE0099B651 /* proc.cpp */; };
|
||||
9C7A555C1DCD71330049C25D /* reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855813B3ACEE0099B651 /* reader.cpp */; };
|
||||
9C7A555D1DCD71330049C25D /* sanity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855913B3ACEE0099B651 /* sanity.cpp */; };
|
||||
9C7A555E1DCD71330049C25D /* tokenizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855D13B3ACEE0099B651 /* tokenizer.cpp */; };
|
||||
9C7A555F1DCD71330049C25D /* wildcard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0856013B3ACEE0099B651 /* wildcard.cpp */; };
|
||||
9C7A55601DCD71330049C25D /* wgetopt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855F13B3ACEE0099B651 /* wgetopt.cpp */; };
|
||||
9C7A55611DCD71330049C25D /* wutil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0856113B3ACEE0099B651 /* wutil.cpp */; };
|
||||
9C7A55621DCD71330049C25D /* input.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854A13B3ACEE0099B651 /* input.cpp */; };
|
||||
9C7A55631DCD71330049C25D /* output.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855113B3ACEE0099B651 /* output.cpp */; };
|
||||
9C7A55641DCD71330049C25D /* intern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854B13B3ACEE0099B651 /* intern.cpp */; };
|
||||
9C7A55651DCD71330049C25D /* env_universal_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853813B3ACEE0099B651 /* env_universal_common.cpp */; };
|
||||
9C7A55661DCD71330049C25D /* pager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D03238891849D1980032CF2C /* pager.cpp */; };
|
||||
9C7A55681DCD71330049C25D /* parse_tree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C52F351765284C00BFAB82 /* parse_tree.cpp */; };
|
||||
9C7A55691DCD71330049C25D /* parse_productions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0FE8EE7179FB75F008C9F21 /* parse_productions.cpp */; };
|
||||
9C7A556A1DCD71330049C25D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855E13B3ACEE0099B651 /* util.cpp */; };
|
||||
9C7A556C1DCD71330049C25D /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D02A8C15983CFA008E62BD /* libncurses.dylib */; };
|
||||
9C7A556D1DCD71330049C25D /* libpcre2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D04F7FD01BA4E29300B0F227 /* libpcre2.a */; };
|
||||
9C7A557D1DCD71890049C25D /* fish_key_reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9C7A557C1DCD717C0049C25D /* fish_key_reader.cpp */; };
|
||||
9C7A557E1DCD71CD0049C25D /* print_help.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855613B3ACEE0099B651 /* print_help.cpp */; };
|
||||
9C7A55811DCD739C0049C25D /* fish_key_reader in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9C7A55721DCD71330049C25D /* fish_key_reader */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
D00769121990137800CA4627 /* autoload.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C6FCC914CFA4B0004CE8AD /* autoload.cpp */; };
|
||||
D00769131990137800CA4627 /* builtin_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0F3373A1506DE3C00ECEFC0 /* builtin_test.cpp */; };
|
||||
D00769141990137800CA4627 /* color.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0B6B0FE14E88BA400AD6C10 /* color.cpp */; };
|
||||
@@ -286,6 +353,27 @@
|
||||
/* End PBXBuildRule section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
9C7A55321DCD71330049C25D /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D0A084F213B3AC130099B651 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = D008D0C41BC58F8800841177;
|
||||
remoteInfo = "generate-version-header";
|
||||
};
|
||||
9C7A55341DCD71330049C25D /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D0A084F213B3AC130099B651 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = D04F7FCF1BA4E29300B0F227;
|
||||
remoteInfo = libpcre2.a;
|
||||
};
|
||||
9C7A557F1DCD73930049C25D /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D0A084F213B3AC130099B651 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 9C7A55301DCD71330049C25D;
|
||||
remoteInfo = fish_key_reader;
|
||||
};
|
||||
D008D0CA1BC58FDD00841177 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D0A084F213B3AC130099B651 /* Project object */;
|
||||
@@ -438,6 +526,7 @@
|
||||
dstPath = base/bin;
|
||||
dstSubfolderSpec = 1;
|
||||
files = (
|
||||
9C7A55811DCD739C0049C25D /* fish_key_reader in CopyFiles */,
|
||||
D0F019F115A977140034B3B1 /* fish in CopyFiles */,
|
||||
D0F019F315A977290034B3B1 /* fish_indent in CopyFiles */,
|
||||
);
|
||||
@@ -468,6 +557,17 @@
|
||||
/* Begin PBXFileReference section */
|
||||
4E142D731B56B5D7008783C8 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = config.h; path = ../osx/config.h; sourceTree = "<group>"; };
|
||||
63A2C0E81CC5F9FB00973404 /* pcre2_find_bracket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pcre2_find_bracket.c; sourceTree = "<group>"; };
|
||||
9C7A55721DCD71330049C25D /* fish_key_reader */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fish_key_reader; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9C7A55731DCD716F0049C25D /* builtin_commandline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_commandline.h; sourceTree = "<group>"; };
|
||||
9C7A55741DCD716F0049C25D /* builtin_complete.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_complete.h; sourceTree = "<group>"; };
|
||||
9C7A55751DCD716F0049C25D /* builtin_jobs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_jobs.h; sourceTree = "<group>"; };
|
||||
9C7A55761DCD716F0049C25D /* builtin_printf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_printf.h; sourceTree = "<group>"; };
|
||||
9C7A55771DCD716F0049C25D /* builtin_set_color.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_set_color.h; sourceTree = "<group>"; };
|
||||
9C7A55781DCD716F0049C25D /* builtin_set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_set.h; sourceTree = "<group>"; };
|
||||
9C7A55791DCD716F0049C25D /* builtin_string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_string.h; sourceTree = "<group>"; };
|
||||
9C7A557A1DCD716F0049C25D /* builtin_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_test.h; sourceTree = "<group>"; };
|
||||
9C7A557B1DCD716F0049C25D /* builtin_ulimit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_ulimit.h; sourceTree = "<group>"; };
|
||||
9C7A557C1DCD717C0049C25D /* fish_key_reader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fish_key_reader.cpp; sourceTree = "<group>"; };
|
||||
D00769421990137800CA4627 /* fish_tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fish_tests; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D00F63F019137E9D00FCCDEC /* fish_version.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fish_version.cpp; sourceTree = "<group>"; };
|
||||
D01A2D23169B730A00767098 /* man1 */ = {isa = PBXFileReference; lastKnownFileType = text; name = man1; path = pages_for_manpath/man1; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -618,6 +718,15 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
9C7A556B1DCD71330049C25D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9C7A556C1DCD71330049C25D /* libncurses.dylib in Frameworks */,
|
||||
9C7A556D1DCD71330049C25D /* libpcre2.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D007693C1990137800CA4627 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -743,6 +852,16 @@
|
||||
D0D02A91159845EF008E62BD /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9C7A557C1DCD717C0049C25D /* fish_key_reader.cpp */,
|
||||
9C7A55731DCD716F0049C25D /* builtin_commandline.h */,
|
||||
9C7A55741DCD716F0049C25D /* builtin_complete.h */,
|
||||
9C7A55751DCD716F0049C25D /* builtin_jobs.h */,
|
||||
9C7A55761DCD716F0049C25D /* builtin_printf.h */,
|
||||
9C7A55771DCD716F0049C25D /* builtin_set_color.h */,
|
||||
9C7A55781DCD716F0049C25D /* builtin_set.h */,
|
||||
9C7A55791DCD716F0049C25D /* builtin_string.h */,
|
||||
9C7A557A1DCD716F0049C25D /* builtin_test.h */,
|
||||
9C7A557B1DCD716F0049C25D /* builtin_ulimit.h */,
|
||||
4E142D731B56B5D7008783C8 /* config.h */,
|
||||
D0C6FCCB14CFA4B7004CE8AD /* autoload.h */,
|
||||
D0C6FCC914CFA4B0004CE8AD /* autoload.cpp */,
|
||||
@@ -888,6 +1007,7 @@
|
||||
D0D02AD01598642A008E62BD /* fish_indent */,
|
||||
D00769421990137800CA4627 /* fish_tests */,
|
||||
D04F7FD01BA4E29300B0F227 /* libpcre2.a */,
|
||||
9C7A55721DCD71330049C25D /* fish_key_reader */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -905,6 +1025,24 @@
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
9C7A55301DCD71330049C25D /* fish_key_reader */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 9C7A556E1DCD71330049C25D /* Build configuration list for PBXNativeTarget "fish_key_reader" */;
|
||||
buildPhases = (
|
||||
9C7A55351DCD71330049C25D /* Sources */,
|
||||
9C7A556B1DCD71330049C25D /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
9C7A55311DCD71330049C25D /* PBXTargetDependency */,
|
||||
9C7A55331DCD71330049C25D /* PBXTargetDependency */,
|
||||
);
|
||||
name = fish_key_reader;
|
||||
productName = fish_Xcode;
|
||||
productReference = 9C7A55721DCD71330049C25D /* fish_key_reader */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
D00769101990137800CA4627 /* fish_tests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D007693E1990137800CA4627 /* Build configuration list for PBXNativeTarget "fish_tests" */;
|
||||
@@ -1031,6 +1169,7 @@
|
||||
D00769101990137800CA4627 /* fish_tests */,
|
||||
D04F7FCF1BA4E29300B0F227 /* pcre2 */,
|
||||
D008D0C41BC58F8800841177 /* generate-version-header */,
|
||||
9C7A55301DCD71330049C25D /* fish_key_reader */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -1226,10 +1365,80 @@
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
9C7A55351DCD71330049C25D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9C7A557E1DCD71CD0049C25D /* print_help.cpp in Sources */,
|
||||
9C7A557D1DCD71890049C25D /* fish_key_reader.cpp in Sources */,
|
||||
9C7A55361DCD71330049C25D /* autoload.cpp in Sources */,
|
||||
9C7A55371DCD71330049C25D /* builtin_commandline.cpp in Sources */,
|
||||
9C7A55381DCD71330049C25D /* builtin_complete.cpp in Sources */,
|
||||
9C7A55391DCD71330049C25D /* builtin_jobs.cpp in Sources */,
|
||||
9C7A553A1DCD71330049C25D /* builtin_set.cpp in Sources */,
|
||||
9C7A553B1DCD71330049C25D /* builtin_set_color.cpp in Sources */,
|
||||
9C7A553C1DCD71330049C25D /* builtin_ulimit.cpp in Sources */,
|
||||
9C7A553D1DCD71330049C25D /* builtin_test.cpp in Sources */,
|
||||
9C7A553E1DCD71330049C25D /* builtin_printf.cpp in Sources */,
|
||||
9C7A553F1DCD71330049C25D /* builtin_string.cpp in Sources */,
|
||||
9C7A55401DCD71330049C25D /* color.cpp in Sources */,
|
||||
9C7A55411DCD71330049C25D /* common.cpp in Sources */,
|
||||
9C7A55421DCD71330049C25D /* event.cpp in Sources */,
|
||||
9C7A55431DCD71330049C25D /* input_common.cpp in Sources */,
|
||||
9C7A55441DCD71330049C25D /* io.cpp in Sources */,
|
||||
9C7A55451DCD71330049C25D /* iothread.cpp in Sources */,
|
||||
9C7A55461DCD71330049C25D /* parse_util.cpp in Sources */,
|
||||
9C7A55471DCD71330049C25D /* path.cpp in Sources */,
|
||||
9C7A55481DCD71330049C25D /* parse_execution.cpp in Sources */,
|
||||
9C7A55491DCD71330049C25D /* postfork.cpp in Sources */,
|
||||
9C7A554A1DCD71330049C25D /* screen.cpp in Sources */,
|
||||
9C7A554B1DCD71330049C25D /* signal.cpp in Sources */,
|
||||
9C7A554C1DCD71330049C25D /* utf8.cpp in Sources */,
|
||||
9C7A554D1DCD71330049C25D /* builtin.cpp in Sources */,
|
||||
9C7A554E1DCD71330049C25D /* function.cpp in Sources */,
|
||||
9C7A554F1DCD71330049C25D /* complete.cpp in Sources */,
|
||||
9C7A55501DCD71330049C25D /* env.cpp in Sources */,
|
||||
9C7A55511DCD71330049C25D /* exec.cpp in Sources */,
|
||||
9C7A55521DCD71330049C25D /* wcstringutil.cpp in Sources */,
|
||||
9C7A55531DCD71330049C25D /* expand.cpp in Sources */,
|
||||
9C7A55541DCD71330049C25D /* fallback.cpp in Sources */,
|
||||
9C7A55551DCD71330049C25D /* fish_version.cpp in Sources */,
|
||||
9C7A55561DCD71330049C25D /* highlight.cpp in Sources */,
|
||||
9C7A55571DCD71330049C25D /* history.cpp in Sources */,
|
||||
9C7A55581DCD71330049C25D /* kill.cpp in Sources */,
|
||||
9C7A55591DCD71330049C25D /* parser.cpp in Sources */,
|
||||
9C7A555A1DCD71330049C25D /* parser_keywords.cpp in Sources */,
|
||||
9C7A555B1DCD71330049C25D /* proc.cpp in Sources */,
|
||||
9C7A555C1DCD71330049C25D /* reader.cpp in Sources */,
|
||||
9C7A555D1DCD71330049C25D /* sanity.cpp in Sources */,
|
||||
9C7A555E1DCD71330049C25D /* tokenizer.cpp in Sources */,
|
||||
9C7A555F1DCD71330049C25D /* wildcard.cpp in Sources */,
|
||||
9C7A55601DCD71330049C25D /* wgetopt.cpp in Sources */,
|
||||
9C7A55611DCD71330049C25D /* wutil.cpp in Sources */,
|
||||
9C7A55621DCD71330049C25D /* input.cpp in Sources */,
|
||||
9C7A55631DCD71330049C25D /* output.cpp in Sources */,
|
||||
9C7A55641DCD71330049C25D /* intern.cpp in Sources */,
|
||||
9C7A55651DCD71330049C25D /* env_universal_common.cpp in Sources */,
|
||||
9C7A55661DCD71330049C25D /* pager.cpp in Sources */,
|
||||
9C7A55681DCD71330049C25D /* parse_tree.cpp in Sources */,
|
||||
9C7A55691DCD71330049C25D /* parse_productions.cpp in Sources */,
|
||||
9C7A556A1DCD71330049C25D /* util.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D00769111990137800CA4627 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9C7A552F1DCD65820049C25D /* util.cpp in Sources */,
|
||||
9C7A55281DCD65540049C25D /* builtin_commandline.cpp in Sources */,
|
||||
9C7A55291DCD65540049C25D /* builtin_complete.cpp in Sources */,
|
||||
9C7A552A1DCD65540049C25D /* builtin_jobs.cpp in Sources */,
|
||||
9C7A552B1DCD65540049C25D /* builtin_set.cpp in Sources */,
|
||||
9C7A552C1DCD65540049C25D /* builtin_set_color.cpp in Sources */,
|
||||
9C7A552D1DCD65540049C25D /* builtin_ulimit.cpp in Sources */,
|
||||
9C7A552E1DCD65540049C25D /* builtin_printf.cpp in Sources */,
|
||||
9C7A55271DCD651F0049C25D /* fallback.cpp in Sources */,
|
||||
D00769121990137800CA4627 /* autoload.cpp in Sources */,
|
||||
D00769131990137800CA4627 /* builtin_test.cpp in Sources */,
|
||||
D00769141990137800CA4627 /* color.cpp in Sources */,
|
||||
@@ -1440,6 +1649,21 @@
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
9C7A55311DCD71330049C25D /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D008D0C41BC58F8800841177 /* generate-version-header */;
|
||||
targetProxy = 9C7A55321DCD71330049C25D /* PBXContainerItemProxy */;
|
||||
};
|
||||
9C7A55331DCD71330049C25D /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D04F7FCF1BA4E29300B0F227 /* pcre2 */;
|
||||
targetProxy = 9C7A55341DCD71330049C25D /* PBXContainerItemProxy */;
|
||||
};
|
||||
9C7A55801DCD73930049C25D /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 9C7A55301DCD71330049C25D /* fish_key_reader */;
|
||||
targetProxy = 9C7A557F1DCD73930049C25D /* PBXContainerItemProxy */;
|
||||
};
|
||||
D008D0CB1BC58FDD00841177 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D008D0C41BC58F8800841177 /* generate-version-header */;
|
||||
@@ -1503,6 +1727,42 @@
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
9C7A556F1DCD71330049C25D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
LLVM_LTO = NO;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
9C7A55701DCD71330049C25D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
LLVM_LTO = YES_THIN;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
9C7A55711DCD71330049C25D /* Release_C++11 */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
LLVM_LTO = YES_THIN;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = "Release_C++11";
|
||||
};
|
||||
D007693F1990137800CA4627 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -1511,6 +1771,7 @@
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
LLVM_LTO = NO;
|
||||
PRODUCT_NAME = fish_tests;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -1523,6 +1784,7 @@
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
LLVM_LTO = YES_THIN;
|
||||
PRODUCT_NAME = fish_tests;
|
||||
};
|
||||
name = Release;
|
||||
@@ -1535,6 +1797,7 @@
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
LLVM_LTO = YES_THIN;
|
||||
PRODUCT_NAME = fish_tests;
|
||||
};
|
||||
name = "Release_C++11";
|
||||
@@ -1619,6 +1882,7 @@
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
INFOPLIST_FILE = osx/Info.plist;
|
||||
LLVM_LTO = YES_THIN;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ridiculousfish.fish-shell";
|
||||
PRODUCT_NAME = fish;
|
||||
WRAPPER_EXTENSION = app;
|
||||
@@ -1632,6 +1896,7 @@
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
LLVM_LTO = YES_THIN;
|
||||
PRODUCT_NAME = fish;
|
||||
};
|
||||
name = "Release_C++11";
|
||||
@@ -1644,6 +1909,7 @@
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
LLVM_LTO = YES_THIN;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = "Release_C++11";
|
||||
@@ -1694,6 +1960,7 @@
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
|
||||
GCC_WARN_UNUSED_VARIABLE = NO;
|
||||
LLVM_LTO = NO;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/osx/pcre2 $(SRCROOT)/osx/shared_headers/";
|
||||
@@ -1719,6 +1986,7 @@
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
|
||||
GCC_WARN_UNUSED_VARIABLE = NO;
|
||||
LLVM_LTO = YES_THIN;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/osx/pcre2 $(SRCROOT)/osx/shared_headers/";
|
||||
@@ -1744,6 +2012,7 @@
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
|
||||
GCC_WARN_UNUSED_VARIABLE = NO;
|
||||
LLVM_LTO = YES_THIN;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/osx/pcre2 $(SRCROOT)/osx/shared_headers/";
|
||||
@@ -1900,6 +2169,7 @@
|
||||
);
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
INFOPLIST_FILE = osx/Info.plist;
|
||||
LLVM_LTO = NO;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ridiculousfish.fish-shell";
|
||||
PRODUCT_NAME = fish;
|
||||
WRAPPER_EXTENSION = app;
|
||||
@@ -1917,6 +2187,7 @@
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
INFOPLIST_FILE = osx/Info.plist;
|
||||
LLVM_LTO = YES_THIN;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ridiculousfish.fish-shell";
|
||||
PRODUCT_NAME = fish;
|
||||
WRAPPER_EXTENSION = app;
|
||||
@@ -1935,6 +2206,7 @@
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
LLVM_LTO = NO;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -1947,6 +2219,7 @@
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
LLVM_LTO = YES_THIN;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
@@ -1958,6 +2231,7 @@
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
LLVM_LTO = NO;
|
||||
PRODUCT_NAME = fish;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -1969,6 +2243,7 @@
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
LLVM_LTO = YES_THIN;
|
||||
PRODUCT_NAME = fish;
|
||||
};
|
||||
name = Release;
|
||||
@@ -1996,6 +2271,16 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
9C7A556E1DCD71330049C25D /* Build configuration list for PBXNativeTarget "fish_key_reader" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
9C7A556F1DCD71330049C25D /* Debug */,
|
||||
9C7A55701DCD71330049C25D /* Release */,
|
||||
9C7A55711DCD71330049C25D /* Release_C++11 */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D007693E1990137800CA4627 /* Build configuration list for PBXNativeTarget "fish_tests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.3.900</string>
|
||||
<string>2.4.500</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.1</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#define HAVE_BACKTRACE_SYMBOLS 1
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
/* #undef HAVE_CLOCK_GETTIME */
|
||||
#define HAVE_CLOCK_GETTIME 1
|
||||
|
||||
/* Define to 1 if you have the <curses.h> header file. */
|
||||
#define HAVE_CURSES_H 1
|
||||
@@ -51,7 +51,7 @@
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `mkostemp' function. */
|
||||
/* #undef HAVE_MKOSTEMP */
|
||||
#define HAVE_MKOSTEMP 1
|
||||
|
||||
/* Define to 1 if you have the <ncurses/curses.h> header file. */
|
||||
/* #undef HAVE_NCURSES_CURSES_H */
|
||||
@@ -167,7 +167,7 @@
|
||||
#define PACKAGE_NAME "fish"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "fish 2.4b1"
|
||||
#define PACKAGE_STRING "fish 2.4.0-git"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "fish"
|
||||
@@ -176,7 +176,7 @@
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "2.4b1"
|
||||
#define PACKAGE_VERSION "2.4.0-git"
|
||||
|
||||
/* The size of `wchar_t', as computed by sizeof. */
|
||||
#define SIZEOF_WCHAR_T 4
|
||||
|
||||
@@ -18,11 +18,11 @@ static void die(const char *format, ...) {
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', stderr);
|
||||
|
||||
|
||||
if (s_command_path[0] != '\0') {
|
||||
unlink(s_command_path);
|
||||
}
|
||||
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -31,14 +31,14 @@ static void launch_fish_with_applescript(NSString *fish_binary_path)
|
||||
// load the script from a resource by fetching its URL from within our bundle
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:@"launch_fish" ofType:@"scpt"];
|
||||
if (! path) die("Couldn't get path to launch_fish.scpt");
|
||||
|
||||
|
||||
NSURL *url = [NSURL fileURLWithPath:path isDirectory:NO];
|
||||
if (! url) die("Couldn't get URL to launch_fish.scpt");
|
||||
|
||||
|
||||
NSDictionary *errors = nil;
|
||||
NSAppleScript *appleScript = [[NSAppleScript alloc] initWithContentsOfURL:url error:&errors];
|
||||
if (! appleScript) die("Couldn't load AppleScript");
|
||||
|
||||
|
||||
// create the first parameter
|
||||
NSAppleEventDescriptor *firstParameter =
|
||||
[NSAppleEventDescriptor descriptorWithString:fish_binary_path];
|
||||
@@ -84,16 +84,17 @@ static void launch_fish_with_applescript(NSString *fish_binary_path)
|
||||
|
||||
/* This approach asks Terminal to open a script that we control */
|
||||
int main(void) {
|
||||
|
||||
|
||||
@autoreleasepool {
|
||||
/* Get the fish executable. Make sure it's absolute. */
|
||||
NSURL *fish_executable = [[NSBundle mainBundle] URLForResource:@"fish" withExtension:@"" subdirectory:@"base/bin"];
|
||||
NSURL *fish_executable = [[NSBundle mainBundle] URLForResource:@"fish" withExtension:@""
|
||||
subdirectory:@"base/bin"];
|
||||
if (! fish_executable)
|
||||
die("Could not find fish executable in bundle");
|
||||
|
||||
|
||||
launch_fish_with_applescript([fish_executable path]);
|
||||
}
|
||||
|
||||
|
||||
/* If we succeeded, it will clean itself up */
|
||||
return 0;
|
||||
}
|
||||
|
||||
11
share/completions/caffeinate.fish
Normal file
11
share/completions/caffeinate.fish
Normal file
@@ -0,0 +1,11 @@
|
||||
# completion for caffeinate (macOS)
|
||||
|
||||
complete -c caffeinate -s d -f -d 'Create an assertion to prevent the display from sleeping'
|
||||
complete -c caffeinate -s i -f -d 'Create an assertion to prevent the system from idle sleeping'
|
||||
complete -c caffeinate -s m -f -d 'Create an assertion to prevent the disk from idle sleeping'
|
||||
complete -c caffeinate -s s -f -d 'Create an assertion to prevent the system from sleeping (AC power)'
|
||||
complete -c caffeinate -s u -f -d 'Create an assertion to declare that user is active'
|
||||
complete -c caffeinate -s t -x -a '10 60 300 600 1800 3600' -d 'Specifies the timeout value in seconds'
|
||||
complete -c caffeinate -s w -x -a '(__fish_complete_pids)' -d 'Waits for the process with the specified PID to exit'
|
||||
|
||||
complete -c caffeinate -x -a '(__fish_complete_subcommand)'
|
||||
33
share/completions/defaults.fish
Normal file
33
share/completions/defaults.fish
Normal file
@@ -0,0 +1,33 @@
|
||||
# completion for defaults (macOS)
|
||||
|
||||
function __fish_defaults_domains
|
||||
defaults domains | string split ", "
|
||||
end
|
||||
|
||||
complete -f -c defaults -o 'currentHost' -d 'Restricts preferences operations to the current logged-in host'
|
||||
complete -f -c defaults -o 'host' -d 'Restricts preferences operations to hostname'
|
||||
|
||||
# read
|
||||
complete -f -c defaults -n '__fish_use_subcommand' -a read -d 'Shows defaults entire given domain'
|
||||
complete -f -c defaults -n '__fish_seen_subcommand_from read read-type write rename delete' -a '(__fish_defaults_domains)'
|
||||
complete -f -c defaults -n '__fish_seen_subcommand_from read read-type write rename delete' -o 'app'
|
||||
|
||||
# write
|
||||
complete -f -c defaults -n '__fish_use_subcommand' -a write -d 'Writes domain or or a key in the domain'
|
||||
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'string' -d 'String as the value for the given key'
|
||||
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'data' -d 'Raw data bytes for given key'
|
||||
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'int' -d 'Integer as the value for the given key'
|
||||
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'float' -d 'Floating point number as the value for the given key'
|
||||
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'bool' -d 'Boolean as the value for the given key'
|
||||
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'date' -d 'Date as the value for the given key'
|
||||
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'array' -d 'Array as the value for the given key'
|
||||
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'array-add' -d 'Add new elements to the end of an array'
|
||||
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'dict' -d 'Add a dictionary to domain'
|
||||
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'dict-add' -d 'Add new key/value pairs to a dictionary'
|
||||
|
||||
complete -f -c defaults -n '__fish_use_subcommand' -a read-type -d 'Shows the type for the given domain, key'
|
||||
complete -f -c defaults -n '__fish_use_subcommand' -a rename -d 'Renames old_key to new_key'
|
||||
complete -f -c defaults -n '__fish_use_subcommand' -a delete -d 'Deletes domain or a key in the domain'
|
||||
complete -f -c defaults -n '__fish_use_subcommand' -a domains -d 'Prints the names of all domains in the users defaults system'
|
||||
complete -f -c defaults -n '__fish_use_subcommand' -a find -d 'Searches for word in domain names, keys, and values'
|
||||
complete -f -c defaults -n '__fish_use_subcommand' -a help -d 'Prints a list of possible command formats'
|
||||
64
share/completions/dig.fish
Normal file
64
share/completions/dig.fish
Normal file
@@ -0,0 +1,64 @@
|
||||
# completion for dig
|
||||
|
||||
function __fish_complete_dig
|
||||
set -l token (commandline -ct)
|
||||
switch $token
|
||||
case '+tries=*' '+retry=*' '+time=*' '+bufsize=*' '+ndots=*' '+edns=*'
|
||||
printf '%s\n' $token(seq 0 50)
|
||||
end
|
||||
end
|
||||
|
||||
complete -f -c dig -s 4 -d 'Use IPv4 query transport only'
|
||||
complete -f -c dig -s 6 -d 'Use IPv6 query transport only'
|
||||
complete -f -c dig -s m -d 'Enable memory usage debugging'
|
||||
complete -c dig -s b -x -d 'Bind to source address/port'
|
||||
complete -c dig -s f -r -d 'Specify batch mode file'
|
||||
complete -c dig -s c -x -a 'IN CH HS QCLASS' -d 'Specify query class'
|
||||
complete -c dig -s k -r -d 'Specify TSIG key file'
|
||||
complete -c dig -s y -x -d 'specify named base64 TSIG key'
|
||||
complete -c dig -s p -x -d 'Specify port number'
|
||||
complete -c dig -s q -x -d 'Specify query name'
|
||||
complete -c dig -s t -x -a 'A AAAA AFSDB APL CAA CDNSKEY CDS CERT CNAME DHCID DLV DNAME DNSKEY DS HIP IPSECKEY KEY KX LOC MX NAPTR NS NSEC NSEC3 NSEC3PARAM PTR RRSIG RP SIG SOA SRV SSHFP TA TKEY TLSA TSIG TXT URI' -d 'Specify query type'
|
||||
complete -c dig -s x -x -d 'Reverse lookup'
|
||||
complete -f -c dig -s h -d 'Print help and exit'
|
||||
complete -f -c dig -s v -d 'Print version and exit'
|
||||
|
||||
complete -f -c dig -a '+vc +novc' -d 'TCP mode'
|
||||
complete -f -c dig -a '+tcp +notcp' -d 'TCP mode, alternate syntax'
|
||||
complete -f -c dig -a '+search +nosearch' -d 'Set whether to use searchlist'
|
||||
complete -f -c dig -a '+showsearch +noshowsearch' -d 'Search with intermediate results'
|
||||
complete -f -c dig -a '+defname +nodefname' -d 'Deprecated, treated as a synonym for +[no]search'
|
||||
complete -f -c dig -a '+recurse +norecurse' -d 'Recursive mode'
|
||||
complete -f -c dig -a '+ignore +noignore' -d 'Dont revert to TCP for TC responses.'
|
||||
complete -f -c dig -a '+fail +nofail' -d 'Dont try next server on SERVFAIL'
|
||||
complete -f -c dig -a '+besteffort +nobesteffort' -d 'Try to parse even illegal messages'
|
||||
complete -f -c dig -a '+aaonly +noaaonly' -d 'Set AA flag in query (+[no]aaflag)'
|
||||
complete -f -c dig -a '+adflag +noadflag' -d 'Set AD flag in query'
|
||||
complete -f -c dig -a '+cdflag +nocdflag' -d 'Set CD flag in query'
|
||||
complete -f -c dig -a '+cl +nocl' -d 'Control display of class in records'
|
||||
complete -f -c dig -a '+cmd +nocmd' -d 'Control display of command line'
|
||||
complete -f -c dig -a '+comments +nocomments' -d 'Control display of comment lines'
|
||||
complete -f -c dig -a '+question +noquestion' -d 'Control display of question'
|
||||
complete -f -c dig -a '+answer +noanswer' -d 'Control display of answer'
|
||||
complete -f -c dig -a '+authority +noauthority' -d 'Control display of authority'
|
||||
complete -f -c dig -a '+additional +noadditional' -d 'Control display of additional'
|
||||
complete -f -c dig -a '+stats +nostats' -d 'Control display of statistics'
|
||||
complete -f -c dig -a '+short +noshort' -d 'Disable everything except short form of answer'
|
||||
complete -f -c dig -a '+ttlid +nottlid' -d 'Control display of ttls in records'
|
||||
complete -f -c dig -a '+all +noall' -d 'Set or clear all display flags'
|
||||
complete -f -c dig -a '+qr +noqr' -d 'Print question before sending'
|
||||
complete -f -c dig -a '+nssearch +nonssearch' -d 'Search all authoritative nameservers'
|
||||
complete -f -c dig -a '+identify +noidentify' -d 'ID responders in short answers'
|
||||
complete -f -c dig -a '+trace +notrace' -d 'Trace delegation down from root'
|
||||
complete -f -c dig -a '+dnssec +nodnssec' -d 'Request DNSSEC records'
|
||||
complete -f -c dig -a '+nsid +nonsid' -d 'Request Name Server ID'
|
||||
complete -f -c dig -a '+multiline +nomultiline' -d 'Print records in an expanded format'
|
||||
complete -f -c dig -a '+onesoa +noonesoa' -d 'AXFR prints only one soa record'
|
||||
|
||||
complete -f -c dig -a '+tries=' -d 'Set number of UDP attempts'
|
||||
complete -f -c dig -a '+retry=' -d 'Set number of UDP retries'
|
||||
complete -f -c dig -a '+time=' -d 'Set query timeout'
|
||||
complete -f -c dig -a '+bufsize=' -d 'Set EDNS0 Max UDP packet size'
|
||||
complete -f -c dig -a '+ndots=' -d 'Set NDOTS value'
|
||||
complete -f -c dig -a '+edns=' -d 'Set EDNS version'
|
||||
complete -c dig -a '(__fish_complete_dig)'
|
||||
@@ -1,4 +1,4 @@
|
||||
#completion for diskutil
|
||||
# completion for diskutil (macOS)
|
||||
|
||||
function __fish_diskutil_devices
|
||||
set -l mountpoints /dev/disk*; printf '%s\n' $mountpoints
|
||||
@@ -22,6 +22,10 @@ complete -f -c diskutil -n '__fish_seen_subcommand_from info' -o 'all' -d 'Proce
|
||||
# activity
|
||||
complete -f -c diskutil -n '__fish_use_subcommand' -a activity -d 'Continuously display system-wide disk manipulation activity'
|
||||
|
||||
# listFilesystems
|
||||
complete -f -c diskutil -n '__fish_use_subcommand' -a listFilesystems -d 'Show the file system personalities available'
|
||||
complete -f -c diskutil -n '__fish_seen_subcommand_from listFilesystems' -o 'plist' -d 'Return a property list'
|
||||
|
||||
# umount
|
||||
complete -f -c diskutil -n '__fish_use_subcommand' -a umount -d 'Unmount a single volume'
|
||||
complete -f -c diskutil -n '__fish_seen_subcommand_from umount' -a '(__fish_diskutil_mounted_volumes)'
|
||||
|
||||
14
share/completions/dpkg-reconfigure.fish
Normal file
14
share/completions/dpkg-reconfigure.fish
Normal file
@@ -0,0 +1,14 @@
|
||||
# Completions for the `dpkg-reconfigure` command
|
||||
|
||||
complete -f -c dpkg-reconfigure -a '(__fish_print_packages)' --description 'Package'
|
||||
|
||||
# Support flags
|
||||
complete -x -f -c dpkg-reconfigure -s h -l help --description 'Display help'
|
||||
|
||||
# General options
|
||||
complete -f -c dpkg-reconfigure -s f -l frontend -r -a "dialog readline noninteractive gnome kde editor web" --description 'Set configuration frontend'
|
||||
complete -f -c dpkg-reconfigure -s p -l priority -r -a "low medium high critical" --description 'Set priority threshold'
|
||||
complete -f -c dpkg-reconfigure -l default-priority --description 'Use default priority threshold'
|
||||
complete -f -c dpkg-reconfigure -s u -l unseen-only --description 'Show only unseen question'
|
||||
complete -f -c dpkg-reconfigure -l force --description 'Reconfigure also inconsistent packages'
|
||||
complete -f -c dpkg-reconfigure -l no-reload --description 'Prevent reloading templates'
|
||||
51
share/completions/lxc.fish
Normal file
51
share/completions/lxc.fish
Normal file
@@ -0,0 +1,51 @@
|
||||
function __fish_lxc_no_subcommand -d 'Test if lxc has yet to be given the command'
|
||||
for i in (commandline --tokenize --cut-at-cursor --current-process)
|
||||
if contains -- $i config copy delete exec file help image launch list move network profile publish remote restore restart snapshot start stop
|
||||
return 1
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function __fish_lxc_list_containers
|
||||
lxc list -c n | string match -r '\| [a-zA-Z_-]+' | string replace -r '\| ' ''
|
||||
end
|
||||
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments config --description 'Manage configuration.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments copy --description 'Copy containers within or in between lxd instances.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments delete --description 'Delete containers or snapshots.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments exec --description 'Execute the specified command in a container.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments file --description 'Manage files on a container.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments finger --description 'Check if the LXD instance is up.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments help --description 'Print help.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments image --description 'Manipulate container images.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments info --description 'List information on LXD servers and containers.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments init --description 'Initialize a container from a particular image.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments launch --description 'Launch a container from a particular image.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments list --description 'Lists the available resources.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments manpage --description 'Prints all the subcommands help.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments monitor --description 'Monitor activity on the LXD server.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments move --description 'Move containers within or in between lxd instances.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments network --description 'Manage networks.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments pause --description 'Changes state of one or more containers to pause.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments profile --description 'Manage configuration profiles.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments publish --description 'Publish containers as images.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments remote --description 'Manage remote LXD servers.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments restart --description 'Changes state of one or more containers to restart.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments restore --description 'Set the current state of a container back to a snapshot.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments snapshot --description 'Create a read-only snapshot of a container.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments start --description 'Changes state of one or more containers to start.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments stop --description 'Changes state of one or more containers to stop.'
|
||||
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments version --description 'Prints the version number of this client tool.'
|
||||
|
||||
# config
|
||||
complete --condition '__fish_seen_subcommand_from config' --command lxc --no-files --arguments "device get set unset show edit trust"
|
||||
|
||||
# exec
|
||||
complete --condition '__fish_seen_subcommand_from exec' --command lxc --no-files --arguments "(__fish_lxc_list_containers)"
|
||||
|
||||
# start
|
||||
complete --condition '__fish_seen_subcommand_from start' --command lxc --no-files --arguments "(__fish_lxc_list_containers)"
|
||||
|
||||
# stop
|
||||
complete --condition '__fish_seen_subcommand_from stop' --command lxc --no-files --arguments "(__fish_lxc_list_containers)"
|
||||
12
share/completions/mddiagnose.fish
Normal file
12
share/completions/mddiagnose.fish
Normal file
@@ -0,0 +1,12 @@
|
||||
# completion for mddiagnose (macOS)
|
||||
|
||||
complete -c mddiagnose -s h -f -d 'Display help'
|
||||
complete -c mddiagnose -s d -f -d 'Ignore unknown options'
|
||||
complete -c mddiagnose -s n -f -d 'Do not reveal the resulting package in the Finder'
|
||||
complete -c mddiagnose -s r -f -d 'Avoid restricted operations such as heap'
|
||||
complete -c mddiagnose -s s -f -d 'Skip gathering system.log'
|
||||
complete -c mddiagnose -s v -f -d 'Prints version of mddiagnose'
|
||||
complete -c mddiagnose -s m -f -d 'Minimal report'
|
||||
complete -c mddiagnose -s e -r -d 'Evalute indexing information for path'
|
||||
complete -c mddiagnose -s p -r -d 'Evalute permissions information for path'
|
||||
complete -c mddiagnose -s f -r -d 'Write the diagnostic to the specified path'
|
||||
12
share/completions/mdfind.fish
Normal file
12
share/completions/mdfind.fish
Normal file
@@ -0,0 +1,12 @@
|
||||
# completion for mdfind (macOS)
|
||||
|
||||
complete -c mdfind -o attr -x -d 'Fetches the value of the specified attribute'
|
||||
complete -c mdfind -o count -f -d 'Query only reports matching items count'
|
||||
complete -c mdfind -o onlyin -x -a '(__fish_complete_directories (commandline -ct))' -d 'Search only within given directory'
|
||||
complete -c mdfind -o live -f -d 'Query should stay active'
|
||||
complete -c mdfind -o name -x -d 'Search on file name only'
|
||||
complete -c mdfind -o reprint -f -d 'Reprint results on live update'
|
||||
complete -c mdfind -s s -x -d 'Show contents of smart folder'
|
||||
complete -c mdfind -s 0 -f -d 'Use NUL (\0) as a path separator, for use with xargs -0'
|
||||
complete -c mdfind -o literal -f -d 'Force the provided query string to be taken as a literal'
|
||||
complete -c mdfind -o interpret -f -d 'Interprete query string as Spotlight query'
|
||||
13
share/completions/mdimport.fish
Normal file
13
share/completions/mdimport.fish
Normal file
@@ -0,0 +1,13 @@
|
||||
# completion for mdimport (macOS)
|
||||
|
||||
complete -c mdimport -s g -r -d 'Import files using the listed plugin'
|
||||
complete -c mdimport -s V -f -d 'Print timing information for this run'
|
||||
complete -c mdimport -s A -f -d 'Print out the list of all of the attributes and exit'
|
||||
complete -c mdimport -s X -f -d 'Print out the schema file and exit'
|
||||
complete -c mdimport -s r -f -d 'Ask the server to reimport files for UTIs claimed by the listed plugin'
|
||||
complete -c mdimport -s p -f -d 'Print out performance information gathered during the run'
|
||||
complete -c mdimport -s L -f -d 'Print the list of installed importers and exit'
|
||||
complete -c mdimport -s d -x -a '1 2 3 4' -d 'Print debugging information'
|
||||
complete -c mdimport -s n -f -d 'Dont send the imported attributes to the data store'
|
||||
complete -c mdimport -s w -x -d 'Wait for the specified interval between scanning files'
|
||||
complete -c mdimport -s o -r -d 'Write the imported attributes to a file'
|
||||
6
share/completions/mdls.fish
Normal file
6
share/completions/mdls.fish
Normal file
@@ -0,0 +1,6 @@
|
||||
# completion for mdls (macOS)
|
||||
|
||||
complete -c mdls -s n -o name -x -d 'Print only the matching metadata attribute value'
|
||||
complete -c mdls -s r -o raw -f -d 'Print raw attribute data'
|
||||
complete -c mdls -n '__fish_seen_subcommand_from -raw -r' -o nullMarker -x -d 'Sets a marker string to be used when a requested attribute is null'
|
||||
complete -c mdls -s p -o plist -r -d 'Output attributes in XML format to file'
|
||||
24
share/completions/mdutil.fish
Normal file
24
share/completions/mdutil.fish
Normal file
@@ -0,0 +1,24 @@
|
||||
# completion for mdutil (macOS)
|
||||
|
||||
function __fish_mdutil_volumes
|
||||
command mdutil -a -s | while read -l line
|
||||
if string match -q \t"*" -- $line
|
||||
printf "%s\n" $line
|
||||
else
|
||||
# Use printf to not output a newline so indented lines are joined
|
||||
# to non-indented ones
|
||||
printf "%s" (string replace -r ':$' '' -- $line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
complete -c mdutil -s p -f -d 'Publish metadata'
|
||||
complete -c mdutil -s i -f -a 'on off' -d 'Turn indexing on or off'
|
||||
complete -c mdutil -s d -f -d 'Disable Spotlight activity for volume'
|
||||
complete -c mdutil -s E -f -d 'Erase and rebuild index'
|
||||
complete -c mdutil -s s -f -d 'Print indexing status'
|
||||
complete -c mdutil -s t -x -a '(__fish_mdutil_volumes)' -d 'Resolve files from file id with an optional volume path or device id'
|
||||
complete -c mdutil -s a -f -d 'Apply command to all volumes'
|
||||
complete -c mdutil -s V -x -a '(__fish_mdutil_volumes)' -d 'Apply command to all stores on the specified volume'
|
||||
complete -c mdutil -s v -f -d 'Display verbose information'
|
||||
complete -c mdutil -x -a '(__fish_mdutil_volumes)'
|
||||
82
share/completions/mkvextract.fish
Normal file
82
share/completions/mkvextract.fish
Normal file
@@ -0,0 +1,82 @@
|
||||
# Sample output of 'mkvmerge -i file.mkv'
|
||||
#
|
||||
# File 'file.mkv': container: Matroska
|
||||
# Track ID 0: video (MPEG-4p10/AVC/h.264)
|
||||
# Track ID 1: audio (AAC)
|
||||
# Track ID 2: subtitles (SubStationAlpha)
|
||||
# Attachment ID 1: type 'application/x-truetype-font', size 53532 bytes, file name 'some_font.ttf'
|
||||
# Chapters: 7 entires
|
||||
|
||||
function __fish_mkvextract_find_matroska_in_args
|
||||
set -l cmd (commandline -opc)
|
||||
if not set -q cmd[3]
|
||||
return 1
|
||||
end
|
||||
for c in $cmd[3..-1]
|
||||
set -l skip_next 1
|
||||
test $skip_next -eq 0; and set skip_next 1; and continue
|
||||
switch $c
|
||||
# General options with an argument we need to skip
|
||||
case "--ui-language" "--command-line-charset" "--output-charset" "-r" "--redirect-output" "-c" "--blockadd" "--simple-language"
|
||||
set skip_next 0
|
||||
continue
|
||||
# these behave like commands and everything after them is ignored
|
||||
case "-h" "--help" "-V" "--version"
|
||||
return 1
|
||||
case "*"
|
||||
if test -f "$c"
|
||||
echo $c
|
||||
return 0
|
||||
end
|
||||
continue
|
||||
end
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
function __fish_mkvextract_print_attachments
|
||||
if set -l matroska (__fish_mkvextract_find_matroska_in_args)
|
||||
if set -l info (mkvmerge -i $matroska)
|
||||
string match 'Attachment ID*' -- $info | string replace -r '.*?(\d+).*? type \'(.*?)\'.*?file name \'(.*?)\'' '$1:\t$3 ($2)'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function __fish_mkvextract_print_tracks
|
||||
if set -l matroska (__fish_mkvextract_find_matroska_in_args)
|
||||
if set -l info (mkvmerge -i $matroska)
|
||||
string match 'Track ID*' -- $info | string replace -r '.*?(\d+): (.*)' '$1:\t$2'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# simple options
|
||||
complete -f -c mkvextract -s V -l "version" -d "Show version information"
|
||||
complete -f -c mkvextract -s h -l "help" -d "Show help"
|
||||
# commands
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "tracks" -d "Extract tracks to external files"
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "tags" -d "Extract tags as XML"
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "attachments" -d "Extract attachments"
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "chapters" -d "Extract chapters as XML"
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "cuesheet" -d "Extract chapters and tags as CUE sheet"
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "timecodes_v2" -d "Extract timecodes of a track as timecode v2 file"
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "cues" -d "Extract cue information as text file"
|
||||
# dynamic tracks and attachments completions
|
||||
complete -f -c mkvextract -n "__fish_seen_subcommand_from tracks timecodes_v2 cues" -a "(__fish_mkvextract_print_tracks)"
|
||||
complete -f -c mkvextract -n "__fish_seen_subcommand_from attachments" -a "(__fish_mkvextract_print_attachments)"
|
||||
# options common to all commands
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -s f -l "parse-fully" -d "Parse the whole file instead of relying on the index"
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -s v -l "verbose" -d "Increase verbosity"
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -s q -l "quiet" -d "Suppress status output"
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -r -l "ui-language" -d "Force the translations for 'code' to be used"
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -r -l "command-line-charset" -d "Charset for strings on the command line"
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -r -l "output-charset" -d "Outputs messages in specified charset"
|
||||
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -r -s r -l "redirect-output" -d "Redirect all messages into a file"
|
||||
# command-specific options
|
||||
complete -f -c mkvextract -n "__fish_seen_subcommand_from tracks" -r -s c -d "Convert text subtitles to a charset"
|
||||
complete -f -c mkvextract -n "__fish_seen_subcommand_from tracks" -l "cuesheet" -d "Also try to extract the CUE sheet"
|
||||
complete -f -c mkvextract -n "__fish_seen_subcommand_from tracks" -r -l "blockadd" -d "Keep only the BlockAdditions up to the specified level"
|
||||
complete -f -c mkvextract -n "__fish_seen_subcommand_from tracks" -l "raw" -d "Extract the data to a raw file"
|
||||
complete -f -c mkvextract -n "__fish_seen_subcommand_from tracks" -l "fullraw" -d "Extract the data to a raw file including the CodecPrivate as header"
|
||||
complete -f -c mkvextract -n "__fish_seen_subcommand_from chapters" -s s -l "simple" -d "Exports the chapter information in a simple format"
|
||||
complete -f -c mkvextract -n "__fish_seen_subcommand_from chapters" -r -l "simple-language" -d "Uses the chapter names of the specified language"
|
||||
12
share/completions/nvram.fish
Normal file
12
share/completions/nvram.fish
Normal file
@@ -0,0 +1,12 @@
|
||||
# completion for nvram (macOS)
|
||||
|
||||
function __fish_nvram_variables
|
||||
command nvram -p
|
||||
end
|
||||
|
||||
complete -c nvram -s x -f -d 'Use XML format for reading and writing variables'
|
||||
complete -c nvram -s p -f -d 'Print all of the firmware variables'
|
||||
complete -c nvram -s f -r -d 'Set firmware variables from a text file'
|
||||
complete -c nvram -s d -x -a '(__fish_nvram_variables)' -d 'Deletes the named firmware variable'
|
||||
complete -c nvram -s c -f -d 'Delete all of the firmware variable'
|
||||
complete -c nvram -x -a '(__fish_nvram_variables)'
|
||||
@@ -1,14 +1,25 @@
|
||||
# Note that when a completion file is sourced a new block scope is created so `set -l` works.
|
||||
set -l __fish_status_all_commands is-login is-interactive is-block is-command-substitution is-no-job-control is-interactive-job-control is-full-job-control current-filename current-line-number print-stack-trace job-control
|
||||
|
||||
# These are the recognized flags.
|
||||
complete -c status -s h -l help --description "Display help and exit"
|
||||
complete -c status -l is-command-substitution --description "Test if a command substitution is currently evaluated"
|
||||
complete -c status -l is-block --description "Test if a code block is currently evaluated"
|
||||
complete -c status -l is-interactive --description "Test if this is an interactive shell"
|
||||
complete -c status -l is-login --description "Test if this is a login shell"
|
||||
complete -c status -l is-full-job-control --description "Test if all new jobs are put under job control"
|
||||
complete -c status -l is-interactive-job-control --description "Test if only interactive new jobs are put under job control"
|
||||
complete -c status -l is-no-job-control --description "Test if new jobs are never put under job control"
|
||||
complete -c status -s j -l job-control -xa "full interactive none" --description "Set which jobs are out under job control"
|
||||
complete -c status -s t -l print-stack-trace --description "Print a list of all function calls leading up to running the current command"
|
||||
complete -c status -s f -l current-filename --description "Print the filename of the currently running script"
|
||||
complete -c status -s n -l current-line-number --description "Print the line number of the currently running script"
|
||||
complete -c status -s t -l print-stack-trace --description "Prints a trace of all function calls on the stack"
|
||||
|
||||
# The "is-something" subcommands.
|
||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-login -d "Test if this is a login shell"
|
||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-interactive -d "Test if this is an interactive shell"
|
||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-command-substitution -d "Test if a command substitution is currently evaluated"
|
||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-block -d "Test if a code block is currently evaluated"
|
||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-no-job-control -d "Test if new jobs are never put under job control"
|
||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-interactive-job-control -d "Test if only interactive new jobs are put under job control"
|
||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-full-job-control -d "Test if all new jobs are put under job control"
|
||||
|
||||
# The subcommands that are not "is-something" which don't change the fish state.
|
||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-filename -d "Print the filename of the currently running script"
|
||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-line-number -d "Print the line number of the currently running script"
|
||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a print-stack-trace -d "Print a list of all function calls leading up to running the current command"
|
||||
|
||||
# The job-control command changes fish state.
|
||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a job-control -d "Set which jobs are under job control"
|
||||
complete -f -c status -n "__fish_seen_subcommand_from job-control" -a full -d "Set all jobs under job control"
|
||||
complete -f -c status -n "__fish_seen_subcommand_from job-control" -a interactive -d "Set only interactive jobs under job control"
|
||||
complete -f -c status -n "__fish_seen_subcommand_from job-control" -a none -d "Set no jobs under job control"
|
||||
|
||||
@@ -165,7 +165,7 @@ for cmd in $blame $diff $log $merge
|
||||
_svn_cmpl_ $cmd -l extensions -s x -d 'Ignore changes in amount of whitespace' -xa '-b --ignore-space-change'
|
||||
_svn_cmpl_ $cmd -l extensions -s x -d 'Ignore all whitespace' -xa '-w --ignore-all-space'
|
||||
_svn_cmpl_ $cmd -l extensions -s x -d 'Ignore eol style' -xa '-w --ignore-eol-style'
|
||||
_svn_cmpl_ $cmd -l extensions -s x -d 'Show C function name' -xa '-p --shoe-c-function'
|
||||
_svn_cmpl_ $cmd -l extensions -s x -d 'Show C function name' -xa '-p --show-c-function'
|
||||
|
||||
# Next completion doesn't work, since fish doesn't respect -x key
|
||||
#_svn_cmpl_ $cmd -l extensions -n '__fish_seen_subcommand_from --diff-cmd' -xa '(__fish_complete_svn_diff)'
|
||||
|
||||
111
share/completions/sysbench.fish
Normal file
111
share/completions/sysbench.fish
Normal file
@@ -0,0 +1,111 @@
|
||||
### Auto-complete for sysbench (cross-platform and multi-threaded benchmark tool) ###
|
||||
|
||||
### sub commands specification ###
|
||||
complete -c sysbench -f -a "run\t'Run the test'"
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -a "
|
||||
prepare\t'Prepare and create test file'
|
||||
cleanup\t'Cleanup test files'
|
||||
"
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -a "
|
||||
prepare\t'Prepare test table'
|
||||
cleanup\t'Cleanup test table'
|
||||
"
|
||||
|
||||
### generic long options specification ###
|
||||
complete -c sysbench -x -l num-threads -d 'The total number of worker threads to create (default: 1)'
|
||||
complete -c sysbench -x -l max-requests -d 'Limit for total number of requests. 0 means unlimited (default: 10000)'
|
||||
complete -c sysbench -x -l max-time -d 'Limit for total execution time in seconds. 0 means unlimited (default: 0)'
|
||||
complete -c sysbench -x -l thread-stack-size -d 'Size of stack for each thread (defaut: 32K)'
|
||||
complete -c sysbench -f -l init-rng -d 'Specifies if random numbers generator should be initialized from timer (defaut: off)' -a 'on off'
|
||||
complete -c sysbench -x -l test -d 'Name of the test mode to run(required)' -a "
|
||||
cpu\t'Benchmark cpu by calculating prime numbers'
|
||||
threads\t'Benchmark scheduler performance'
|
||||
mutex\t'Benchmark mutex implementation'
|
||||
fileio\t'Benchmark various file I/O workloads'
|
||||
oltp\t'Benchmark a real database performance'
|
||||
"
|
||||
complete -c sysbench -f -l debug -d 'Print more debug info (default: off)' -a 'on off'
|
||||
complete -c sysbench -f -l validate -d 'Perform validation of test results where possible (default: off)' -a 'on off'
|
||||
complete -c sysbench -l help -d 'Print help on general syntax'
|
||||
complete -c sysbench -l version -d 'Show version of program'
|
||||
complete -c sysbench -x -l percentile -d 'A percentile rank of query execution times to count (default: 95)'
|
||||
complete -c sysbench -f -l batch -d 'Dump current results periodically (default: off)' -a 'on off'
|
||||
complete -c sysbench -x -l batch-delay -d 'Delay between batch dumps in secods (default: 300)'
|
||||
|
||||
### options for test=`cpu` mode ###
|
||||
complete -c sysbench -n "__fish_contains_opt test=cpu" -x -l cpu-max-prime -d 'Calculation of prime numbers up to the specified value'
|
||||
|
||||
### options for test=`threads` mode ###
|
||||
complete -c sysbench -n "__fish_contains_opt test=threads" -x -l thread-yields -d 'Number of lock/yield/unlock loops to execute per each request (default: 1000)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=threads" -x -l thread-locks -d 'Number of mutexes to create (default: 8)'
|
||||
|
||||
### options for test=`mutex` mode ###
|
||||
complete -c sysbench -n "__fish_contains_opt test=mutex" -x -l mutex-num -d 'Number of mutexes to create (default: 4096)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=mutex" -x -l memory-scope -d 'Specifies whether each thread uses a global or local allocation (default:global)' -a "
|
||||
local\t'Allocate memory locally'
|
||||
global\t'Allocate memory globally'
|
||||
"
|
||||
complete -c sysbench -n "__fish_contains_opt test=mutex" -x -l memory-total-size -d 'Total size of data to transfer (default: 100G)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=mutex" -x -l memory-oper -d 'Type of memory operations' -a 'read write'
|
||||
|
||||
### options for test=`fileio` mode ###
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-num -d 'Number of files to create (default: 128)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-block-size -d 'Block size to use in all I/O operations (default: 16K)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-total-size -d 'Total size of files (default: 2G)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-test-mode -d 'Type of workload to produce' -a "
|
||||
seqwr\t'Sequential write'
|
||||
seqrewr\t'Sequential rewrite'
|
||||
seqrd\t'Sequential read'
|
||||
rndrd\t'Random read'
|
||||
rndwr\t'Random write'
|
||||
rndrw\t'Random read/write'
|
||||
"
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-io-mode -d 'I/O mode (default: sync)' -a 'sync async fastmmap slowmmap'
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-async-backlog -d 'Number of asynchronous operations to queue per thread (default: 128)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-extra-flags -d 'Additional flags to use with open(2)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-fsync-freq -d 'Do fsync() after this number of requests (default: 0)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -f -l file-fsync-all -d 'Do fsync() after each write operation (default: no)' -a 'yes no'
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -f -l file-fsync-end -d 'Do fsync() at the end of the test (default: yes)' -a 'yes no'
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-fsync-mode -d 'Method used for synchronization: fsync, fdatasync (default: fsync)' -a 'fsync fdatasync'
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-merged-requests -d 'Upper limit of I/O requests merge (default: 0)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-rw-ratio -d 'reads/writes ratio for combined random read/write test (default: 1.5)'
|
||||
|
||||
### options for test=`oltp` mode ###
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-test-mode -d 'Execution mode: simple, complex and nontrx(non-transactional)(default: complex)' -a "
|
||||
simple\t'Simple'
|
||||
complex\t'Advanced transactional'
|
||||
nontrx\t'Non-transactional'
|
||||
"
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -f -l oltp-read-only -d 'Read-only mode. No UPDATE, DELETE or INSERT queries will be performed. (default: off)' -a 'on off'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-range-size -d 'Range size for range queries (default: 100)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-point-selects -d 'Number of point select queries in a single transaction (default: 10)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-simple-ranges -d 'Number of simple range queries in a single transaction (default: 1)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-sum-ranges -d 'Number of SUM range queries in a single transaction (default: 1)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-order-ranges -d 'Number of ORDER range queries in a single transaction (default: 1)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-distinct-ranges -d 'Number of DISTINCT range queries in a single transaction (default: 1)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-index-updates -d 'Number of index UPDATE queries in a single transaction (default: 1)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-non-index-updates -d 'Number of non-index UPDATE queries in a single transaction (default: 1)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-nontrx-mode -d 'Type of queries for non-transactional execution mode (default: select)' -a 'select update_key update_nokey insert delete'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-connect-delay -d 'Time to sleep(in microseconds) after each connection to database (default: 10000)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-user-delay-min -d 'Minimum time to sleep(in microseconds) after each request (default: 0)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-user-delay-max -d 'Maximum time to sleep(in microseconds) after each request (default: 0)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-table-name -d 'Name of the test table (default: sbtest)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-table-size -d 'Number of rows in the test table (default: 10000)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-dist-type -d 'Distribution type of random numbers (default: special)' -a "
|
||||
uniform\t'Uniform distribution'
|
||||
gauss\t'Gaussian distribution'
|
||||
special\t'Specified percent of numbers is generated in a specified percent of cases'
|
||||
"
|
||||
complete -c sysbench -n "__fish_contains_opt oltp-dist-type=special" -x -l oltp-dist-pct -d 'Percentage of values to be treated as \'special\'(default: 1)'
|
||||
complete -c sysbench -n "__fish_contains_opt oltp-dist-type=special" -x -l oltp-dist-res -d 'Percentage of cases when \'special\' values are generated (default: 75)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l db-ps-mode -d 'Use "Prepared Statements" API if supported, otherwise - use clientside statements: disable, auto (default: auto)' -a 'disable auto'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-host -d 'MySQL server host (default: localhost)' -a "(__fish_print_hostnames)"
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-port -d 'MySQL server port (default: 3306)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -l mysql-socket -d 'Unix socket file to communicate with the MySQL server'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-user -d 'MySQL user (default: sbtest)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-password -d 'MySQL password'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-db -d 'MySQL database name (default: sbtest)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-table-engine -d 'Type of the test table to use' -a 'myisam innodb heap ndbcluster bdb maria falcon pbxt'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-ssl -d 'Use SSL connections. (default: no)' -a 'yes no'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l myisam-max-rows -d 'MAX_ROWS option for MyISAM tables (required for big tables) (default: 1000000)'
|
||||
complete -c sysbench -n "__fish_contains_opt test=oltp" -l mysql-create-options -d 'Additional options passed to CREATE TABLE.'
|
||||
@@ -3,7 +3,7 @@ if type -q -f sysctl
|
||||
if sysctl -h >/dev/null ^/dev/null
|
||||
# Print sysctl keys and values, separated by a tab
|
||||
function __fish_sysctl_values
|
||||
sysctl -a ^/dev/null | string replace -a " = " "\t"
|
||||
sysctl -a ^/dev/null | string replace -a " = " \t
|
||||
end
|
||||
|
||||
complete -c sysctl -a '(__fish_sysctl_values)' -f
|
||||
@@ -32,7 +32,7 @@ if type -q -f sysctl
|
||||
else
|
||||
# OSX sysctl
|
||||
function __fish_sysctl_values
|
||||
sysctl -a ^/dev/null | string replace -a ":" "\t"
|
||||
sysctl -a ^/dev/null | string replace -a ":" \t
|
||||
end
|
||||
|
||||
complete -c sysctl -a '(__fish_sysctl_values)' -f
|
||||
|
||||
56
share/completions/tmutil.fish
Normal file
56
share/completions/tmutil.fish
Normal file
@@ -0,0 +1,56 @@
|
||||
# completion for tmutil (macOS)
|
||||
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a addexclusion -d 'Add an exclusion not to back up a file'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from addexclusion' -s v -d 'Volume exclusion'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from addexclusion' -s p -d 'Path exclusion'
|
||||
complete -r -c tmutil -n '__fish_use_subcommand' -a associatedisk -d 'Bind a snapshot volume directory to the specified local disk'
|
||||
complete -r -c tmutil -n '__fish_use_subcommand' -a calculatedrift -d 'Determine the amount of change between snapshots'
|
||||
complete -r -c tmutil -n '__fish_use_subcommand' -a compare -d 'Perform a backup diff'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s a -d 'Compare all supported metadata'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s n -d 'No metadata comparison'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s @ -d 'Compare extended attributes'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s c -d 'Compare creation times'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s d -d 'Compare file data forks'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s e -d 'Compare ACLs'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s f -d 'Compare file flags'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s g -d 'Compare GIDs'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s m -d 'Compare file modes'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s s -d 'Compare sizes'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s t -d 'Compare modification times'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s u -d 'Compare UIDs'
|
||||
complete -r -c tmutil -n '__fish_seen_subcommand_from compare' -s D -d 'Limit traversal depth to depth levels from the beginning of iteration'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s E -d 'Dont take exclusions into account'
|
||||
complete -r -c tmutil -n '__fish_seen_subcommand_from compare' -s I -d 'Ignore path'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s U -d 'Ignore logical volume identity'
|
||||
complete -r -c tmutil -n '__fish_use_subcommand' -a delete -d 'Delete one or more snapshots'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a destinationinfo -d 'Print information about destinations'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a disable -d 'Turn off automatic backups'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a disablelocal -d 'Turn off local Time Machine snapshots'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a enable -d 'Turn on automatic backups'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a enablelocal -d 'Turn on local Time Machine snapshots'
|
||||
complete -r -c tmutil -n '__fish_use_subcommand' -a inheritbackup -d 'Claim a machine directory or sparsebundle for use by the current machine'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a isexcluded -d 'Determine if a file, directory, or volume are excluded from backups'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a latestbackup -d 'Print the path to the latest snapshot'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a listbackups -d 'Print paths for all snapshots'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a machinedirectory -d 'Print the path to the current machine directory'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a removedestination -d 'Removes a backup destination'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a removeexclusion -d 'Remove an exclusion'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from removeexclusion' -s v -d 'Volume exclusion'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from removeexclusion' -s p -d 'Path exclusion'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a restore -d 'Restore an item'
|
||||
complete -r -c tmutil -n '__fish_seen_subcommand_from restore' -s v
|
||||
complete -r -c tmutil -n '__fish_use_subcommand' -a setdestination -d 'Set a backup destination'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from setdestination' -s a -d 'Add to the list of destinations'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from setdestination' -s p -d 'Enter the password at a non-echoing interactive prompt'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a snapshot -d 'Create new local Time Machine snapshot'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a startbackup -d 'Begin a backup if one is not already running'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from startbackup' -s a -l auto -d 'Automatic mode'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from startbackup' -s b -l block -d 'Block until finished'
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from startbackup' -s r -l rotation -d 'Autmatic rotation'
|
||||
complete -r -c tmutil -n '__fish_seen_subcommand_from startbackup' -s d -l destination -d 'Backup destination'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a stopbackup -d 'Cancel a backup currently in progress'
|
||||
complete -r -c tmutil -n '__fish_use_subcommand' -a uniquesize -d 'Analyze the specified path and determine its unique size'
|
||||
complete -r -c tmutil -n '__fish_use_subcommand' -a verifychecksums -d 'Verify snapshot'
|
||||
complete -f -c tmutil -n '__fish_use_subcommand' -a version -d 'Print version'
|
||||
|
||||
complete -f -c tmutil -n '__fish_seen_subcommand_from destinationinfo isexcluded compare' -s X -d 'Print as XML'
|
||||
@@ -220,13 +220,18 @@ function __fish_config_interactive -d "Initializations that should be performed
|
||||
# Notify terminals when $PWD changes (issue #906)
|
||||
# VTE and Terminal.app support this in practice.
|
||||
if test "0$VTE_VERSION" -ge 3405 -o "$TERM_PROGRAM" = "Apple_Terminal"
|
||||
function fish_title; end
|
||||
function __update_cwd_osc --on-variable PWD --description 'Notify capable terminals when $PWD changes'
|
||||
status --is-command-substitution
|
||||
or test -n "$INSIDE_EMACS"
|
||||
and return
|
||||
printf \e\]7\;file://\%s\%s\a (hostname) (echo -n $PWD | __fish_urlencode)
|
||||
end
|
||||
if test "$TERM_PROGRAM" = "Apple_Terminal"
|
||||
# Suppress duplicative title display on Terminal.app
|
||||
echo -n \e\]0\;\a # clear existing title
|
||||
function fish_title
|
||||
end
|
||||
end
|
||||
__update_cwd_osc # Run once because we might have already inherited a PWD from an old tab
|
||||
end
|
||||
|
||||
|
||||
@@ -39,10 +39,11 @@ function __fish_print_help --description "Print help message for the specified f
|
||||
set cols (math $cols - 4) # leave a bit of space on the right
|
||||
set rLL -rLL=$cols[1]n
|
||||
end
|
||||
set -lx GROFF_TMAC_PATH $__fish_datadir/groff
|
||||
if test -e "$__fish_datadir/man/man1/$item.1"
|
||||
set help (nroff -man -c -t $rLL "$__fish_datadir/man/man1/$item.1" ^/dev/null)
|
||||
set help (nroff -c -man -mfish -t $rLL "$__fish_datadir/man/man1/$item.1" ^/dev/null)
|
||||
else if test -e "$__fish_datadir/man/man1/$item.1.gz"
|
||||
set help (gunzip -c "$__fish_datadir/man/man1/$item.1.gz" ^/dev/null | nroff -man -c -t $rLL ^/dev/null)
|
||||
set help (gunzip -c "$__fish_datadir/man/man1/$item.1.gz" ^/dev/null | nroff -c -man -mfish -t $rLL ^/dev/null)
|
||||
end
|
||||
|
||||
# The original implementation trimmed off the top 5 lines and bottom 3 lines
|
||||
|
||||
@@ -3,7 +3,14 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod
|
||||
# They are supposed to be unrelated to text-editing (or movement).
|
||||
# This takes $argv so the vi-bindings can pass the mode they are valid in.
|
||||
|
||||
if contains -- -h $argv
|
||||
or contains -- --help $argv
|
||||
echo "Sorry but this function doesn't support -h or --help"
|
||||
return 1
|
||||
end
|
||||
|
||||
bind $argv \cy yank
|
||||
or return # protect against invalid $argv
|
||||
bind $argv \ey yank-pop
|
||||
|
||||
# Left/Right arrow
|
||||
@@ -81,10 +88,11 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod
|
||||
bind $argv -k f1 __fish_man_page
|
||||
bind $argv \eh __fish_man_page
|
||||
|
||||
# This will make sure the output of the current command is paged using the default pager when you press Meta-p.
|
||||
# This will make sure the output of the current command is paged using the default pager when
|
||||
# you press Meta-p.
|
||||
# If none is set, less will be used.
|
||||
bind $argv \ep '__fish_paginate'
|
||||
|
||||
|
||||
# Make it easy to turn an unexecuted command into a comment in the shell history. Also,
|
||||
# remove the commenting chars so the command can be further edited then executed.
|
||||
bind $argv \e\# __fish_toggle_comment_commandline
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function alias --description 'Legacy function for creating shellscript functions using an alias-like syntax'
|
||||
function alias --description 'Creates a function wrapping a command'
|
||||
if count $argv > /dev/null
|
||||
switch $argv[1]
|
||||
case -h --h --he --hel --help
|
||||
@@ -14,8 +14,12 @@ function alias --description 'Legacy function for creating shellscript functions
|
||||
switch (count $argv)
|
||||
|
||||
case 0
|
||||
echo "Fish implements aliases using functions. Use 'functions' builtin to see list of functions and 'functions function_name' to see function definition, type 'help alias' for more information."
|
||||
return 1
|
||||
for func in (functions -n)
|
||||
set -l output (functions $func | string match -r -- "function .* --description '(alias .*)'" | string split \n)
|
||||
set -q output[2]
|
||||
and echo $output[2]
|
||||
end
|
||||
return 0
|
||||
case 1
|
||||
set -l tmp (string replace -r "=" '\n' -- $argv) ""
|
||||
set name $tmp[1]
|
||||
@@ -60,5 +64,6 @@ function alias --description 'Legacy function for creating shellscript functions
|
||||
set prefix command
|
||||
end
|
||||
end
|
||||
echo "function $name --wraps $first_word; $prefix $first_word $body \$argv; end" | source
|
||||
set -l cmd_string (string escape "alias $argv")
|
||||
echo "function $name --wraps $first_word --description $cmd_string; $prefix $first_word $body \$argv; end" | source
|
||||
end
|
||||
|
||||
@@ -1,86 +1,95 @@
|
||||
|
||||
function fish_default_key_bindings -d "Default (Emacs-like) key bindings for fish"
|
||||
if not set -q argv[1]
|
||||
# Clear earlier bindings, if any
|
||||
bind --erase --all
|
||||
if test "$fish_key_bindings" != "fish_default_key_bindings"
|
||||
# Allow the user to set the variable universally
|
||||
set -q fish_key_bindings; or set -g fish_key_bindings
|
||||
set fish_key_bindings fish_default_key_bindings # This triggers the handler, which calls us again and ensures the user_key_bindings are executed
|
||||
return
|
||||
end
|
||||
end
|
||||
if contains -- -h $argv
|
||||
or contains -- --help $argv
|
||||
echo "Sorry but this function doesn't support -h or --help"
|
||||
return 1
|
||||
end
|
||||
|
||||
if not set -q argv[1]
|
||||
bind --erase --all # clear earlier bindings, if any
|
||||
if test "$fish_key_bindings" != "fish_default_key_bindings"
|
||||
# Allow the user to set the variable universally
|
||||
set -q fish_key_bindings
|
||||
or set -g fish_key_bindings
|
||||
# This triggers the handler, which calls us again and ensures the user_key_bindings
|
||||
# are executed.
|
||||
set fish_key_bindings fish_default_key_bindings
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
# These are shell-specific bindings that we share with vi mode.
|
||||
__fish_shared_key_bindings $argv
|
||||
or return # protect against invalid $argv
|
||||
|
||||
# This is the default binding, i.e. the one used if no other binding matches
|
||||
bind $argv "" self-insert
|
||||
# This is the default binding, i.e. the one used if no other binding matches
|
||||
bind $argv "" self-insert
|
||||
or exit # protect against invalid $argv
|
||||
|
||||
bind $argv \n execute
|
||||
bind $argv \r execute
|
||||
bind $argv \n execute
|
||||
bind $argv \r execute
|
||||
|
||||
bind $argv \ck kill-line
|
||||
bind $argv \ck kill-line
|
||||
|
||||
bind $argv \eOC forward-char
|
||||
bind $argv \eOD backward-char
|
||||
bind $argv \e\[C forward-char
|
||||
bind $argv \e\[D backward-char
|
||||
bind $argv -k right forward-char
|
||||
bind $argv -k left backward-char
|
||||
bind $argv \eOC forward-char
|
||||
bind $argv \eOD backward-char
|
||||
bind $argv \e\[C forward-char
|
||||
bind $argv \e\[D backward-char
|
||||
bind $argv -k right forward-char
|
||||
bind $argv -k left backward-char
|
||||
|
||||
bind $argv -k dc delete-char
|
||||
bind $argv -k backspace backward-delete-char
|
||||
bind $argv \x7f backward-delete-char
|
||||
bind $argv -k dc delete-char
|
||||
bind $argv -k backspace backward-delete-char
|
||||
bind $argv \x7f backward-delete-char
|
||||
|
||||
# for PuTTY
|
||||
# https://github.com/fish-shell/fish-shell/issues/180
|
||||
bind $argv \e\[1~ beginning-of-line
|
||||
bind $argv \e\[3~ delete-char
|
||||
bind $argv \e\[4~ end-of-line
|
||||
# for PuTTY
|
||||
# https://github.com/fish-shell/fish-shell/issues/180
|
||||
bind $argv \e\[1~ beginning-of-line
|
||||
bind $argv \e\[3~ delete-char
|
||||
bind $argv \e\[4~ end-of-line
|
||||
|
||||
# OS X SnowLeopard doesn't have these keys. Don't show an annoying error message.
|
||||
bind $argv -k home beginning-of-line 2> /dev/null
|
||||
bind $argv -k end end-of-line 2> /dev/null
|
||||
bind $argv \e\[3\;2~ backward-delete-char # Mavericks Terminal.app shift-delete
|
||||
# OS X SnowLeopard doesn't have these keys. Don't show an annoying error message.
|
||||
bind $argv -k home beginning-of-line 2>/dev/null
|
||||
bind $argv -k end end-of-line 2>/dev/null
|
||||
bind $argv \e\[3\;2~ backward-delete-char # Mavericks Terminal.app shift-delete
|
||||
|
||||
bind $argv \ca beginning-of-line
|
||||
bind $argv \ce end-of-line
|
||||
bind $argv \ch backward-delete-char
|
||||
bind $argv \cp up-or-search
|
||||
bind $argv \cn down-or-search
|
||||
bind $argv \cf forward-char
|
||||
bind $argv \cb backward-char
|
||||
bind $argv \ct transpose-chars
|
||||
bind $argv \et transpose-words
|
||||
bind $argv \eu upcase-word
|
||||
bind $argv \ca beginning-of-line
|
||||
bind $argv \ce end-of-line
|
||||
bind $argv \ch backward-delete-char
|
||||
bind $argv \cp up-or-search
|
||||
bind $argv \cn down-or-search
|
||||
bind $argv \cf forward-char
|
||||
bind $argv \cb backward-char
|
||||
bind $argv \ct transpose-chars
|
||||
bind $argv \et transpose-words
|
||||
bind $argv \eu upcase-word
|
||||
|
||||
# This clashes with __fish_list_current_token
|
||||
# bind $argv \el downcase-word
|
||||
bind $argv \ec capitalize-word
|
||||
bind $argv \e\x7f backward-kill-word
|
||||
bind $argv \eb backward-word
|
||||
bind $argv \ef forward-word
|
||||
bind $argv \e\[1\;5C forward-word
|
||||
bind $argv \e\[1\;5D backward-word
|
||||
bind $argv -k ppage beginning-of-history
|
||||
bind $argv -k npage end-of-history
|
||||
bind $argv \e\< beginning-of-buffer
|
||||
bind $argv \e\> end-of-buffer
|
||||
# This clashes with __fish_list_current_token
|
||||
# bind $argv \el downcase-word
|
||||
bind $argv \ec capitalize-word
|
||||
bind $argv \e\x7f backward-kill-word
|
||||
bind $argv \eb backward-word
|
||||
bind $argv \ef forward-word
|
||||
bind $argv \e\[1\;5C forward-word
|
||||
bind $argv \e\[1\;5D backward-word
|
||||
bind $argv -k ppage beginning-of-history
|
||||
bind $argv -k npage end-of-history
|
||||
bind $argv \e\< beginning-of-buffer
|
||||
bind $argv \e\> end-of-buffer
|
||||
|
||||
bind \ed forward-kill-word
|
||||
bind \ed kill-word
|
||||
bind \ed forward-kill-word
|
||||
bind \ed kill-word
|
||||
|
||||
# Ignore some known-bad control sequences
|
||||
# https://github.com/fish-shell/fish-shell/issues/1917
|
||||
bind \e\[I 'begin;end'
|
||||
bind \e\[O 'begin;end'
|
||||
# Ignore some known-bad control sequences
|
||||
# https://github.com/fish-shell/fish-shell/issues/1917
|
||||
bind \e\[I 'begin;end'
|
||||
bind \e\[O 'begin;end'
|
||||
|
||||
# term-specific special bindings
|
||||
switch "$TERM"
|
||||
case 'rxvt*'
|
||||
bind $argv \e\[8~ end-of-line
|
||||
bind $argv \eOc forward-word
|
||||
bind $argv \eOd backward-word
|
||||
end
|
||||
# term-specific special bindings
|
||||
switch "$TERM"
|
||||
case 'rxvt*'
|
||||
bind $argv \e\[8~ end-of-line
|
||||
bind $argv \eOc forward-word
|
||||
bind $argv \eOd backward-word
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
# Set the default prompt command.
|
||||
|
||||
function fish_fallback_prompt --description "A simple fallback prompt without too much color or special characters for linux VTs"
|
||||
# Just calculate this once, to save a few cycles when displaying the prompt
|
||||
if not set -q __fish_prompt_hostname
|
||||
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
|
||||
end
|
||||
|
||||
set -l color_cwd
|
||||
set -l suffix
|
||||
switch $USER
|
||||
@@ -23,5 +18,5 @@ function fish_fallback_prompt --description "A simple fallback prompt without to
|
||||
set suffix '>'
|
||||
end
|
||||
|
||||
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
|
||||
echo -n -s "$USER" @ (prompt_hostname) ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
|
||||
end
|
||||
|
||||
18
share/functions/fish_hybrid_key_bindings.fish
Normal file
18
share/functions/fish_hybrid_key_bindings.fish
Normal file
@@ -0,0 +1,18 @@
|
||||
function fish_hybrid_key_bindings --description "Vi-style bindings that inherit emacs-style bindings in all modes"
|
||||
bind --erase --all # clear earlier bindings, if any
|
||||
|
||||
if test "$fish_key_bindings" != "fish_hybrid_key_bindings"
|
||||
# Allow the user to set the variable universally
|
||||
set -q fish_key_bindings
|
||||
or set -g fish_key_bindings
|
||||
# This triggers the handler, which calls us again and ensures the user_key_bindings
|
||||
# are executed.
|
||||
set fish_key_bindings fish_hybrid_key_bindings
|
||||
return
|
||||
end
|
||||
|
||||
for mode in default insert visual
|
||||
fish_default_key_bindings -M $mode
|
||||
end
|
||||
fish_vi_key_bindings --no-erase
|
||||
end
|
||||
7
share/functions/fish_key_reader.fish
Normal file
7
share/functions/fish_key_reader.fish
Normal file
@@ -0,0 +1,7 @@
|
||||
# check if command fish_key_reader works and is the same version that
|
||||
# came with this fish. This will happen one time.
|
||||
command -s fish_key_reader > /dev/null
|
||||
and command fish_key_reader --version 2>&1 | string match -rq $FISH_VERSION
|
||||
# if alias doesn't define the function here, this is an autoloaded "nothing".
|
||||
# the command (if there is one) will be used by default.
|
||||
or alias fish_key_reader=(string escape $__fish_bin_dir/fish_key_reader)
|
||||
@@ -2,6 +2,7 @@
|
||||
function fish_mode_prompt --description "Displays the current mode"
|
||||
# Do nothing if not in vi mode
|
||||
if test "$fish_key_bindings" = "fish_vi_key_bindings"
|
||||
or test "$fish_key_bindings" = "fish_hybrid_key_bindings"
|
||||
switch $fish_bind_mode
|
||||
case default
|
||||
set_color --bold --background red white
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
# Set the default prompt command.
|
||||
|
||||
function fish_prompt --description "Write out the prompt"
|
||||
# Just calculate this once, to save a few cycles when displaying the prompt
|
||||
if not set -q __fish_prompt_hostname
|
||||
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
|
||||
end
|
||||
|
||||
set -l color_cwd
|
||||
set -l suffix
|
||||
switch $USER
|
||||
@@ -23,5 +18,5 @@ function fish_prompt --description "Write out the prompt"
|
||||
set suffix '>'
|
||||
end
|
||||
|
||||
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
|
||||
echo -n -s "$USER" @ (prompt_hostname) ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
|
||||
end
|
||||
|
||||
@@ -1,11 +1,63 @@
|
||||
function fish_vi_cursor -d 'Set cursor shape for different vi modes'
|
||||
# Since we read exported variables (KONSOLE_PROFILE_NAME and ITERM_PROFILE)
|
||||
# we need to check harder if we're actually in a supported terminal,
|
||||
# because we might be in a term-in-a-term (emacs ansi-term).
|
||||
if not contains -- $TERM xterm konsole xterm-256color konsole-256color
|
||||
and not set -q TMUX
|
||||
# Check hard if we are in a supporting terminal.
|
||||
#
|
||||
# Challenges here are term-in-a-terms (emacs ansi-term does not support this, tmux does),
|
||||
# that we can only figure out if we are in konsole/iterm/vte via exported variables,
|
||||
# and ancient xterm versions.
|
||||
#
|
||||
# tmux defaults to $TERM = screen, but can do this if it is in a supporting terminal.
|
||||
# Unfortunately, we can only detect this via the exported variables, so we miss some cases.
|
||||
#
|
||||
# We will also miss some cases of terminal-stacking,
|
||||
# e.g. tmux started in suckless' st (no support) started in konsole.
|
||||
# But since tmux in konsole seems rather common and that case so uncommon,
|
||||
# we will just fail there (though it seems that tmux or st swallow it anyway).
|
||||
#
|
||||
# We use the `tput` here just to see if terminfo thinks we can change the cursor.
|
||||
# We cannot use that sequence directly as it's not the correct one for konsole and iTerm,
|
||||
# and because we may want to change the cursor even though terminfo says we can't (tmux).
|
||||
if not tput Ss > /dev/null ^/dev/null
|
||||
# Whitelist tmux...
|
||||
and not begin
|
||||
set -q TMUX
|
||||
# ...in a supporting term...
|
||||
and begin set -q KONSOLE_PROFILE_NAME
|
||||
or set -q ITERM_PROFILE
|
||||
or test "$VTE_VERSION" -ge 4000
|
||||
or test (string replace -r "XTerm\((\d+)\)" '$1' -- $XTERM_VERSION) -ge 280
|
||||
end
|
||||
# .. unless an unsupporting terminal has been started in tmux inside a supporting one
|
||||
and begin string match -q "screen*" -- $TERM
|
||||
or string match -q "tmux*" -- $TERM
|
||||
end
|
||||
end
|
||||
and not string match -q "konsole*" -- $TERM
|
||||
# Blacklist
|
||||
or begin
|
||||
# vte-based terms set $TERM = xterm*, but only gained support relatively recently.
|
||||
# From https://bugzilla.gnome.org/show_bug.cgi?id=720821, it appears it was version 0.40.0
|
||||
set -q VTE_VERSION
|
||||
and test "$VTE_VERSION" -lt 4000
|
||||
end
|
||||
or set -q INSIDE_EMACS
|
||||
or begin
|
||||
# TERM = xterm is special because plenty of things claim to be it, but aren't fully compatible
|
||||
# This includes old vte-terms (without $VTE_VERSION), old xterms (without $XTERM_VERSION or < 280)
|
||||
# and maybe other stuff.
|
||||
# This needs to be kept _at least_ as long as Ubuntu 14.04 is still a thing
|
||||
# because that ships a gnome-terminal without support and without $VTE_VERSION.
|
||||
string match -q 'xterm*' -- $TERM
|
||||
and not begin set -q KONSOLE_PROFILE_NAME
|
||||
or set -q ITERM_PROFILE
|
||||
or test "$VTE_VERSION" -ge 4000
|
||||
# If $XTERM_VERSION is undefined, this will return 1 and print an error. Silence it.
|
||||
or test (string replace -r "XTerm\((\d+)\)" '$1' -- $XTERM_VERSION) -ge 280 ^/dev/null
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
set -l terminal $argv[1]
|
||||
set -q terminal[1]
|
||||
or set terminal auto
|
||||
@@ -18,11 +70,9 @@ function fish_vi_cursor -d 'Set cursor shape for different vi modes'
|
||||
or set -q ITERM_PROFILE
|
||||
set function __fish_cursor_konsole
|
||||
set uses_echo 1
|
||||
else if string match -q "xterm*" -- $TERM; or test "$VTE_VERSION" -gt 1910
|
||||
else
|
||||
set function __fish_cursor_xterm
|
||||
set uses_echo 1
|
||||
else
|
||||
return 1
|
||||
end
|
||||
case konsole
|
||||
set function __fish_cursor_konsole
|
||||
|
||||
@@ -1,29 +1,41 @@
|
||||
function fish_vi_key_bindings --description 'vi-like key bindings for fish'
|
||||
if contains -- -h $argv
|
||||
or contains -- --help $argv
|
||||
echo "Sorry but this function doesn't support -h or --help"
|
||||
return 1
|
||||
end
|
||||
|
||||
# Erase all bindings if not explicitly requested otherwise to
|
||||
# allow for hybrid bindings.
|
||||
# This needs to be checked here because if we are called again
|
||||
# via the variable handler the argument will be gone.
|
||||
if not contains -- $argv[1] --no-erase
|
||||
bind --erase --all
|
||||
else if set -q argv[1]
|
||||
set -l rebind true
|
||||
if test "$argv[1]" = "--no-erase"
|
||||
set rebind false
|
||||
set -e argv[1]
|
||||
else
|
||||
bind --erase --all # clear earlier bindings, if any
|
||||
end
|
||||
|
||||
# Allow just calling this function to correctly set the bindings.
|
||||
# Because it's a rather discoverable name, users will execute it
|
||||
# and without this would then have subtly broken bindings.
|
||||
if test "$fish_key_bindings" != "fish_vi_key_bindings"
|
||||
# Allow the user to set the variable universally
|
||||
and test "$rebind" = "true"
|
||||
# Allow the user to set the variable universally.
|
||||
set -q fish_key_bindings
|
||||
or set -g fish_key_bindings
|
||||
set fish_key_bindings fish_vi_key_bindings # This triggers the handler, which calls us again and ensures the user_key_bindings are executed
|
||||
# This triggers the handler, which calls us again and ensures the user_key_bindings
|
||||
# are executed.
|
||||
set fish_key_bindings fish_vi_key_bindings
|
||||
return
|
||||
end
|
||||
|
||||
# The default escape timeout is 300ms. But for users of Vi bindings that can be slightly
|
||||
# annoying when trying to switch to Vi "normal" mode. So set a shorter timeout in this case
|
||||
# unless the user has explicitly set the delay.
|
||||
set -q fish_escape_delay_ms; or set -g fish_escape_delay_ms 100
|
||||
set -q fish_escape_delay_ms
|
||||
or set -g fish_escape_delay_ms 100
|
||||
|
||||
set -l init_mode insert
|
||||
# These are only the special vi-style keys
|
||||
|
||||
@@ -2,7 +2,6 @@ function help --description 'Show help for the fish shell'
|
||||
|
||||
# Declare variables to set correct scope
|
||||
set -l fish_browser
|
||||
set -l fish_browser_bg
|
||||
|
||||
set -l h syntax completion editor job-control todo bugs history killring help
|
||||
set h $h color prompt title variables builtin-overview changes expand
|
||||
@@ -23,58 +22,58 @@ function help --description 'Show help for the fish shell'
|
||||
# by the help function defined below.
|
||||
#
|
||||
set -l graphical_browsers htmlview x-www-browser firefox galeon mozilla konqueror epiphany opera netscape rekonq google-chrome chromium-browser
|
||||
set -l text_browsers htmlview www-browser links elinks lynx w3m
|
||||
|
||||
if type -q "$BROWSER"
|
||||
# User has manually set a preferred browser, so we respect that
|
||||
set fish_browser $BROWSER
|
||||
|
||||
# If browser is known to be graphical, put into background
|
||||
if contains -- $BROWSER $graphical_browsers
|
||||
set fish_browser_bg 1
|
||||
end
|
||||
if set -q fish_help_browser[1]
|
||||
# User has set a fish-specific help browser. This overrides the
|
||||
# browser that may be defined by $BROWSER. The fish_help_browser
|
||||
# variable may be an array containing a browser name plus options.
|
||||
set fish_browser $fish_help_browser
|
||||
else
|
||||
# Check for a text-based browser.
|
||||
for i in $text_browsers
|
||||
if type -q -f $i
|
||||
set fish_browser $i
|
||||
break
|
||||
end
|
||||
end
|
||||
set -l text_browsers htmlview www-browser links elinks lynx w3m
|
||||
|
||||
# If we are in a graphical environment, check if there is a graphical
|
||||
# browser to use instead.
|
||||
if test "$DISPLAY" -a \( "$XAUTHORITY" = "$HOME/.Xauthority" -o "$XAUTHORITY" = "" \)
|
||||
for i in $graphical_browsers
|
||||
if set -q BROWSER
|
||||
# User has manually set a preferred browser, so we respect that
|
||||
set fish_browser $BROWSER
|
||||
else
|
||||
# Check for a text-based browser.
|
||||
for i in $text_browsers
|
||||
if type -q -f $i
|
||||
set fish_browser $i
|
||||
set fish_browser_bg 1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# If we are in a graphical environment, check if there is a graphical
|
||||
# browser to use instead.
|
||||
if test "$DISPLAY" -a \( "$XAUTHORITY" = "$HOME/.Xauthority" -o "$XAUTHORITY" = "" \)
|
||||
for i in $graphical_browsers
|
||||
if type -q -f $i
|
||||
set fish_browser $i
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# If the OS appears to be Windows (graphical), try to use cygstart
|
||||
if type -q cygstart
|
||||
set fish_browser cygstart
|
||||
# If xdg-open is available, just use that
|
||||
else if type -q xdg-open
|
||||
set fish_browser xdg-open
|
||||
end
|
||||
# If the OS appears to be Windows (graphical), try to use cygstart
|
||||
if type -q cygstart
|
||||
set fish_browser cygstart
|
||||
# If xdg-open is available, just use that
|
||||
else if type -q xdg-open
|
||||
set fish_browser xdg-open
|
||||
end
|
||||
|
||||
|
||||
# On OS X, we go through osascript by default
|
||||
if test (uname) = Darwin
|
||||
if type -q osascript
|
||||
set fish_browser osascript
|
||||
# On OS X, we go through osascript by default
|
||||
if test (uname) = Darwin
|
||||
if type -q osascript
|
||||
set fish_browser osascript
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if test -z $fish_browser
|
||||
if not set -q fish_browser
|
||||
printf (_ '%s: Could not find a web browser.\n') help
|
||||
printf (_ 'Please set the variable $BROWSER to a suitable browser and try again.\n\n')
|
||||
printf (_ 'Please set the variable $BROWSER or fish_help_browser and try again.\n\n')
|
||||
return 1
|
||||
end
|
||||
|
||||
@@ -136,17 +135,15 @@ function help --description 'Show help for the fish shell'
|
||||
return
|
||||
end
|
||||
|
||||
if test $fish_browser_bg
|
||||
|
||||
switch $fish_browser
|
||||
# If browser is known to be graphical, put into background
|
||||
if contains -- $fish_browser[1] $graphical_browsers
|
||||
switch $fish_browser[1]
|
||||
case 'htmlview' 'x-www-browser'
|
||||
printf (_ 'help: Help is being displayed in your default browser.\n')
|
||||
|
||||
case '*'
|
||||
printf (_ 'help: Help is being displayed in %s.\n') $fish_browser
|
||||
|
||||
printf (_ 'help: Help is being displayed in %s.\n') $fish_browser[1]
|
||||
end
|
||||
|
||||
eval "$fish_browser $page_url &"
|
||||
else
|
||||
eval $fish_browser $page_url
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# application for the file.
|
||||
#
|
||||
|
||||
if not test (uname) = Darwin
|
||||
if not command -s open >/dev/null
|
||||
function open --description "Open file in default application"
|
||||
if count $argv >/dev/null
|
||||
switch $argv[1]
|
||||
|
||||
10
share/functions/prompt_hostname.fish
Normal file
10
share/functions/prompt_hostname.fish
Normal file
@@ -0,0 +1,10 @@
|
||||
# Fetching the host name can be expensive if there is a problem with DNS or whatever subsystem the
|
||||
# hostname command uses. So cache the answer so including it in the prompt doesn't make fish seem
|
||||
# slow.
|
||||
if not set -q __fish_prompt_hostname
|
||||
set -g __fish_prompt_hostname (hostname | string split '.')[1]
|
||||
end
|
||||
|
||||
function prompt_hostname
|
||||
echo $__fish_prompt_hostname
|
||||
end
|
||||
@@ -1,50 +1,53 @@
|
||||
# Provide a minimalist realpath implementation to help deal with platforms that may not provide it
|
||||
# as a command. If a realpath command is available simply pass all arguments thru to it. If not
|
||||
# fallback to alternative solutions.
|
||||
# as a command. If an external realpath or grealpath command is available simply pass all arguments
|
||||
# thru to it. If not fallback to our builtin.
|
||||
|
||||
# The following is slightly subtle. The first time `realpath` is invoked by autoloading this script
|
||||
# will be read. If we see that there is an external realpath command we just return. That will cause
|
||||
# fish to run the external command. Or, if there is a grealpath, we alias it.
|
||||
# On the other hand, if an external command isn't found we provide a function that will facilitate
|
||||
# fallback behavion through our builtin.
|
||||
# The following is slightly subtle. We have to define a realpath function even if there is an
|
||||
# external command by that name. That's because if we don't the parser will select our builtin.
|
||||
# However, we only want our builtin if there is no external realpath command.
|
||||
|
||||
if not command -s realpath >/dev/null
|
||||
# If there is a HomeBrew installed version of GNU realpath named grealpath use that.
|
||||
if command -s grealpath >/dev/null
|
||||
function realpath -w grealpath -d "print the resolved path [grealpath]"
|
||||
grealpath $argv
|
||||
end
|
||||
exit 0
|
||||
if command -s realpath >/dev/null
|
||||
function realpath -w realpath -d "print the resolved path [command realpath]"
|
||||
command realpath $argv
|
||||
end
|
||||
exit 0
|
||||
end
|
||||
|
||||
# If there is a HomeBrew installed version of GNU realpath named grealpath use that.
|
||||
if command -s grealpath >/dev/null
|
||||
function realpath -w grealpath -d "print the resolved path [command grealpath]"
|
||||
command grealpath $argv
|
||||
end
|
||||
exit 0
|
||||
end
|
||||
|
||||
function realpath -d "return an absolute path without symlinks"
|
||||
if test -z "$argv"
|
||||
printf "usage: %s%s%s %sfile%s …\n" (set_color -o) $_ (set_color normal) (set_color -u) (set_color normal)
|
||||
echo " resolves files as absolute paths without symlinks"
|
||||
return 1
|
||||
end
|
||||
|
||||
function realpath -d "return an absolute path without symlinks"
|
||||
if test -z "$argv"
|
||||
printf "usage: %s%s%s %sfile%s …\n" (set_color -o) $_ (set_color normal) (set_color -u) (set_color normal)
|
||||
echo " resolves files as absolute paths without symlinks"
|
||||
return 1
|
||||
end
|
||||
# Loop over arguments - allow our realpath to work on more than one path per invocation
|
||||
# like gnu/bsd realpath.
|
||||
for arg in $argv
|
||||
switch $arg
|
||||
# These - no can do our realpath
|
||||
case -s --strip --no-symlinks -z --zero --relative-base\* --relative-to\*
|
||||
__fish_print_help realpath
|
||||
return 2
|
||||
|
||||
# Loop over arguments - allow our realpath to work on more than one path per invocation
|
||||
# like gnu/bsd realpath.
|
||||
for arg in $argv
|
||||
switch $arg
|
||||
# These - no can do our realpath
|
||||
case -s --strip --no-symlinks -z --zero --relative-base\* --relative-to\*
|
||||
__fish_print_help realpath
|
||||
return 2
|
||||
|
||||
case -h --help --version
|
||||
__fish_print_help realpath
|
||||
return 0
|
||||
case -h --help --version
|
||||
__fish_print_help realpath
|
||||
return 0
|
||||
|
||||
# Handle commands called with these arguments by dropping the arguments to protect
|
||||
# realpath from them. There are no sure things here.
|
||||
case -e --canonicalize-existing --physical -P -q --quiet -m --canonicalize-missing
|
||||
continue
|
||||
case -e --canonicalize-existing --physical -P -q --quiet -m --canonicalize-missing
|
||||
continue
|
||||
|
||||
case "*"
|
||||
builtin realpath $arg
|
||||
end
|
||||
case "*"
|
||||
builtin realpath $arg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -37,7 +37,7 @@ function vared --description "Edit variable value"
|
||||
end
|
||||
end
|
||||
else
|
||||
printf (_ '%s: %s is an array variable. Use %svared%s %s[n]%s to edit the n:th element of %s\n') vared $argv (set_color $fish_color_command; echo) (set_color $fish_color_normal; echo) $argv (set_color reset; echo) $argv
|
||||
printf (_ '%s: %s is an array variable. Use %svared%s %s[n]%s to edit the n:th element of %s\n') vared $argv (set_color $fish_color_command; echo) (set_color $fish_color_normal; echo) $argv (set_color normal; echo) $argv
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
14
share/groff/fish.tmac
Normal file
14
share/groff/fish.tmac
Normal file
@@ -0,0 +1,14 @@
|
||||
.\" This is needed on systems that ship with groff versions older than 1.20;
|
||||
.\" such as macOS up thru Sierra (10.12). See fish issue #2673.
|
||||
.\"
|
||||
.\" For UTF-8, map some characters conservatively for the sake
|
||||
.\" of easy cut and paste.
|
||||
.
|
||||
.if '\*[.T]'utf8' \{\
|
||||
. rchar \- - ' `
|
||||
.
|
||||
. char \- \N'45'
|
||||
. char - \N'45'
|
||||
. char ' \N'39'
|
||||
. char ` \N'96'
|
||||
.\}
|
||||
@@ -12,8 +12,8 @@ function fish_prompt -d "Write out the prompt"
|
||||
if [ (_git_branch_name) ]
|
||||
set -l git_branch (set_color -o blue)(_git_branch_name)
|
||||
if [ (_is_git_dirty) ]
|
||||
for i in (git branch -qv --no-color| string match -r \*|cut -d' ' -f4-|cut -d] -f1|tr , \n)\
|
||||
(git status --porcelain | cut -c 1-2 | uniq)
|
||||
for i in (git branch -qv --no-color | string match -r \* | cut -d' ' -f4- | cut -d] -f1 | tr , \n)\
|
||||
(git status --porcelain | cut -c 1-2 | uniq)
|
||||
switch $i
|
||||
case "*[ahead *"
|
||||
set git_status "$git_status"(set_color red)⬆
|
||||
@@ -39,29 +39,10 @@ function fish_prompt -d "Write out the prompt"
|
||||
set git_info "(git$git_status$git_branch"(set_color white)")"
|
||||
end
|
||||
set_color -b black
|
||||
printf '%s%s%s%s%s%s%s%s%s%s%s%s%s'\
|
||||
(set_color -o white) \
|
||||
'❰' \
|
||||
(set_color green) \
|
||||
$USER \
|
||||
(set_color white) \
|
||||
'❙' \
|
||||
(set_color yellow) \
|
||||
(echo $PWD | sed -e "s|^$HOME|~|") \
|
||||
(set_color white) \
|
||||
$git_info \
|
||||
(set_color white) \
|
||||
'❱' \
|
||||
(set_color white)
|
||||
printf '%s%s%s%s%s%s%s%s%s%s%s%s%s' (set_color -o white) '❰' (set_color green) $USER (set_color white) '❙' (set_color yellow) (echo $PWD | sed -e "s|^$HOME|~|") (set_color white) $git_info (set_color white) '❱' (set_color white)
|
||||
if test $laststatus -eq 0
|
||||
printf "%s✔%s≻%s " \
|
||||
(set_color -o green)\
|
||||
(set_color white) \
|
||||
(set_color normal)
|
||||
printf "%s✔%s≻%s " (set_color -o green) (set_color white) (set_color normal)
|
||||
else
|
||||
printf "%s✘%s≻%s " \
|
||||
(set_color -o red) \
|
||||
(set_color white) \
|
||||
(set_color normal)
|
||||
printf "%s✘%s≻%s " (set_color -o red) (set_color white) (set_color normal)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
# name: Classic
|
||||
function fish_prompt --description "Write out the prompt"
|
||||
# Just calculate this once, to save a few cycles when displaying the prompt
|
||||
if not set -q __fish_prompt_hostname
|
||||
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
|
||||
end
|
||||
set -l color_cwd
|
||||
set -l suffix
|
||||
switch $USER
|
||||
case root toor
|
||||
if set -q fish_color_cwd_root
|
||||
set color_cwd $fish_color_cwd_root
|
||||
else
|
||||
set color_cwd $fish_color_cwd
|
||||
end
|
||||
set suffix '#'
|
||||
case '*'
|
||||
set color_cwd $fish_color_cwd
|
||||
set suffix '>'
|
||||
end
|
||||
|
||||
set -l color_cwd
|
||||
set -l suffix
|
||||
switch $USER
|
||||
case root toor
|
||||
if set -q fish_color_cwd_root
|
||||
set color_cwd $fish_color_cwd_root
|
||||
else
|
||||
set color_cwd $fish_color_cwd
|
||||
end
|
||||
set suffix '#'
|
||||
case '*'
|
||||
set color_cwd $fish_color_cwd
|
||||
set suffix '>'
|
||||
end
|
||||
|
||||
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
|
||||
echo -n -s "$USER" @ (prompt_hostname) ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
|
||||
end
|
||||
|
||||
@@ -10,25 +10,20 @@ function fish_prompt --description "Write out the prompt"
|
||||
printf "%s(%d)%s " (set_color red --bold) $last_status (set_color normal)
|
||||
end
|
||||
|
||||
# Just calculate this once, to save a few cycles when displaying the prompt
|
||||
if not set -q __fish_prompt_hostname
|
||||
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
|
||||
end
|
||||
|
||||
set -l color_cwd
|
||||
set -l suffix
|
||||
switch $USER
|
||||
case root toor
|
||||
if set -q fish_color_cwd_root
|
||||
set color_cwd $fish_color_cwd_root
|
||||
else
|
||||
case root toor
|
||||
if set -q fish_color_cwd_root
|
||||
set color_cwd $fish_color_cwd_root
|
||||
else
|
||||
set color_cwd $fish_color_cwd
|
||||
end
|
||||
set suffix '#'
|
||||
case '*'
|
||||
set color_cwd $fish_color_cwd
|
||||
end
|
||||
set suffix '#'
|
||||
case '*'
|
||||
set color_cwd $fish_color_cwd
|
||||
set suffix '>'
|
||||
set suffix '>'
|
||||
end
|
||||
|
||||
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
|
||||
echo -n -s "$USER" @ (prompt_hostname) ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
|
||||
end
|
||||
|
||||
@@ -3,71 +3,68 @@
|
||||
# vim: set noet:
|
||||
|
||||
function fish_prompt --description 'Write out the prompt'
|
||||
set -l last_status $status
|
||||
set -l last_status $status
|
||||
set -l normal (set_color normal)
|
||||
|
||||
# Just calculate this once, to save a few cycles when displaying the prompt
|
||||
if not set -q __fish_prompt_hostname
|
||||
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
|
||||
end
|
||||
# Hack; fish_config only copies the fish_prompt function (see #736)
|
||||
if not set -q -g __fish_classic_git_functions_defined
|
||||
set -g __fish_classic_git_functions_defined
|
||||
|
||||
set -l normal (set_color normal)
|
||||
function __fish_repaint_user --on-variable fish_color_user --description "Event handler, repaint when fish_color_user changes"
|
||||
if status --is-interactive
|
||||
commandline -f repaint ^/dev/null
|
||||
end
|
||||
end
|
||||
|
||||
# Hack; fish_config only copies the fish_prompt function (see #736)
|
||||
if not set -q -g __fish_classic_git_functions_defined
|
||||
set -g __fish_classic_git_functions_defined
|
||||
function __fish_repaint_host --on-variable fish_color_host --description "Event handler, repaint when fish_color_host changes"
|
||||
if status --is-interactive
|
||||
commandline -f repaint ^/dev/null
|
||||
end
|
||||
end
|
||||
|
||||
function __fish_repaint_user --on-variable fish_color_user --description "Event handler, repaint when fish_color_user changes"
|
||||
if status --is-interactive
|
||||
commandline -f repaint ^/dev/null
|
||||
end
|
||||
end
|
||||
|
||||
function __fish_repaint_host --on-variable fish_color_host --description "Event handler, repaint when fish_color_host changes"
|
||||
if status --is-interactive
|
||||
commandline -f repaint ^/dev/null
|
||||
end
|
||||
end
|
||||
|
||||
function __fish_repaint_status --on-variable fish_color_status --description "Event handler; repaint when fish_color_status changes"
|
||||
if status --is-interactive
|
||||
commandline -f repaint ^/dev/null
|
||||
end
|
||||
end
|
||||
function __fish_repaint_status --on-variable fish_color_status --description "Event handler; repaint when fish_color_status changes"
|
||||
if status --is-interactive
|
||||
commandline -f repaint ^/dev/null
|
||||
end
|
||||
end
|
||||
|
||||
function __fish_repaint_bind_mode --on-variable fish_key_bindings --description "Event handler; repaint when fish_key_bindings changes"
|
||||
if status --is-interactive
|
||||
commandline -f repaint ^/dev/null
|
||||
end
|
||||
end
|
||||
function __fish_repaint_bind_mode --on-variable fish_key_bindings --description "Event handler; repaint when fish_key_bindings changes"
|
||||
if status --is-interactive
|
||||
commandline -f repaint ^/dev/null
|
||||
end
|
||||
end
|
||||
|
||||
# initialize our new variables
|
||||
if not set -q __fish_classic_git_prompt_initialized
|
||||
set -qU fish_color_user; or set -U fish_color_user -o green
|
||||
set -qU fish_color_host; or set -U fish_color_host -o cyan
|
||||
set -qU fish_color_status; or set -U fish_color_status red
|
||||
set -U __fish_classic_git_prompt_initialized
|
||||
end
|
||||
end
|
||||
# initialize our new variables
|
||||
if not set -q __fish_classic_git_prompt_initialized
|
||||
set -qU fish_color_user
|
||||
or set -U fish_color_user -o green
|
||||
set -qU fish_color_host
|
||||
or set -U fish_color_host -o cyan
|
||||
set -qU fish_color_status
|
||||
or set -U fish_color_status red
|
||||
set -U __fish_classic_git_prompt_initialized
|
||||
end
|
||||
end
|
||||
|
||||
set -l color_cwd
|
||||
set -l prefix
|
||||
switch $USER
|
||||
case root toor
|
||||
if set -q fish_color_cwd_root
|
||||
set color_cwd $fish_color_cwd_root
|
||||
else
|
||||
set color_cwd $fish_color_cwd
|
||||
end
|
||||
set suffix '#'
|
||||
case '*'
|
||||
set color_cwd $fish_color_cwd
|
||||
set suffix '>'
|
||||
end
|
||||
set -l color_cwd
|
||||
set -l prefix
|
||||
switch $USER
|
||||
case root toor
|
||||
if set -q fish_color_cwd_root
|
||||
set color_cwd $fish_color_cwd_root
|
||||
else
|
||||
set color_cwd $fish_color_cwd
|
||||
end
|
||||
set suffix '#'
|
||||
case '*'
|
||||
set color_cwd $fish_color_cwd
|
||||
set suffix '>'
|
||||
end
|
||||
|
||||
set -l prompt_status
|
||||
if test $last_status -ne 0
|
||||
set prompt_status ' ' (set_color $fish_color_status) "[$last_status]" "$normal"
|
||||
end
|
||||
set -l prompt_status
|
||||
if test $last_status -ne 0
|
||||
set prompt_status ' ' (set_color $fish_color_status) "[$last_status]" "$normal"
|
||||
end
|
||||
|
||||
echo -n -s (set_color $fish_color_user) "$USER" $normal @ (set_color $fish_color_host) "$__fish_prompt_hostname" $normal ' ' (set_color $color_cwd) (prompt_pwd) $normal (__fish_vcs_prompt) $normal $prompt_status "> "
|
||||
echo -n -s (set_color $fish_color_user) "$USER" $normal @ (set_color $fish_color_host) (prompt_hostname) $normal ' ' (set_color $color_cwd) (prompt_pwd) $normal (__fish_vcs_prompt) $normal $prompt_status "> "
|
||||
end
|
||||
|
||||
@@ -2,54 +2,55 @@
|
||||
# author: Maurizio De Santis
|
||||
|
||||
function fish_prompt --description 'Write out the prompt, prepending the Debian chroot environment if present'
|
||||
if not set -q __fish_prompt_normal
|
||||
set -g __fish_prompt_normal (set_color normal)
|
||||
end
|
||||
|
||||
# Just calculate these once, to save a few cycles when displaying the prompt
|
||||
if not set -q __fish_prompt_hostname
|
||||
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
|
||||
if not set -q __fish_prompt_chroot_env
|
||||
set -g __fish_prompt_chroot_env (set_color yellow)
|
||||
end
|
||||
|
||||
# Set variable identifying the chroot you work in (used in the prompt below)
|
||||
if begin
|
||||
not set -q debian_chroot
|
||||
and test -r /etc/debian_chroot
|
||||
end
|
||||
|
||||
if not set -q __fish_prompt_normal
|
||||
set -g __fish_prompt_normal (set_color normal)
|
||||
set debian_chroot (cat /etc/debian_chroot)
|
||||
end
|
||||
if begin
|
||||
not set -q __fish_debian_chroot_prompt
|
||||
and set -q debian_chroot
|
||||
and test -n $debian_chroot
|
||||
end
|
||||
set -g __fish_debian_chroot_prompt "($debian_chroot)"
|
||||
end
|
||||
|
||||
if not set -q __fish_prompt_chroot_env
|
||||
set -g __fish_prompt_chroot_env (set_color yellow)
|
||||
end
|
||||
# Prepend the chroot environment if present
|
||||
if set -q __fish_debian_chroot_prompt
|
||||
echo -n -s "$__fish_prompt_chroot_env" "$__fish_debian_chroot_prompt" "$__fish_prompt_normal" ' '
|
||||
end
|
||||
|
||||
# Set variable identifying the chroot you work in (used in the prompt below)
|
||||
if begin; not set -q debian_chroot; and test -r /etc/debian_chroot; end
|
||||
set debian_chroot (cat /etc/debian_chroot)
|
||||
end
|
||||
if begin; not set -q __fish_debian_chroot_prompt; and set -q debian_chroot; and test -n $debian_chroot; end
|
||||
set -g __fish_debian_chroot_prompt "($debian_chroot)"
|
||||
end
|
||||
switch $USER
|
||||
|
||||
# Prepend the chroot environment if present
|
||||
if set -q __fish_debian_chroot_prompt
|
||||
echo -n -s "$__fish_prompt_chroot_env" "$__fish_debian_chroot_prompt" "$__fish_prompt_normal" ' '
|
||||
end
|
||||
case root toor
|
||||
|
||||
switch $USER
|
||||
|
||||
case root toor
|
||||
|
||||
if not set -q __fish_prompt_cwd
|
||||
if set -q fish_color_cwd_root
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd_root)
|
||||
else
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
|
||||
end
|
||||
if not set -q __fish_prompt_cwd
|
||||
if set -q fish_color_cwd_root
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd_root)
|
||||
else
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
|
||||
end
|
||||
end
|
||||
|
||||
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal" '# '
|
||||
echo -n -s "$USER" @ (prompt_hostname) ' ' "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal" '# '
|
||||
|
||||
case '*'
|
||||
case '*'
|
||||
|
||||
if not set -q __fish_prompt_cwd
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
|
||||
end
|
||||
if not set -q __fish_prompt_cwd
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
|
||||
end
|
||||
|
||||
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal" '> '
|
||||
echo -n -s "$USER" @ (prompt_hostname) ' ' "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal" '> '
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,46 +6,41 @@ function fish_prompt --description 'Write out the prompt'
|
||||
#Save the return status of the previous command
|
||||
set stat $status
|
||||
|
||||
# Just calculate these once, to save a few cycles when displaying the prompt
|
||||
if not set -q __fish_prompt_hostname
|
||||
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
|
||||
end
|
||||
|
||||
if not set -q __fish_prompt_normal
|
||||
if not set -q __fish_prompt_normal
|
||||
set -g __fish_prompt_normal (set_color normal)
|
||||
end
|
||||
|
||||
if not set -q __fish_color_blue
|
||||
if not set -q __fish_color_blue
|
||||
set -g __fish_color_blue (set_color -o blue)
|
||||
end
|
||||
|
||||
#Set the color for the status depending on the value
|
||||
#Set the color for the status depending on the value
|
||||
set __fish_color_status (set_color -o green)
|
||||
if test $stat -gt 0
|
||||
set __fish_color_status (set_color -o red)
|
||||
end
|
||||
|
||||
switch $USER
|
||||
switch $USER
|
||||
|
||||
case root toor
|
||||
case root toor
|
||||
|
||||
if not set -q __fish_prompt_cwd
|
||||
if set -q fish_color_cwd_root
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd_root)
|
||||
else
|
||||
if not set -q __fish_prompt_cwd
|
||||
if set -q fish_color_cwd_root
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd_root)
|
||||
else
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
|
||||
end
|
||||
end
|
||||
|
||||
printf '%s@%s %s%s%s# ' $USER (prompt_hostname) "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal"
|
||||
|
||||
case '*'
|
||||
|
||||
if not set -q __fish_prompt_cwd
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
|
||||
end
|
||||
end
|
||||
|
||||
printf '%s@%s %s%s%s# ' $USER $__fish_prompt_hostname "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal"
|
||||
|
||||
case '*'
|
||||
|
||||
if not set -q __fish_prompt_cwd
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
|
||||
end
|
||||
|
||||
printf '[%s] %s%s@%s %s%s %s(%s)%s \f\r> ' (date "+%H:%M:%S") "$__fish_color_blue" $USER $__fish_prompt_hostname "$__fish_prompt_cwd" "$PWD" "$__fish_color_status" "$stat" "$__fish_prompt_normal"
|
||||
printf '[%s] %s%s@%s %s%s %s(%s)%s \f\r> ' (date "+%H:%M:%S") "$__fish_color_blue" $USER (prompt_hostname) "$__fish_prompt_cwd" "$PWD" "$__fish_color_status" "$stat" "$__fish_prompt_normal"
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,94 +4,94 @@
|
||||
|
||||
|
||||
function fish_prompt --description 'Write out the prompt'
|
||||
if not set -q __fish_git_prompt_show_informative_status
|
||||
set -g __fish_git_prompt_show_informative_status 1
|
||||
end
|
||||
if not set -q __fish_git_prompt_hide_untrackedfiles
|
||||
set -g __fish_git_prompt_hide_untrackedfiles 1
|
||||
end
|
||||
if not set -q __fish_git_prompt_show_informative_status
|
||||
set -g __fish_git_prompt_show_informative_status 1
|
||||
end
|
||||
if not set -q __fish_git_prompt_hide_untrackedfiles
|
||||
set -g __fish_git_prompt_hide_untrackedfiles 1
|
||||
end
|
||||
|
||||
if not set -q __fish_git_prompt_color_branch
|
||||
set -g __fish_git_prompt_color_branch magenta --bold
|
||||
end
|
||||
if not set -q __fish_git_prompt_showupstream
|
||||
set -g __fish_git_prompt_showupstream "informative"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_upstream_ahead
|
||||
set -g __fish_git_prompt_char_upstream_ahead "↑"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_upstream_behind
|
||||
set -g __fish_git_prompt_char_upstream_behind "↓"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_upstream_prefix
|
||||
set -g __fish_git_prompt_char_upstream_prefix ""
|
||||
end
|
||||
if not set -q __fish_git_prompt_color_branch
|
||||
set -g __fish_git_prompt_color_branch magenta --bold
|
||||
end
|
||||
if not set -q __fish_git_prompt_showupstream
|
||||
set -g __fish_git_prompt_showupstream "informative"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_upstream_ahead
|
||||
set -g __fish_git_prompt_char_upstream_ahead "↑"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_upstream_behind
|
||||
set -g __fish_git_prompt_char_upstream_behind "↓"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_upstream_prefix
|
||||
set -g __fish_git_prompt_char_upstream_prefix ""
|
||||
end
|
||||
|
||||
if not set -q __fish_git_prompt_char_stagedstate
|
||||
set -g __fish_git_prompt_char_stagedstate "●"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_dirtystate
|
||||
set -g __fish_git_prompt_char_dirtystate "✚"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_untrackedfiles
|
||||
set -g __fish_git_prompt_char_untrackedfiles "…"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_conflictedstate
|
||||
set -g __fish_git_prompt_char_conflictedstate "✖"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_cleanstate
|
||||
set -g __fish_git_prompt_char_cleanstate "✔"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_stagedstate
|
||||
set -g __fish_git_prompt_char_stagedstate "●"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_dirtystate
|
||||
set -g __fish_git_prompt_char_dirtystate "✚"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_untrackedfiles
|
||||
set -g __fish_git_prompt_char_untrackedfiles "…"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_conflictedstate
|
||||
set -g __fish_git_prompt_char_conflictedstate "✖"
|
||||
end
|
||||
if not set -q __fish_git_prompt_char_cleanstate
|
||||
set -g __fish_git_prompt_char_cleanstate "✔"
|
||||
end
|
||||
|
||||
if not set -q __fish_git_prompt_color_dirtystate
|
||||
set -g __fish_git_prompt_color_dirtystate blue
|
||||
end
|
||||
if not set -q __fish_git_prompt_color_stagedstate
|
||||
set -g __fish_git_prompt_color_stagedstate yellow
|
||||
end
|
||||
if not set -q __fish_git_prompt_color_invalidstate
|
||||
set -g __fish_git_prompt_color_invalidstate red
|
||||
end
|
||||
if not set -q __fish_git_prompt_color_untrackedfiles
|
||||
set -g __fish_git_prompt_color_untrackedfiles $fish_color_normal
|
||||
end
|
||||
if not set -q __fish_git_prompt_color_cleanstate
|
||||
set -g __fish_git_prompt_color_cleanstate green --bold
|
||||
end
|
||||
if not set -q __fish_git_prompt_color_dirtystate
|
||||
set -g __fish_git_prompt_color_dirtystate blue
|
||||
end
|
||||
if not set -q __fish_git_prompt_color_stagedstate
|
||||
set -g __fish_git_prompt_color_stagedstate yellow
|
||||
end
|
||||
if not set -q __fish_git_prompt_color_invalidstate
|
||||
set -g __fish_git_prompt_color_invalidstate red
|
||||
end
|
||||
if not set -q __fish_git_prompt_color_untrackedfiles
|
||||
set -g __fish_git_prompt_color_untrackedfiles $fish_color_normal
|
||||
end
|
||||
if not set -q __fish_git_prompt_color_cleanstate
|
||||
set -g __fish_git_prompt_color_cleanstate green --bold
|
||||
end
|
||||
|
||||
set -l last_status $status
|
||||
set -l last_status $status
|
||||
|
||||
if not set -q __fish_prompt_normal
|
||||
set -g __fish_prompt_normal (set_color normal)
|
||||
end
|
||||
if not set -q __fish_prompt_normal
|
||||
set -g __fish_prompt_normal (set_color normal)
|
||||
end
|
||||
|
||||
set -l color_cwd
|
||||
set -l prefix
|
||||
switch $USER
|
||||
case root toor
|
||||
if set -q fish_color_cwd_root
|
||||
set color_cwd $fish_color_cwd_root
|
||||
else
|
||||
set color_cwd $fish_color_cwd
|
||||
end
|
||||
set suffix '#'
|
||||
case '*'
|
||||
set color_cwd $fish_color_cwd
|
||||
set suffix '$'
|
||||
end
|
||||
set -l color_cwd
|
||||
set -l prefix
|
||||
switch $USER
|
||||
case root toor
|
||||
if set -q fish_color_cwd_root
|
||||
set color_cwd $fish_color_cwd_root
|
||||
else
|
||||
set color_cwd $fish_color_cwd
|
||||
end
|
||||
set suffix '#'
|
||||
case '*'
|
||||
set color_cwd $fish_color_cwd
|
||||
set suffix '$'
|
||||
end
|
||||
|
||||
# PWD
|
||||
set_color $color_cwd
|
||||
echo -n (prompt_pwd)
|
||||
set_color normal
|
||||
# PWD
|
||||
set_color $color_cwd
|
||||
echo -n (prompt_pwd)
|
||||
set_color normal
|
||||
|
||||
printf '%s ' (__fish_vcs_prompt)
|
||||
printf '%s ' (__fish_vcs_prompt)
|
||||
|
||||
if not test $last_status -eq 0
|
||||
set_color $fish_color_error
|
||||
end
|
||||
if not test $last_status -eq 0
|
||||
set_color $fish_color_error
|
||||
end
|
||||
|
||||
echo -n "$suffix "
|
||||
echo -n "$suffix "
|
||||
|
||||
set_color normal
|
||||
set_color normal
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# name: Just a Dollar
|
||||
function fish_prompt
|
||||
echo -n '$ '
|
||||
echo -n '$ '
|
||||
end
|
||||
|
||||
@@ -2,19 +2,13 @@
|
||||
# author: Steve
|
||||
|
||||
function fish_prompt --description 'Write out the prompt'
|
||||
# Just calculate these once, to save a few cycles when displaying the prompt
|
||||
if not set -q __fish_prompt_hostname
|
||||
set -g __fish_prompt_hostname (hostname -s)
|
||||
end
|
||||
if not set -q __fish_prompt_normal
|
||||
set -g __fish_prompt_normal (set_color normal)
|
||||
end
|
||||
|
||||
if not set -q __fish_prompt_normal
|
||||
set -g __fish_prompt_normal (set_color normal)
|
||||
end
|
||||
|
||||
if not set -q __fish_prompt_cwd
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
|
||||
end
|
||||
|
||||
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' "$__fish_prompt_cwd" (prompt_pwd) (__fish_vcs_prompt) "$__fish_prompt_normal" '> '
|
||||
if not set -q __fish_prompt_cwd
|
||||
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
|
||||
end
|
||||
|
||||
echo -n -s "$USER" @ (prompt_hostname) ' ' "$__fish_prompt_cwd" (prompt_pwd) (__fish_vcs_prompt) "$__fish_prompt_normal" '> '
|
||||
end
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# author: ridiculous_fish
|
||||
|
||||
function fish_prompt
|
||||
set_color $fish_color_cwd
|
||||
echo -n (basename $PWD)
|
||||
set_color normal
|
||||
echo -n ' ) '
|
||||
set_color $fish_color_cwd
|
||||
echo -n (basename $PWD)
|
||||
set_color normal
|
||||
echo -n ' ) '
|
||||
end
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
# author: Guilhem "Nim" Saurel − https://github.com/nim65s/dotfiles/
|
||||
|
||||
function fish_prompt
|
||||
and set retc green; or set retc red
|
||||
tty|string match -q -r tty; and set tty tty; or set tty pts
|
||||
and set retc green
|
||||
or set retc red
|
||||
tty | string match -q -r tty
|
||||
and set tty tty
|
||||
or set tty pts
|
||||
|
||||
set_color $retc
|
||||
if [ $tty = tty ]
|
||||
@@ -26,7 +29,7 @@ function fish_prompt
|
||||
else
|
||||
set_color -o cyan
|
||||
end
|
||||
echo -n (hostname)
|
||||
echo -n (prompt_hostname)
|
||||
set_color -o white
|
||||
#echo -n :(prompt_pwd)
|
||||
echo -n :(pwd|sed "s=$HOME=~=")
|
||||
@@ -46,16 +49,16 @@ function fish_prompt
|
||||
echo -n (date +%X)
|
||||
set_color -o green
|
||||
echo -n ]
|
||||
|
||||
|
||||
if type -q acpi
|
||||
if [ (acpi -a 2> /dev/null | string match -r off) ]
|
||||
echo -n '─['
|
||||
set_color -o red
|
||||
echo -n (acpi -b|cut -d' ' -f 4-)
|
||||
set_color -o green
|
||||
echo -n ']'
|
||||
end
|
||||
end
|
||||
if [ (acpi -a 2> /dev/null | string match -r off) ]
|
||||
echo -n '─['
|
||||
set_color -o red
|
||||
echo -n (acpi -b|cut -d' ' -f 4-)
|
||||
set_color -o green
|
||||
echo -n ']'
|
||||
end
|
||||
end
|
||||
echo
|
||||
set_color normal
|
||||
for job in (jobs)
|
||||
|
||||
@@ -3,28 +3,28 @@
|
||||
|
||||
|
||||
function fish_prompt
|
||||
if not set -q VIRTUAL_ENV_DISABLE_PROMPT
|
||||
set -g VIRTUAL_ENV_DISABLE_PROMPT true
|
||||
end
|
||||
set_color yellow
|
||||
printf '%s' (whoami)
|
||||
set_color normal
|
||||
printf ' at '
|
||||
if not set -q VIRTUAL_ENV_DISABLE_PROMPT
|
||||
set -g VIRTUAL_ENV_DISABLE_PROMPT true
|
||||
end
|
||||
set_color yellow
|
||||
printf '%s' (whoami)
|
||||
set_color normal
|
||||
printf ' at '
|
||||
|
||||
set_color magenta
|
||||
printf '%s' (hostname|cut -d . -f 1)
|
||||
set_color normal
|
||||
printf ' in '
|
||||
set_color magenta
|
||||
echo -n (prompt_hostname)
|
||||
set_color normal
|
||||
printf ' in '
|
||||
|
||||
set_color $fish_color_cwd
|
||||
printf '%s' (prompt_pwd)
|
||||
set_color normal
|
||||
set_color $fish_color_cwd
|
||||
printf '%s' (prompt_pwd)
|
||||
set_color normal
|
||||
|
||||
# Line 2
|
||||
echo
|
||||
if test $VIRTUAL_ENV
|
||||
printf "(%s) " (set_color blue)(basename $VIRTUAL_ENV)(set_color normal)
|
||||
end
|
||||
printf '↪ '
|
||||
set_color normal
|
||||
# Line 2
|
||||
echo
|
||||
if test $VIRTUAL_ENV
|
||||
printf "(%s) " (set_color blue)(basename $VIRTUAL_ENV)(set_color normal)
|
||||
end
|
||||
printf '↪ '
|
||||
set_color normal
|
||||
end
|
||||
|
||||
@@ -3,74 +3,76 @@
|
||||
|
||||
function fish_prompt
|
||||
|
||||
if not set -q -g __fish_robbyrussell_functions_defined
|
||||
set -g __fish_robbyrussell_functions_defined
|
||||
function _git_branch_name
|
||||
echo (git symbolic-ref HEAD ^/dev/null | sed -e 's|^refs/heads/||')
|
||||
if not set -q -g __fish_robbyrussell_functions_defined
|
||||
set -g __fish_robbyrussell_functions_defined
|
||||
function _git_branch_name
|
||||
echo (git symbolic-ref HEAD ^/dev/null | sed -e 's|^refs/heads/||')
|
||||
end
|
||||
|
||||
function _is_git_dirty
|
||||
echo (git status -s --ignore-submodules=dirty ^/dev/null)
|
||||
end
|
||||
|
||||
function _is_git_repo
|
||||
type -q git
|
||||
or return 1
|
||||
git status -s >/dev/null ^/dev/null
|
||||
end
|
||||
|
||||
function _hg_branch_name
|
||||
echo (hg branch ^/dev/null)
|
||||
end
|
||||
|
||||
function _is_hg_dirty
|
||||
echo (hg status -mard ^/dev/null)
|
||||
end
|
||||
|
||||
function _is_hg_repo
|
||||
type -q hg
|
||||
or return 1
|
||||
hg summary >/dev/null ^/dev/null
|
||||
end
|
||||
|
||||
function _repo_branch_name
|
||||
eval "_$argv[1]_branch_name"
|
||||
end
|
||||
|
||||
function _is_repo_dirty
|
||||
eval "_is_$argv[1]_dirty"
|
||||
end
|
||||
|
||||
function _repo_type
|
||||
if _is_hg_repo
|
||||
echo 'hg'
|
||||
else if _is_git_repo
|
||||
echo 'git'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function _is_git_dirty
|
||||
echo (git status -s --ignore-submodules=dirty ^/dev/null)
|
||||
set -l cyan (set_color -o cyan)
|
||||
set -l yellow (set_color -o yellow)
|
||||
set -l red (set_color -o red)
|
||||
set -l blue (set_color -o blue)
|
||||
set -l normal (set_color normal)
|
||||
|
||||
set -l arrow "$red➜ "
|
||||
if [ $USER = 'root' ]
|
||||
set arrow "$red# "
|
||||
end
|
||||
|
||||
function _is_git_repo
|
||||
type -q git; or return 1
|
||||
git status -s >/dev/null ^/dev/null
|
||||
set -l cwd $cyan(basename (prompt_pwd))
|
||||
|
||||
set -l repo_type (_repo_type)
|
||||
if [ $repo_type ]
|
||||
set -l repo_branch $red(_repo_branch_name $repo_type)
|
||||
set repo_info "$blue $repo_type:($repo_branch$blue)"
|
||||
|
||||
if [ (_is_repo_dirty $repo_type) ]
|
||||
set -l dirty "$yellow ✗"
|
||||
set repo_info "$repo_info$dirty"
|
||||
end
|
||||
end
|
||||
|
||||
function _hg_branch_name
|
||||
echo (hg branch ^/dev/null)
|
||||
end
|
||||
|
||||
function _is_hg_dirty
|
||||
echo (hg status -mard ^/dev/null)
|
||||
end
|
||||
|
||||
function _is_hg_repo
|
||||
type -q hg; or return 1
|
||||
hg summary >/dev/null ^/dev/null
|
||||
end
|
||||
|
||||
function _repo_branch_name
|
||||
eval "_$argv[1]_branch_name"
|
||||
end
|
||||
|
||||
function _is_repo_dirty
|
||||
eval "_is_$argv[1]_dirty"
|
||||
end
|
||||
|
||||
function _repo_type
|
||||
if _is_hg_repo
|
||||
echo 'hg'
|
||||
else if _is_git_repo
|
||||
echo 'git'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
set -l cyan (set_color -o cyan)
|
||||
set -l yellow (set_color -o yellow)
|
||||
set -l red (set_color -o red)
|
||||
set -l blue (set_color -o blue)
|
||||
set -l normal (set_color normal)
|
||||
|
||||
set -l arrow "$red➜ "
|
||||
if [ $USER = 'root' ]
|
||||
set arrow "$red# "
|
||||
end
|
||||
|
||||
set -l cwd $cyan(basename (prompt_pwd))
|
||||
|
||||
set -l repo_type (_repo_type)
|
||||
if [ $repo_type ]
|
||||
set -l repo_branch $red(_repo_branch_name $repo_type)
|
||||
set repo_info "$blue $repo_type:($repo_branch$blue)"
|
||||
|
||||
if [ (_is_repo_dirty $repo_type) ]
|
||||
set -l dirty "$yellow ✗"
|
||||
set repo_info "$repo_info$dirty"
|
||||
end
|
||||
end
|
||||
|
||||
echo -n -s $arrow ' '$cwd $repo_info $normal ' '
|
||||
echo -n -s $arrow ' '$cwd $repo_info $normal ' '
|
||||
end
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# name: Screen Savvy
|
||||
# author: Matthias
|
||||
function fish_prompt -d "Write out the prompt"
|
||||
if test -z $WINDOW
|
||||
printf '%s%s@%s%s%s%s%s> ' (set_color yellow) (whoami) (set_color purple) (hostname|cut -d . -f 1) (set_color $fish_color_cwd) (prompt_pwd) (set_color normal)
|
||||
else
|
||||
printf '%s%s@%s%s%s(%s)%s%s%s> ' (set_color yellow) (whoami) (set_color purple) (hostname|cut -d . -f 1) (set_color white) (echo $WINDOW) (set_color $fish_color_cwd) (prompt_pwd) (set_color normal)
|
||||
end
|
||||
if test -z $WINDOW
|
||||
printf '%s%s@%s%s%s%s%s> ' (set_color yellow) (whoami) (set_color purple) (prompt_hostname) (set_color $fish_color_cwd) (prompt_pwd) (set_color normal)
|
||||
else
|
||||
printf '%s%s@%s%s%s(%s)%s%s%s> ' (set_color yellow) (whoami) (set_color purple) (prompt_hostname) (set_color white) (echo $WINDOW) (set_color $fish_color_cwd) (prompt_pwd) (set_color normal)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,52 +2,55 @@
|
||||
# author: Ivan Tham <ivanthamjunhoe@gmail.com>
|
||||
|
||||
function fish_prompt
|
||||
test $SSH_TTY; and printf (set_color red)(whoami)(set_color white)'@'(set_color yellow)(hostname)' '
|
||||
|
||||
test $USER = 'root'; and echo (set_color red)"#"
|
||||
test $SSH_TTY
|
||||
and printf (set_color red)$USER(set_color brwhite)'@'(set_color yellow)(prompt_hostname)' '
|
||||
test $USER = 'root'
|
||||
and echo (set_color red)"#"
|
||||
|
||||
# Main
|
||||
echo -n (set_color cyan)(prompt_pwd) (set_color red)'❯'(set_color yellow)'❯'(set_color green)'❯ '
|
||||
echo -n (set_color cyan)(prompt_pwd) (set_color red)'❯'(set_color yellow)'❯'(set_color green)'❯ '
|
||||
end
|
||||
|
||||
function fish_right_prompt
|
||||
# last status
|
||||
test $status != 0; and printf (set_color red)"⏎ "
|
||||
test $status != 0
|
||||
and printf (set_color red)"⏎ "
|
||||
|
||||
if git rev-parse ^ /dev/null
|
||||
# Purple if branch detached else green
|
||||
git branch -qv | grep "\*" | grep -q detached
|
||||
and set_color purple --bold
|
||||
or set_color green --bold
|
||||
if git rev-parse ^/dev/null
|
||||
# Magenta if branch detached else green
|
||||
git branch -qv | grep "\*" | string match -rq detached
|
||||
and set_color brmagenta
|
||||
or set_color brgreen
|
||||
|
||||
# Need optimization on this block (eliminate space)
|
||||
git name-rev --name-only HEAD
|
||||
|
||||
# Merging state
|
||||
git merge -q ^ /dev/null; or printf ':'(set_color red)'merge'
|
||||
git merge -q ^/dev/null
|
||||
or printf ':'(set_color red)'merge'
|
||||
printf ' '
|
||||
|
||||
# Symbols
|
||||
for i in (git branch -qv --no-color|grep \*|cut -d' ' -f4-|cut -d] -f1|tr , \n)\
|
||||
(git status --porcelain | cut -c 1-2 | uniq)
|
||||
switch $i
|
||||
for i in (git branch -qv --no-color|grep \*|cut -d' ' -f4-|cut -d] -f1|tr , \n)\
|
||||
(git status --porcelain | cut -c 1-2 | uniq)
|
||||
switch $i
|
||||
case "*[ahead *"
|
||||
printf (set_color purple)⬆' '
|
||||
printf (set_color magenta)⬆' '
|
||||
case "*behind *"
|
||||
printf (set_color purple)⬇' '
|
||||
case "."
|
||||
printf (set_color green)✚' '
|
||||
case " D"
|
||||
printf (set_color red)✖' '
|
||||
case "*M*"
|
||||
printf (set_color blue)✱' '
|
||||
printf (set_color magenta)⬇' '
|
||||
case "."
|
||||
printf (set_color green)✚' '
|
||||
case " D"
|
||||
printf (set_color red)✖' '
|
||||
case "*M*"
|
||||
printf (set_color blue)✱' '
|
||||
case "*R*"
|
||||
printf (set_color purple)➜' '
|
||||
printf (set_color brmagenta)➜' '
|
||||
case "*U*"
|
||||
printf (set_color brown)═' '
|
||||
case "??"
|
||||
printf (set_color white)◼' '
|
||||
end
|
||||
end
|
||||
end
|
||||
printf (set_color bryellow)═' '
|
||||
case "??"
|
||||
printf (set_color brwhite)◼' '
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,35 +2,35 @@
|
||||
# author: terlar - https://github.com/terlar
|
||||
|
||||
function fish_prompt --description 'Write out the prompt'
|
||||
set -l last_status $status
|
||||
set -l last_status $status
|
||||
|
||||
# User
|
||||
set_color $fish_color_user
|
||||
echo -n (whoami)
|
||||
set_color normal
|
||||
# User
|
||||
set_color $fish_color_user
|
||||
echo -n (whoami)
|
||||
set_color normal
|
||||
|
||||
echo -n '@'
|
||||
echo -n '@'
|
||||
|
||||
# Host
|
||||
set_color $fish_color_host
|
||||
echo -n (hostname -s)
|
||||
set_color normal
|
||||
# Host
|
||||
set_color $fish_color_host
|
||||
echo -n (prompt_hostname)
|
||||
set_color normal
|
||||
|
||||
echo -n ':'
|
||||
echo -n ':'
|
||||
|
||||
# PWD
|
||||
set_color $fish_color_cwd
|
||||
echo -n (prompt_pwd)
|
||||
set_color normal
|
||||
# PWD
|
||||
set_color $fish_color_cwd
|
||||
echo -n (prompt_pwd)
|
||||
set_color normal
|
||||
|
||||
__terlar_git_prompt
|
||||
__fish_hg_prompt
|
||||
echo
|
||||
__terlar_git_prompt
|
||||
__fish_hg_prompt
|
||||
echo
|
||||
|
||||
if not test $last_status -eq 0
|
||||
set_color $fish_color_error
|
||||
end
|
||||
if not test $last_status -eq 0
|
||||
set_color $fish_color_error
|
||||
end
|
||||
|
||||
echo -n '➤ '
|
||||
set_color normal
|
||||
echo -n '➤ '
|
||||
set_color normal
|
||||
end
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
# author: Jon Clayden
|
||||
|
||||
function fish_prompt -d "Write out the prompt"
|
||||
set -l home_escaped (echo -n $HOME | sed 's/\//\\\\\//g')
|
||||
set -l pwd (echo -n $PWD | sed "s/^$home_escaped/~/" | sed 's/ /%20/g')
|
||||
set -l prompt_symbol ''
|
||||
switch $USER
|
||||
case root toor; set prompt_symbol '#'
|
||||
case '*'; set prompt_symbol '$'
|
||||
end
|
||||
printf "[%s@%s %s%s%s]%s " $USER (hostname -s) (set_color $fish_color_cwd) $pwd (set_color normal) $prompt_symbol
|
||||
set -l home_escaped (echo -n $HOME | sed 's/\//\\\\\//g')
|
||||
set -l pwd (echo -n $PWD | sed "s/^$home_escaped/~/" | sed 's/ /%20/g')
|
||||
set -l prompt_symbol ''
|
||||
switch $USER
|
||||
case root toor
|
||||
set prompt_symbol '#'
|
||||
case '*'
|
||||
set prompt_symbol '$'
|
||||
end
|
||||
printf "[%s@%s %s%s%s]%s " $USER (prompt_hostname) (set_color $fish_color_cwd) $pwd (set_color normal) $prompt_symbol
|
||||
end
|
||||
|
||||
@@ -1,50 +1,49 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# Whether we're Python 2
|
||||
import sys
|
||||
import binascii
|
||||
import cgi
|
||||
import glob
|
||||
import multiprocessing.pool
|
||||
import os
|
||||
import operator
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import select
|
||||
import socket
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import webbrowser
|
||||
|
||||
FISH_BIN_PATH = False # will be set later
|
||||
IS_PY2 = sys.version_info[0] == 2
|
||||
|
||||
if IS_PY2:
|
||||
import SimpleHTTPServer
|
||||
import SocketServer
|
||||
from urlparse import parse_qs
|
||||
|
||||
else:
|
||||
import http.server as SimpleHTTPServer
|
||||
import socketserver as SocketServer
|
||||
from urllib.parse import parse_qs
|
||||
|
||||
# Check to see if IPv6 is enabled in the kernel
|
||||
HAS_IPV6 = True
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
||||
s.close()
|
||||
except:
|
||||
HAS_IPV6 = False
|
||||
|
||||
# Disable CLI web browsers
|
||||
term = os.environ.pop('TERM', None)
|
||||
import webbrowser
|
||||
if term:
|
||||
os.environ['TERM'] = term
|
||||
|
||||
import subprocess
|
||||
import re, socket, cgi, select, time, glob, random, string, binascii
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
FISH_BIN_PATH = False # will be set later
|
||||
|
||||
def run_fish_cmd(text):
|
||||
from subprocess import PIPE
|
||||
# ensure that fish is using UTF-8
|
||||
ctype = os.environ.get("LC_ALL", os.environ.get("LC_CTYPE", os.environ.get("LANG")))
|
||||
# Ensure that fish is using UTF-8.
|
||||
ctype = os.environ.get("LC_ALL", os.environ.get("LC_CTYPE",
|
||||
os.environ.get("LANG")))
|
||||
env = None
|
||||
if ctype is None or re.search(r"\.utf-?8$", ctype, flags=re.I) is None:
|
||||
# override LC_CTYPE with en_US.UTF-8
|
||||
@@ -52,68 +51,66 @@ def run_fish_cmd(text):
|
||||
# Fish makes the same assumption in config.fish
|
||||
env = os.environ.copy()
|
||||
env.update(LC_CTYPE="en_US.UTF-8", LANG="en_US.UTF-8")
|
||||
p = subprocess.Popen([FISH_BIN_PATH], stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env)
|
||||
p = subprocess.Popen([FISH_BIN_PATH], stdin=PIPE, stdout=PIPE, stderr=PIPE,
|
||||
env=env)
|
||||
out, err = p.communicate(text.encode('utf-8'))
|
||||
out = out.decode('utf-8', 'replace')
|
||||
err = err.decode('utf-8', 'replace')
|
||||
return(out, err)
|
||||
|
||||
|
||||
def escape_fish_cmd(text):
|
||||
# Replace one backslash with two, and single quotes with backslash-quote
|
||||
escaped = text.replace('\\', '\\\\').replace("'", "\\'")
|
||||
return "'" + escaped + "'"
|
||||
|
||||
named_colors = {
|
||||
'black' : '000000',
|
||||
'red' : '800000',
|
||||
'green' : '008000',
|
||||
'brown' : '725000',
|
||||
'yellow' : '808000',
|
||||
'blue' : '000080',
|
||||
'magenta' : '800080',
|
||||
'purple' : '800080',
|
||||
'cyan' : '008080',
|
||||
'grey' : 'e5e5e5',
|
||||
'brgrey' : '555555',
|
||||
'white' : 'c0c0c0',
|
||||
'brblack' : '808080',
|
||||
'brred' : 'ff0000',
|
||||
'brgreen' : '00ff00',
|
||||
'brbrown' : 'ffff00',
|
||||
'bryellow' : 'ffff00',
|
||||
'brblue' : '0000ff',
|
||||
'brmagenta' : 'ff00ff',
|
||||
'brpurple' : 'ff00ff',
|
||||
'brcyan' : '00ffff',
|
||||
'brwhite' : 'ffffff'
|
||||
'black': '000000', 'red': '800000', 'green': '008000', 'brown': '725000',
|
||||
'yellow': '808000', 'blue': '000080', 'magenta': '800080',
|
||||
'purple': '800080', 'cyan': '008080', 'grey': 'e5e5e5', 'brgrey': '555555',
|
||||
'white': 'c0c0c0', 'brblack': '808080', 'brred': 'ff0000',
|
||||
'brgreen': '00ff00', 'brbrown': 'ffff00', 'bryellow': 'ffff00',
|
||||
'brblue': '0000ff', 'brmagenta': 'ff00ff', 'brpurple': 'ff00ff',
|
||||
'brcyan': '00ffff', 'brwhite': 'ffffff'
|
||||
}
|
||||
|
||||
bindings_blacklist = set(["self-insert", "'begin;end'"])
|
||||
|
||||
|
||||
def parse_one_color(comp):
|
||||
""" A basic function to parse a single color value like 'FFA000' """
|
||||
if comp in named_colors:
|
||||
# Named color
|
||||
return named_colors[comp]
|
||||
elif re.match(r"[0-9a-fA-F]{3}", comp) is not None or re.match(r"[0-9a-fA-F]{6}", comp) is not None:
|
||||
elif (re.match(r"[0-9a-fA-F]{3}", comp) is not None or
|
||||
re.match(r"[0-9a-fA-F]{6}", comp) is not None):
|
||||
# Hex color
|
||||
return comp
|
||||
else:
|
||||
# Unknown
|
||||
return ''
|
||||
|
||||
|
||||
def better_color(c1, c2):
|
||||
""" Indicate which color is "better", i.e. prefer term256 colors """
|
||||
if not c2: return c1
|
||||
if not c1: return c2
|
||||
if c1 == 'normal': return c2
|
||||
if c2 == 'normal': return c1
|
||||
if c2 in named_colors: return c1
|
||||
if c1 in named_colors: return c2
|
||||
if not c2:
|
||||
return c1
|
||||
if not c1:
|
||||
return c2
|
||||
if c1 == 'normal':
|
||||
return c2
|
||||
if c2 == 'normal':
|
||||
return c1
|
||||
if c2 in named_colors:
|
||||
return c1
|
||||
if c1 in named_colors:
|
||||
return c2
|
||||
return c1
|
||||
|
||||
|
||||
def parse_color(color_str):
|
||||
""" A basic function to parse a color string, for example, 'red' '--bold' """
|
||||
""" A basic function to parse a color string, for example, 'red' '--bold'.
|
||||
"""
|
||||
comps = color_str.split(' ')
|
||||
color = 'normal'
|
||||
background_color = ''
|
||||
@@ -127,21 +124,69 @@ def parse_color(color_str):
|
||||
underline = True
|
||||
elif comp.startswith('--background='):
|
||||
# Background color
|
||||
background_color = better_color(background_color, parse_one_color(comp[len('--background='):]))
|
||||
background_color = better_color(
|
||||
background_color, parse_one_color(comp[len('--background='):]))
|
||||
else:
|
||||
# Regular color
|
||||
color = better_color(color, parse_one_color(comp))
|
||||
|
||||
return {"color": color, "background": background_color, "bold": bold, "underline": underline}
|
||||
return {"color": color, "background": background_color, "bold": bold,
|
||||
"underline": underline}
|
||||
|
||||
|
||||
def parse_bool(val):
|
||||
val = val.lower()
|
||||
if val.startswith('f') or val.startswith('0'): return False
|
||||
if val.startswith('t') or val.startswith('1'): return True
|
||||
if val.startswith('f') or val.startswith('0'):
|
||||
return False
|
||||
if val.startswith('t') or val.startswith('1'):
|
||||
return True
|
||||
return bool(val)
|
||||
|
||||
|
||||
def html_color_for_ansi_color_index(val):
|
||||
arr = ['black', '#AA0000', '#00AA00', '#AA5500', '#0000AA', '#AA00AA', '#00AAAA', '#AAAAAA', '#555555', '#FF5555', '#55FF55', '#FFFF55', '#5555FF', '#FF55FF', '#55FFFF', 'white', '#000000', '#00005f', '#000087', '#0000af', '#0000d7', '#0000ff', '#005f00', '#005f5f', '#005f87', '#005faf', '#005fd7', '#005fff', '#008700', '#00875f', '#008787', '#0087af', '#0087d7', '#0087ff', '#00af00', '#00af5f', '#00af87', '#00afaf', '#00afd7', '#00afff', '#00d700', '#00d75f', '#00d787', '#00d7af', '#00d7d7', '#00d7ff', '#00ff00', '#00ff5f', '#00ff87', '#00ffaf', '#00ffd7', '#00ffff', '#5f0000', '#5f005f', '#5f0087', '#5f00af', '#5f00d7', '#5f00ff', '#5f5f00', '#5f5f5f', '#5f5f87', '#5f5faf', '#5f5fd7', '#5f5fff', '#5f8700', '#5f875f', '#5f8787', '#5f87af', '#5f87d7', '#5f87ff', '#5faf00', '#5faf5f', '#5faf87', '#5fafaf', '#5fafd7', '#5fafff', '#5fd700', '#5fd75f', '#5fd787', '#5fd7af', '#5fd7d7', '#5fd7ff', '#5fff00', '#5fff5f', '#5fff87', '#5fffaf', '#5fffd7', '#5fffff', '#870000', '#87005f', '#870087', '#8700af', '#8700d7', '#8700ff', '#875f00', '#875f5f', '#875f87', '#875faf', '#875fd7', '#875fff', '#878700', '#87875f', '#878787', '#8787af', '#8787d7', '#8787ff', '#87af00', '#87af5f', '#87af87', '#87afaf', '#87afd7', '#87afff', '#87d700', '#87d75f', '#87d787', '#87d7af', '#87d7d7', '#87d7ff', '#87ff00', '#87ff5f', '#87ff87', '#87ffaf', '#87ffd7', '#87ffff', '#af0000', '#af005f', '#af0087', '#af00af', '#af00d7', '#af00ff', '#af5f00', '#af5f5f', '#af5f87', '#af5faf', '#af5fd7', '#af5fff', '#af8700', '#af875f', '#af8787', '#af87af', '#af87d7', '#af87ff', '#afaf00', '#afaf5f', '#afaf87', '#afafaf', '#afafd7', '#afafff', '#afd700', '#afd75f', '#afd787', '#afd7af', '#afd7d7', '#afd7ff', '#afff00', '#afff5f', '#afff87', '#afffaf', '#afffd7', '#afffff', '#d70000', '#d7005f', '#d70087', '#d700af', '#d700d7', '#d700ff', '#d75f00', '#d75f5f', '#d75f87', '#d75faf', '#d75fd7', '#d75fff', '#d78700', '#d7875f', '#d78787', '#d787af', '#d787d7', '#d787ff', '#d7af00', '#d7af5f', '#d7af87', '#d7afaf', '#d7afd7', '#d7afff', '#d7d700', '#d7d75f', '#d7d787', '#d7d7af', '#d7d7d7', '#d7d7ff', '#d7ff00', '#d7ff5f', '#d7ff87', '#d7ffaf', '#d7ffd7', '#d7ffff', '#ff0000', '#ff005f', '#ff0087', '#ff00af', '#ff00d7', '#ff00ff', '#ff5f00', '#ff5f5f', '#ff5f87', '#ff5faf', '#ff5fd7', '#ff5fff', '#ff8700', '#ff875f', '#ff8787', '#ff87af', '#ff87d7', '#ff87ff', '#ffaf00', '#ffaf5f', '#ffaf87', '#ffafaf', '#ffafd7', '#ffafff', '#ffd700', '#ffd75f', '#ffd787', '#ffd7af', '#ffd7d7', '#ffd7ff', '#ffff00', '#ffff5f', '#ffff87', '#ffffaf', '#ffffd7', '#ffffff', '#080808', '#121212', '#1c1c1c', '#262626', '#303030', '#3a3a3a', '#444444', '#4e4e4e', '#585858', '#626262', '#6c6c6c', '#767676', '#808080', '#8a8a8a', '#949494', '#9e9e9e', '#a8a8a8', '#b2b2b2', '#bcbcbc', '#c6c6c6', '#d0d0d0', '#dadada', '#e4e4e4', '#eeeeee']
|
||||
arr = ['black', '#AA0000', '#00AA00', '#AA5500', '#0000AA', '#AA00AA',
|
||||
'#00AAAA', '#AAAAAA', '#555555', '#FF5555', '#55FF55', '#FFFF55',
|
||||
'#5555FF', '#FF55FF', '#55FFFF', 'white', '#000000', '#00005f',
|
||||
'#000087', '#0000af', '#0000d7', '#0000ff', '#005f00', '#005f5f',
|
||||
'#005f87', '#005faf', '#005fd7', '#005fff', '#008700', '#00875f',
|
||||
'#008787', '#0087af', '#0087d7', '#0087ff', '#00af00', '#00af5f',
|
||||
'#00af87', '#00afaf', '#00afd7', '#00afff', '#00d700', '#00d75f',
|
||||
'#00d787', '#00d7af', '#00d7d7', '#00d7ff', '#00ff00', '#00ff5f',
|
||||
'#00ff87', '#00ffaf', '#00ffd7', '#00ffff', '#5f0000', '#5f005f',
|
||||
'#5f0087', '#5f00af', '#5f00d7', '#5f00ff', '#5f5f00', '#5f5f5f',
|
||||
'#5f5f87', '#5f5faf', '#5f5fd7', '#5f5fff', '#5f8700', '#5f875f',
|
||||
'#5f8787', '#5f87af', '#5f87d7', '#5f87ff', '#5faf00', '#5faf5f',
|
||||
'#5faf87', '#5fafaf', '#5fafd7', '#5fafff', '#5fd700', '#5fd75f',
|
||||
'#5fd787', '#5fd7af', '#5fd7d7', '#5fd7ff', '#5fff00', '#5fff5f',
|
||||
'#5fff87', '#5fffaf', '#5fffd7', '#5fffff', '#870000', '#87005f',
|
||||
'#870087', '#8700af', '#8700d7', '#8700ff', '#875f00', '#875f5f',
|
||||
'#875f87', '#875faf', '#875fd7', '#875fff', '#878700', '#87875f',
|
||||
'#878787', '#8787af', '#8787d7', '#8787ff', '#87af00', '#87af5f',
|
||||
'#87af87', '#87afaf', '#87afd7', '#87afff', '#87d700', '#87d75f',
|
||||
'#87d787', '#87d7af', '#87d7d7', '#87d7ff', '#87ff00', '#87ff5f',
|
||||
'#87ff87', '#87ffaf', '#87ffd7', '#87ffff', '#af0000', '#af005f',
|
||||
'#af0087', '#af00af', '#af00d7', '#af00ff', '#af5f00', '#af5f5f',
|
||||
'#af5f87', '#af5faf', '#af5fd7', '#af5fff', '#af8700', '#af875f',
|
||||
'#af8787', '#af87af', '#af87d7', '#af87ff', '#afaf00', '#afaf5f',
|
||||
'#afaf87', '#afafaf', '#afafd7', '#afafff', '#afd700', '#afd75f',
|
||||
'#afd787', '#afd7af', '#afd7d7', '#afd7ff', '#afff00', '#afff5f',
|
||||
'#afff87', '#afffaf', '#afffd7', '#afffff', '#d70000', '#d7005f',
|
||||
'#d70087', '#d700af', '#d700d7', '#d700ff', '#d75f00', '#d75f5f',
|
||||
'#d75f87', '#d75faf', '#d75fd7', '#d75fff', '#d78700', '#d7875f',
|
||||
'#d78787', '#d787af', '#d787d7', '#d787ff', '#d7af00', '#d7af5f',
|
||||
'#d7af87', '#d7afaf', '#d7afd7', '#d7afff', '#d7d700', '#d7d75f',
|
||||
'#d7d787', '#d7d7af', '#d7d7d7', '#d7d7ff', '#d7ff00', '#d7ff5f',
|
||||
'#d7ff87', '#d7ffaf', '#d7ffd7', '#d7ffff', '#ff0000', '#ff005f',
|
||||
'#ff0087', '#ff00af', '#ff00d7', '#ff00ff', '#ff5f00', '#ff5f5f',
|
||||
'#ff5f87', '#ff5faf', '#ff5fd7', '#ff5fff', '#ff8700', '#ff875f',
|
||||
'#ff8787', '#ff87af', '#ff87d7', '#ff87ff', '#ffaf00', '#ffaf5f',
|
||||
'#ffaf87', '#ffafaf', '#ffafd7', '#ffafff', '#ffd700', '#ffd75f',
|
||||
'#ffd787', '#ffd7af', '#ffd7d7', '#ffd7ff', '#ffff00', '#ffff5f',
|
||||
'#ffff87', '#ffffaf', '#ffffd7', '#ffffff', '#080808', '#121212',
|
||||
'#1c1c1c', '#262626', '#303030', '#3a3a3a', '#444444', '#4e4e4e',
|
||||
'#585858', '#626262', '#6c6c6c', '#767676', '#808080', '#8a8a8a',
|
||||
'#949494', '#9e9e9e', '#a8a8a8', '#b2b2b2', '#bcbcbc', '#c6c6c6',
|
||||
'#d0d0d0', '#dadada', '#e4e4e4', '#eeeeee']
|
||||
if val < 0 or val >= len(arr):
|
||||
return ''
|
||||
else:
|
||||
@@ -149,6 +194,8 @@ def html_color_for_ansi_color_index(val):
|
||||
|
||||
# Function to return special ANSI escapes like exit_attribute_mode
|
||||
g_special_escapes_dict = None
|
||||
|
||||
|
||||
def get_special_ansi_escapes():
|
||||
global g_special_escapes_dict
|
||||
if g_special_escapes_dict is None:
|
||||
@@ -160,8 +207,10 @@ def get_special_ansi_escapes():
|
||||
def get_tparm(key):
|
||||
val = None
|
||||
key = curses.tigetstr("sgr0")
|
||||
if key: val = curses.tparm(key)
|
||||
if val: val = val.decode('utf-8')
|
||||
if key:
|
||||
val = curses.tparm(key)
|
||||
if val:
|
||||
val = val.decode('utf-8')
|
||||
return val
|
||||
|
||||
# Just a few for now
|
||||
@@ -173,6 +222,8 @@ def get_special_ansi_escapes():
|
||||
|
||||
# Given a known ANSI escape sequence, convert it to HTML and append to the list
|
||||
# Returns whether we have an open <span>
|
||||
|
||||
|
||||
def append_html_for_ansi_escape(full_val, result, span_open):
|
||||
|
||||
# Strip off the initial \x1b[ and terminating m
|
||||
@@ -187,16 +238,16 @@ def append_html_for_ansi_escape(full_val, result, span_open):
|
||||
match = re.match('38;5;(\d+)', val)
|
||||
if match is not None:
|
||||
close_span()
|
||||
html_color = html_color_for_ansi_color_index(int(match.group(1)))
|
||||
html_color = html_color_for_ansi_color_index(int(match.group(1)))
|
||||
result.append('<span style="color: ' + html_color + '">')
|
||||
return True # span now open
|
||||
return True # span now open
|
||||
|
||||
# term8 foreground color
|
||||
if val in [str(x) for x in range(30, 38)]:
|
||||
close_span()
|
||||
html_color = html_color_for_ansi_color_index(int(val) - 30)
|
||||
html_color = html_color_for_ansi_color_index(int(val) - 30)
|
||||
result.append('<span style="color: ' + html_color + '">')
|
||||
return True # span now open
|
||||
return True # span now open
|
||||
|
||||
# Try special escapes
|
||||
special_escapes = get_special_ansi_escapes()
|
||||
@@ -209,15 +260,17 @@ def append_html_for_ansi_escape(full_val, result, span_open):
|
||||
# Do nothing on failure
|
||||
return span_open
|
||||
|
||||
|
||||
def strip_ansi(val):
|
||||
# Make a half-assed effort to strip ANSI control sequences
|
||||
# We assume that all such sequences start with 0x1b and end with m,
|
||||
# which catches most cases
|
||||
return re.sub("\x1b[^m]*m", '', val)
|
||||
|
||||
|
||||
def ansi_prompt_line_width(val):
|
||||
# Given an ANSI prompt, return the length of its longest line, as in the number of characters it takes up
|
||||
# Start by stripping off ANSI
|
||||
# Given an ANSI prompt, return the length of its longest line, as in the
|
||||
# number of characters it takes up. Start by stripping off ANSI.
|
||||
stripped_val = strip_ansi(val)
|
||||
|
||||
# Now count the longest line
|
||||
@@ -225,10 +278,10 @@ def ansi_prompt_line_width(val):
|
||||
|
||||
|
||||
def ansi_to_html(val):
|
||||
# Split us up by ANSI escape sequences
|
||||
# We want to catch not only the standard color codes, but also things like sgr0
|
||||
# Hence this lame check
|
||||
# Note that Python 2.6 doesn't have a flag param to re.split, so we have to compile it first
|
||||
# Split us up by ANSI escape sequences. We want to catch not only the
|
||||
# standard color codes, but also things like sgr0. Hence this lame check.
|
||||
# Note that Python 2.6 doesn't have a flag param to re.split, so we have to
|
||||
# compile it first.
|
||||
reg = re.compile("""
|
||||
( # Capture
|
||||
\x1b # Escape
|
||||
@@ -253,10 +306,12 @@ def ansi_to_html(val):
|
||||
result.append(cgi.escape(strip_ansi(component)))
|
||||
else:
|
||||
# It's an escape sequence. Close the previous escape.
|
||||
span_open = append_html_for_ansi_escape(component, result, span_open)
|
||||
span_open = append_html_for_ansi_escape(component, result,
|
||||
span_open)
|
||||
|
||||
# Close final escape
|
||||
if span_open: result.append('</span>')
|
||||
if span_open:
|
||||
result.append('</span>')
|
||||
|
||||
# Remove empty elements
|
||||
result = [x for x in result if x]
|
||||
@@ -272,6 +327,7 @@ def ansi_to_html(val):
|
||||
|
||||
return ''.join(result)
|
||||
|
||||
|
||||
class FishVar:
|
||||
""" A class that represents a variable """
|
||||
def __init__(self, name, value):
|
||||
@@ -283,15 +339,20 @@ class FishVar:
|
||||
def get_json_obj(self):
|
||||
# Return an array(3): name, value, flags
|
||||
flags = []
|
||||
if self.universal: flags.append('universal')
|
||||
if self.exported: flags.append('exported')
|
||||
return {"name": self.name, "value": self.value, "Flags": ', '.join(flags)}
|
||||
if self.universal:
|
||||
flags.append('universal')
|
||||
if self.exported:
|
||||
flags.append('exported')
|
||||
return {"name": self.name, "value": self.value,
|
||||
"Flags": ', '.join(flags)}
|
||||
|
||||
|
||||
class FishBinding:
|
||||
"""A class that represents keyboard binding """
|
||||
|
||||
def __init__(self, command, raw_binding, readable_binding, description=None):
|
||||
self.command = command
|
||||
def __init__(self, command, raw_binding, readable_binding,
|
||||
description=None):
|
||||
self.command = command
|
||||
self.bindings = []
|
||||
self.description = description
|
||||
self.add_binding(raw_binding, readable_binding)
|
||||
@@ -302,23 +363,24 @@ class FishBinding:
|
||||
i['raw_bindings'].append(raw_binding)
|
||||
break
|
||||
else:
|
||||
self.bindings.append({'readable_binding':readable_binding, 'raw_bindings':[raw_binding]})
|
||||
self.bindings.append({'readable_binding': readable_binding,
|
||||
'raw_bindings': [raw_binding]})
|
||||
|
||||
def get_json_obj(self):
|
||||
return {"command" : self.command, "bindings": self.bindings, "description": self.description}
|
||||
return {"command": self.command, "bindings": self.bindings,
|
||||
"description": self.description}
|
||||
|
||||
|
||||
class BindingParser:
|
||||
""" Class to parse codes for bind command """
|
||||
|
||||
#TODO: What does snext and sprevious mean ?
|
||||
readable_keys= { "dc":"Delete", "npage": "Page Up", "ppage":"Page Down",
|
||||
"sdc": "Shift Delete", "shome": "Shift Home",
|
||||
"left": "Left Arrow", "right": "Right Arrow",
|
||||
"up": "Up Arrow", "down": "Down Arrow",
|
||||
"sleft": "Shift Left", "sright": "Shift Right",
|
||||
"btab": "Shift Tab"
|
||||
}
|
||||
# TODO: What does snext and sprevious mean ?
|
||||
readable_keys = {"dc": "Delete", "npage": "Page Up", "ppage": "Page Down",
|
||||
"sdc": "Shift Delete", "shome": "Shift Home",
|
||||
"left": "Left Arrow", "right": "Right Arrow",
|
||||
"up": "Up Arrow", "down": "Down Arrow",
|
||||
"sleft": "Shift Left", "sright": "Shift Right",
|
||||
"btab": "Shift Tab"}
|
||||
|
||||
def set_buffer(self, buffer):
|
||||
""" Sets code to parse """
|
||||
@@ -356,7 +418,8 @@ class BindingParser:
|
||||
|
||||
# \[1\; is start of control sequence
|
||||
if c == '1':
|
||||
b = self.get_char(); c = self.get_char()
|
||||
b = self.get_char()
|
||||
c = self.get_char()
|
||||
if b == '\\' and c == '~':
|
||||
result += "Home"
|
||||
elif c == ";":
|
||||
@@ -369,7 +432,8 @@ class BindingParser:
|
||||
|
||||
# \[4\~ is End
|
||||
if c == '4':
|
||||
b = self.get_char(); c = self.get_char()
|
||||
b = self.get_char()
|
||||
c = self.get_char()
|
||||
if b == '\\' and c == '~':
|
||||
result += "End"
|
||||
|
||||
@@ -466,7 +530,7 @@ class FishConfigTCPServer(SocketServer.TCPServer):
|
||||
"""TCPServer that only accepts connections from localhost (IPv4/IPv6)."""
|
||||
WHITELIST = set(['::1', '::ffff:127.0.0.1', '127.0.0.1'])
|
||||
|
||||
address_family = socket.AF_INET6 if HAS_IPV6 else socket.AF_INET
|
||||
address_family = socket.AF_INET6 if socket.has_ipv6 else socket.AF_INET
|
||||
|
||||
def verify_request(self, request, client_address):
|
||||
return client_address[0] in FishConfigTCPServer.WHITELIST
|
||||
@@ -526,7 +590,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
for match in re.finditer(r"^fish_color_(\S+) ?(.*)", line):
|
||||
color_name, color_value = [x.strip() for x in match.group(1, 2)]
|
||||
color_desc = descriptions.get(color_name, '')
|
||||
data = { "name": color_name, "description" : color_desc }
|
||||
data = {"name": color_name, "description": color_desc}
|
||||
data.update(parse_color(color_value))
|
||||
result.append(data)
|
||||
remaining.discard(color_name)
|
||||
@@ -564,18 +628,22 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
vars = {}
|
||||
for line in out.split('\n'):
|
||||
comps = line.split(' ', 1)
|
||||
if len(comps) < 2: continue
|
||||
if len(comps) < 2:
|
||||
continue
|
||||
fish_var = FishVar(comps[0], comps[1])
|
||||
vars[fish_var.name] = fish_var
|
||||
|
||||
# Mark universal variables. L means don't abbreviate.
|
||||
for name in self.do_get_variable_names('set -nUL'):
|
||||
if name in vars: vars[name].universal = True
|
||||
if name in vars:
|
||||
vars[name].universal = True
|
||||
# Mark exported variables. L means don't abbreviate.
|
||||
for name in self.do_get_variable_names('set -nxL'):
|
||||
if name in vars: vars[name].exported = True
|
||||
if name in vars:
|
||||
vars[name].exported = True
|
||||
|
||||
return [vars[key].get_json_obj() for key in sorted(vars.keys(), key=lambda x: x.lower())]
|
||||
return [vars[key].get_json_obj() for key
|
||||
in sorted(vars.keys(), key=lambda x: x.lower())]
|
||||
|
||||
def do_get_bindings(self):
|
||||
""" Get key bindings """
|
||||
@@ -621,29 +689,37 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
bindings.append(fish_binding)
|
||||
command_to_binding[command] = fish_binding
|
||||
|
||||
return [ binding.get_json_obj() for binding in bindings ]
|
||||
return [binding.get_json_obj() for binding in bindings]
|
||||
|
||||
def do_get_history(self):
|
||||
# Use \x1e ("record separator") to distinguish between history items. The first
|
||||
# backslash is so Python passes one backslash to fish
|
||||
# Use \x1e ("record separator") to distinguish between history items.
|
||||
# The first backslash is so Python passes one backslash to fish.
|
||||
out, err = run_fish_cmd('for val in $history; echo -n $val \\x1e; end')
|
||||
result = out.split(' \x1e')
|
||||
if result: result.pop() # Trim off the trailing element
|
||||
if result:
|
||||
result.pop() # trim off the trailing element
|
||||
return result
|
||||
|
||||
def do_get_color_for_variable(self, name):
|
||||
"Return the color with the given name, or the empty string if there is none"
|
||||
# Return the color with the given name, or the empty string if there is
|
||||
# none.
|
||||
out, err = run_fish_cmd("echo -n $" + name)
|
||||
return out
|
||||
|
||||
def do_set_color_for_variable(self, name, color, background_color, bold, underline):
|
||||
if not color: color = 'normal'
|
||||
def do_set_color_for_variable(self, name, color, background_color, bold,
|
||||
underline):
|
||||
if not color:
|
||||
color = 'normal'
|
||||
"Sets a color for a fish color name, like 'autosuggestion'"
|
||||
command = 'set -U fish_color_' + name
|
||||
if color: command += ' ' + color
|
||||
if background_color: command += ' --background=' + background_color
|
||||
if bold: command += ' --bold'
|
||||
if underline: command += ' --underline'
|
||||
if color:
|
||||
command += ' ' + color
|
||||
if background_color:
|
||||
command += ' --background=' + background_color
|
||||
if bold:
|
||||
command += ' --bold'
|
||||
if underline:
|
||||
command += ' --underline'
|
||||
|
||||
out, err = run_fish_cmd(command)
|
||||
return out
|
||||
@@ -655,7 +731,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
def do_delete_history_item(self, history_item_text):
|
||||
# It's really lame that we always return success here
|
||||
cmd = ('builtin history delete --exact -- %s; builtin history save' %
|
||||
escape_fish_cmd(history_item_text))
|
||||
escape_fish_cmd(history_item_text))
|
||||
out, err = run_fish_cmd(cmd)
|
||||
return True
|
||||
|
||||
@@ -669,29 +745,35 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
prompt_demo_ansi, err = run_fish_cmd(command_to_run)
|
||||
prompt_demo_html = ansi_to_html(prompt_demo_ansi)
|
||||
prompt_demo_font_size = self.font_size_for_ansi_prompt(prompt_demo_ansi)
|
||||
result = {'function': prompt_function_text, 'demo': prompt_demo_html, 'font_size': prompt_demo_font_size }
|
||||
result = {'function': prompt_function_text, 'demo': prompt_demo_html,
|
||||
'font_size': prompt_demo_font_size}
|
||||
if extras_dict:
|
||||
result.update(extras_dict)
|
||||
return result
|
||||
|
||||
def do_get_current_prompt(self):
|
||||
# Return the current prompt
|
||||
# We run 'false' to demonstrate how the prompt shows the command status (#1624)
|
||||
# Return the current prompt. We run 'false' to demonstrate how the
|
||||
# prompt shows the command status (#1624).
|
||||
prompt_func, err = run_fish_cmd('functions fish_prompt')
|
||||
result = self.do_get_prompt('builtin cd "' + initial_wd + '" ; false ; fish_prompt', prompt_func.strip(), {'name': 'Current'})
|
||||
result = self.do_get_prompt(
|
||||
'builtin cd "' + initial_wd + '" ; false ; fish_prompt',
|
||||
prompt_func.strip(), {'name': 'Current'})
|
||||
return result
|
||||
|
||||
def do_get_sample_prompt(self, text, extras_dict):
|
||||
# Return the prompt you get from the given text
|
||||
# extras_dict is a dictionary whose values get merged in
|
||||
# We run 'false' to demonstrate how the prompt shows the command status (#1624)
|
||||
cmd = text + "\n builtin cd \"" + initial_wd + "\" \n false \n fish_prompt\n"
|
||||
# Return the prompt you get from the given text. Extras_dict is a
|
||||
# dictionary whose values get merged in. We run 'false' to demonstrate
|
||||
# how the prompt shows the command status (#1624)
|
||||
cmd = (text + "\n builtin cd \"" + initial_wd +
|
||||
"\" \n false \n fish_prompt\n")
|
||||
return self.do_get_prompt(cmd, text.strip(), extras_dict)
|
||||
|
||||
def parse_one_sample_prompt_hash(self, line, result_dict):
|
||||
# Allow us to skip whitespace, etc.
|
||||
if not line: return True
|
||||
if line.isspace(): return True
|
||||
if not line:
|
||||
return True
|
||||
if line.isspace():
|
||||
return True
|
||||
|
||||
# Parse a comment hash like '# name: Classic'
|
||||
match = re.match(r"#\s*(\w+?): (.+)", line, re.IGNORECASE)
|
||||
@@ -703,7 +785,6 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
# Skip other hash comments
|
||||
return line.startswith('#')
|
||||
|
||||
|
||||
def read_one_sample_prompt(self, path):
|
||||
try:
|
||||
with open(path, 'rb') as fd:
|
||||
@@ -713,10 +794,13 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
parsing_hashes = True
|
||||
unicode_lines = (line.decode('utf-8') for line in fd)
|
||||
for line in unicode_lines:
|
||||
# Parse hashes until parse_one_sample_prompt_hash return False
|
||||
# Parse hashes until parse_one_sample_prompt_hash return
|
||||
# False.
|
||||
if parsing_hashes:
|
||||
parsing_hashes = self.parse_one_sample_prompt_hash(line, extras_dict)
|
||||
# Maybe not we're not parsing hashes, or maybe we already were not
|
||||
parsing_hashes = self.parse_one_sample_prompt_hash(
|
||||
line, extras_dict)
|
||||
# Maybe not we're not parsing hashes, or maybe we already
|
||||
# were not.
|
||||
if not parsing_hashes:
|
||||
function_lines.append(line)
|
||||
func = ''.join(function_lines).strip()
|
||||
@@ -758,7 +842,8 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
return True
|
||||
|
||||
def do_save_abbreviation(self, abbreviation):
|
||||
out, err = run_fish_cmd('abbr --add \'%s %s\'' % (abbreviation['word'], abbreviation['phrase']))
|
||||
out, err = run_fish_cmd('abbr --add \'%s %s\'' % (
|
||||
abbreviation['word'], abbreviation['phrase']))
|
||||
if err:
|
||||
return err
|
||||
else:
|
||||
@@ -768,21 +853,29 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
if len(haystack) < len(needle):
|
||||
return False
|
||||
bits = 0
|
||||
for x,y in zip(haystack, needle):
|
||||
for x, y in zip(haystack, needle):
|
||||
bits |= ord(x) ^ ord(y)
|
||||
return bits == 0
|
||||
|
||||
def font_size_for_ansi_prompt(self, prompt_demo_ansi):
|
||||
width = ansi_prompt_line_width(prompt_demo_ansi)
|
||||
# Pick a font size
|
||||
if width >= 70: font_size = '8pt'
|
||||
if width >= 60: font_size = '10pt'
|
||||
elif width >= 50: font_size = '11pt'
|
||||
elif width >= 40: font_size = '13pt'
|
||||
elif width >= 30: font_size = '15pt'
|
||||
elif width >= 25: font_size = '16pt'
|
||||
elif width >= 20: font_size = '17pt'
|
||||
else: font_size = '18pt'
|
||||
if width >= 70:
|
||||
font_size = '8pt'
|
||||
if width >= 60:
|
||||
font_size = '10pt'
|
||||
elif width >= 50:
|
||||
font_size = '11pt'
|
||||
elif width >= 40:
|
||||
font_size = '13pt'
|
||||
elif width >= 30:
|
||||
font_size = '15pt'
|
||||
elif width >= 25:
|
||||
font_size = '16pt'
|
||||
elif width >= 20:
|
||||
font_size = '17pt'
|
||||
else:
|
||||
font_size = '18pt'
|
||||
return font_size
|
||||
|
||||
def do_GET(self):
|
||||
@@ -820,7 +913,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
|
||||
# Return valid output
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type','application/json')
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.end_headers()
|
||||
self.write_to_wfile('\n')
|
||||
|
||||
@@ -861,7 +954,9 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
|
||||
if what:
|
||||
# Not sure why we get lists here?
|
||||
output = self.do_set_color_for_variable(what[0], color[0], background_color[0], parse_bool(bold[0]), parse_bool(underline[0]))
|
||||
output = self.do_set_color_for_variable(
|
||||
what[0], color[0], background_color[0],
|
||||
parse_bool(bold[0]), parse_bool(underline[0]))
|
||||
else:
|
||||
output = 'Bad request'
|
||||
elif p == '/get_function/':
|
||||
@@ -881,13 +976,13 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
output = ["Unable to set prompt"]
|
||||
elif p == '/save_abbreviation/':
|
||||
r = self.do_save_abbreviation(postvars)
|
||||
if r == True:
|
||||
if r:
|
||||
output = ["OK"]
|
||||
else:
|
||||
output = [r]
|
||||
elif p == '/remove_abbreviation/':
|
||||
r = self.do_remove_abbreviation(postvars)
|
||||
if r == True:
|
||||
if r:
|
||||
output = ["OK"]
|
||||
else:
|
||||
output = [r]
|
||||
@@ -896,7 +991,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
|
||||
# Return valid output
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type','application/json')
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.end_headers()
|
||||
self.write_to_wfile('\n')
|
||||
|
||||
@@ -932,7 +1027,8 @@ redirect_template_html = """
|
||||
fish_bin_dir = os.environ.get('__fish_bin_dir')
|
||||
fish_bin_path = None
|
||||
if not fish_bin_dir:
|
||||
print('The __fish_bin_dir environment variable is not set. Looking in $PATH...')
|
||||
print('The __fish_bin_dir environment variable is not set. '
|
||||
'Looking in $PATH...')
|
||||
# distutils.spawn is terribly broken, because it looks in wd before PATH,
|
||||
# and doesn't actually validate that the file is even executable
|
||||
for p in os.environ['PATH'].split(os.pathsep):
|
||||
@@ -950,7 +1046,8 @@ else:
|
||||
fish_bin_path = os.path.join(fish_bin_dir, 'fish')
|
||||
|
||||
if not os.access(fish_bin_path, os.X_OK):
|
||||
print("fish could not be executed at path '%s'. Is fish installed correctly?" % fish_bin_path)
|
||||
print("fish could not be executed at path '%s'. "
|
||||
"Is fish installed correctly?" % fish_bin_path)
|
||||
sys.exit(-1)
|
||||
FISH_BIN_PATH = fish_bin_path
|
||||
|
||||
@@ -958,8 +1055,8 @@ FISH_BIN_PATH = fish_bin_path
|
||||
# so get the current working directory
|
||||
initial_wd = os.getcwd()
|
||||
|
||||
# Make sure that the working directory is the one that contains the script server file,
|
||||
# because the document root is the working directory
|
||||
# Make sure that the working directory is the one that contains the script
|
||||
# server file, because the document root is the working directory.
|
||||
where = os.path.dirname(sys.argv[0])
|
||||
os.chdir(where)
|
||||
|
||||
@@ -968,7 +1065,7 @@ authkey = binascii.b2a_hex(os.urandom(16)).decode('ascii')
|
||||
|
||||
# Try to find a suitable port
|
||||
PORT = 8000
|
||||
HOST = "::" if HAS_IPV6 else "localhost"
|
||||
HOST = "::" if socket.has_ipv6 else "localhost"
|
||||
while PORT <= 9000:
|
||||
try:
|
||||
Handler = FishConfigHTTPRequestHandler
|
||||
@@ -992,16 +1089,17 @@ if PORT > 9000:
|
||||
# Just look at the first letter
|
||||
initial_tab = ''
|
||||
if len(sys.argv) > 1:
|
||||
for tab in ['functions', 'prompt', 'colors', 'variables', 'history', 'bindings', 'abbreviations']:
|
||||
for tab in ['functions', 'prompt', 'colors', 'variables', 'history',
|
||||
'bindings', 'abbreviations']:
|
||||
if tab.startswith(sys.argv[1]):
|
||||
initial_tab = '#' + tab
|
||||
break
|
||||
|
||||
url = 'http://localhost:%d/%s/%s' % (PORT, authkey, initial_tab)
|
||||
|
||||
# Create temporary file to hold redirect to real server
|
||||
# This prevents exposing the URL containing the authentication key on the command line
|
||||
# (see CVE-2014-2914 or https://github.com/fish-shell/fish-shell/issues/1438)
|
||||
# Create temporary file to hold redirect to real server. This prevents exposing
|
||||
# the URL containing the authentication key on the command line (see
|
||||
# CVE-2014-2914 or https://github.com/fish-shell/fish-shell/issues/1438).
|
||||
if 'XDG_CACHE_HOME' in os.environ:
|
||||
dirname = os.path.expanduser(os.path.expandvars('$XDG_CACHE_HOME/fish/'))
|
||||
else:
|
||||
@@ -1012,11 +1110,12 @@ try:
|
||||
os.makedirs(dirname, 0o0700)
|
||||
except OSError as e:
|
||||
if e.errno == 17:
|
||||
pass
|
||||
pass
|
||||
else:
|
||||
raise e
|
||||
raise e
|
||||
|
||||
randtoken = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
|
||||
randtoken = ''.join(random.choice(string.ascii_uppercase + string.digits)
|
||||
for _ in range(6))
|
||||
filename = dirname + 'web_config-%s.html' % randtoken
|
||||
|
||||
f = open(filename, 'w')
|
||||
|
||||
123
src/autoload.cpp
123
src/autoload.cpp
@@ -1,7 +1,6 @@
|
||||
// The classes responsible for autoloading functions and completions.
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
@@ -157,6 +156,19 @@ autoload_function_t *autoload_t::get_autoloaded_function_with_creation(const wcs
|
||||
return func;
|
||||
}
|
||||
|
||||
static bool use_cached(autoload_function_t *func, bool really_load, bool allow_stale_functions) {
|
||||
if (!func) {
|
||||
return false; // can't use a function that doesn't exist
|
||||
}
|
||||
if (really_load && !func->is_placeholder && !func->is_loaded) {
|
||||
return false; // can't use an unloaded function
|
||||
}
|
||||
if (!allow_stale_functions && is_stale(func)) {
|
||||
return false; // can't use a stale function
|
||||
}
|
||||
return true; // I guess we can use it
|
||||
}
|
||||
|
||||
/// This internal helper function does all the real work. By using two functions, the internal
|
||||
/// function can return on various places in the code, and the caller can take care of various
|
||||
/// cleanup work.
|
||||
@@ -169,35 +181,21 @@ autoload_function_t *autoload_t::get_autoloaded_function_with_creation(const wcs
|
||||
bool autoload_t::locate_file_and_maybe_load_it(const wcstring &cmd, bool really_load, bool reload,
|
||||
const wcstring_list_t &path_list) {
|
||||
// Note that we are NOT locked in this function!
|
||||
bool reloaded = 0;
|
||||
bool reloaded = false;
|
||||
|
||||
// Try using a cached function. If we really want the function to be loaded, require that it be
|
||||
// really loaded. If we're not reloading, allow stale functions.
|
||||
{
|
||||
bool allow_stale_functions = !reload;
|
||||
|
||||
scoped_lock locker(lock);
|
||||
autoload_function_t *func = this->get_node(cmd); // get the function
|
||||
|
||||
// Determine if we can use this cached function.
|
||||
bool use_cached;
|
||||
if (!func) {
|
||||
// Can't use a function that doesn't exist.
|
||||
use_cached = false;
|
||||
} else if (really_load && !func->is_placeholder && !func->is_loaded) {
|
||||
use_cached = false; // can't use an unloaded function
|
||||
} else if (!allow_stale_functions && is_stale(func)) {
|
||||
use_cached = false; // can't use a stale function
|
||||
} else {
|
||||
use_cached = true; // I guess we can use it
|
||||
}
|
||||
|
||||
// If we can use this function, return whether we were able to access it.
|
||||
if (use_cached) {
|
||||
assert(func != NULL);
|
||||
if (use_cached(func, really_load, allow_stale_functions)) {
|
||||
return func->is_internalized || func->access.accessible;
|
||||
}
|
||||
}
|
||||
|
||||
// The source of the script will end up here.
|
||||
wcstring script_source;
|
||||
bool has_script_source = false;
|
||||
@@ -234,55 +232,52 @@ bool autoload_t::locate_file_and_maybe_load_it(const wcstring &cmd, bool really_
|
||||
|
||||
if (!has_script_source) {
|
||||
// Iterate over path searching for suitable completion files.
|
||||
for (size_t i = 0; i < path_list.size(); i++) {
|
||||
for (size_t i = 0; i < path_list.size() && !found_file; i++) {
|
||||
wcstring next = path_list.at(i);
|
||||
wcstring path = next + L"/" + cmd + L".fish";
|
||||
|
||||
const file_access_attempt_t access = access_file(path, R_OK);
|
||||
if (access.accessible) {
|
||||
found_file = true;
|
||||
|
||||
// Now we're actually going to take the lock.
|
||||
scoped_lock locker(lock);
|
||||
autoload_function_t *func = this->get_node(cmd);
|
||||
|
||||
// Generate the source if we need to load it.
|
||||
bool need_to_load_function =
|
||||
really_load &&
|
||||
(func == NULL || func->access.mod_time != access.mod_time || !func->is_loaded);
|
||||
if (need_to_load_function) {
|
||||
// Generate the script source.
|
||||
wcstring esc = escape_string(path, 1);
|
||||
script_source = L"source " + esc;
|
||||
has_script_source = true;
|
||||
|
||||
// Remove any loaded command because we are going to reload it. Note that this
|
||||
// will deadlock if command_removed calls back into us.
|
||||
if (func && func->is_loaded) {
|
||||
command_removed(cmd);
|
||||
func->is_placeholder = false;
|
||||
}
|
||||
|
||||
// Mark that we're reloading it.
|
||||
reloaded = true;
|
||||
}
|
||||
|
||||
// Create the function if we haven't yet. This does not load it. Do not trigger
|
||||
// eviction unless we are actually loading, because we don't want to evict off of
|
||||
// the main thread.
|
||||
if (!func) {
|
||||
func = get_autoloaded_function_with_creation(cmd, really_load);
|
||||
}
|
||||
|
||||
// It's a fiction to say the script is loaded at this point, but we're definitely
|
||||
// going to load it down below.
|
||||
if (need_to_load_function) func->is_loaded = true;
|
||||
|
||||
// Unconditionally record our access time.
|
||||
func->access = access;
|
||||
|
||||
break;
|
||||
if (!access.accessible) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now we're actually going to take the lock.
|
||||
scoped_lock locker(lock);
|
||||
autoload_function_t *func = this->get_node(cmd);
|
||||
|
||||
// Generate the source if we need to load it.
|
||||
bool need_to_load_function =
|
||||
really_load &&
|
||||
(func == NULL || func->access.mod_time != access.mod_time || !func->is_loaded);
|
||||
if (need_to_load_function) {
|
||||
// Generate the script source.
|
||||
wcstring esc = escape_string(path, 1);
|
||||
script_source = L"source " + esc;
|
||||
has_script_source = true;
|
||||
|
||||
// Remove any loaded command because we are going to reload it. Note that this
|
||||
// will deadlock if command_removed calls back into us.
|
||||
if (func && func->is_loaded) {
|
||||
command_removed(cmd);
|
||||
func->is_placeholder = false;
|
||||
}
|
||||
|
||||
// Mark that we're reloading it.
|
||||
reloaded = true;
|
||||
}
|
||||
|
||||
// Create the function if we haven't yet. This does not load it. Do not trigger
|
||||
// eviction unless we are actually loading, because we don't want to evict off of
|
||||
// the main thread.
|
||||
if (!func) func = get_autoloaded_function_with_creation(cmd, really_load);
|
||||
|
||||
// It's a fiction to say the script is loaded at this point, but we're definitely
|
||||
// going to load it down below.
|
||||
if (need_to_load_function) func->is_loaded = true;
|
||||
|
||||
// Unconditionally record our access time.
|
||||
func->access = access;
|
||||
found_file = true;
|
||||
}
|
||||
|
||||
// If no file or builtin script was found we insert a placeholder function. Later we only
|
||||
@@ -313,7 +308,7 @@ bool autoload_t::locate_file_and_maybe_load_it(const wcstring &cmd, bool really_
|
||||
|
||||
if (really_load) {
|
||||
return reloaded;
|
||||
} else {
|
||||
return found_file || has_script_source;
|
||||
}
|
||||
|
||||
return found_file || has_script_source;
|
||||
}
|
||||
|
||||
1432
src/builtin.cpp
1432
src/builtin.cpp
File diff suppressed because it is too large
Load Diff
@@ -109,6 +109,7 @@ int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_lis
|
||||
void builtin_print_help(parser_t &parser, io_streams_t &streams, const wchar_t *cmd,
|
||||
output_stream_t &b);
|
||||
int builtin_count_args(const wchar_t *const *argv);
|
||||
bool builtin_is_valid_varname(const wchar_t *varname, wcstring &errstr, const wchar_t *cmd);
|
||||
|
||||
void builtin_unknown_option(parser_t &parser, io_streams_t &streams, const wchar_t *cmd,
|
||||
const wchar_t *opt);
|
||||
|
||||
@@ -127,6 +127,10 @@ static void replace_part(const wchar_t *begin, const wchar_t *end, const wchar_t
|
||||
out_pos += wcslen(insert);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected append_mode");
|
||||
break;
|
||||
}
|
||||
}
|
||||
out.append(end);
|
||||
reader_set_buffer(out, out_pos);
|
||||
@@ -152,29 +156,23 @@ static void write_part(const wchar_t *begin, const wchar_t *end, int cut_at_curs
|
||||
while (tok.next(&token)) {
|
||||
if ((cut_at_cursor) && (token.offset + token.text.size() >= pos)) break;
|
||||
|
||||
switch (token.type) {
|
||||
case TOK_STRING: {
|
||||
wcstring tmp = token.text;
|
||||
unescape_string_in_place(&tmp, UNESCAPE_INCOMPLETE);
|
||||
out.append(tmp);
|
||||
out.push_back(L'\n');
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
if (token.type == TOK_STRING) {
|
||||
wcstring tmp = token.text;
|
||||
unescape_string_in_place(&tmp, UNESCAPE_INCOMPLETE);
|
||||
out.append(tmp);
|
||||
out.push_back(L'\n');
|
||||
}
|
||||
}
|
||||
|
||||
streams.out.append(out);
|
||||
|
||||
free(buff);
|
||||
} else {
|
||||
if (cut_at_cursor) {
|
||||
end = begin + pos;
|
||||
streams.out.append(begin, pos);
|
||||
} else {
|
||||
streams.out.append(begin, end - begin);
|
||||
}
|
||||
|
||||
// debug( 0, L"woot2 %ls -> %ls", buff, esc );
|
||||
streams.out.append(begin, end - begin);
|
||||
streams.out.append(L"\n");
|
||||
streams.out.push_back(L'\n');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,6 +330,10 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
|
||||
builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
return 1;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected opt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,12 +426,8 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
|
||||
|
||||
if (cursor_mode) {
|
||||
if (argc - w.woptind) {
|
||||
wchar_t *endptr;
|
||||
long new_pos;
|
||||
errno = 0;
|
||||
|
||||
new_pos = wcstol(argv[w.woptind], &endptr, 10);
|
||||
if (*endptr || errno) {
|
||||
long new_pos = fish_wcstol(argv[w.woptind]);
|
||||
if (errno) {
|
||||
streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, argv[0], argv[w.woptind]);
|
||||
builtin_print_help(parser, streams, argv[0], streams.err);
|
||||
}
|
||||
@@ -476,26 +474,24 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
|
||||
parse_util_token_extent(get_buffer(), get_cursor_pos(), &begin, &end, 0, 0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected buffer_part");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (argc - w.woptind) {
|
||||
case 0: {
|
||||
write_part(begin, end, cut_at_cursor, tokenize, streams);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
replace_part(begin, end, argv[w.woptind], append_mode);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
wcstring sb = argv[w.woptind];
|
||||
for (int i = w.woptind + 1; i < argc; i++) {
|
||||
sb.push_back(L'\n');
|
||||
sb.append(argv[i]);
|
||||
}
|
||||
replace_part(begin, end, sb.c_str(), append_mode);
|
||||
break;
|
||||
int arg_count = argc - w.woptind;
|
||||
if (arg_count == 0) {
|
||||
write_part(begin, end, cut_at_cursor, tokenize, streams);
|
||||
} else if (arg_count == 1) {
|
||||
replace_part(begin, end, argv[w.woptind], append_mode);
|
||||
} else {
|
||||
wcstring sb = argv[w.woptind];
|
||||
for (int i = w.woptind + 1; i < argc; i++) {
|
||||
sb.push_back(L'\n');
|
||||
sb.append(argv[i]);
|
||||
}
|
||||
replace_part(begin, end, sb.c_str(), append_mode);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -122,64 +122,46 @@ static void builtin_complete_remove(const wcstring_list_t &cmd, const wcstring_l
|
||||
// complete.cpp for any heavy lifting.
|
||||
int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
wgetopter_t w;
|
||||
bool res = false;
|
||||
int argc = 0;
|
||||
static int recursion_level = 0;
|
||||
|
||||
wchar_t *cmd = argv[0];
|
||||
int argc = builtin_count_args(argv);
|
||||
int result_mode = SHARED;
|
||||
int remove = 0;
|
||||
int authoritative = -1;
|
||||
|
||||
wcstring short_opt;
|
||||
wcstring_list_t gnu_opt, old_opt;
|
||||
const wchar_t *comp = L"", *desc = L"", *condition = L"";
|
||||
|
||||
bool do_complete = false;
|
||||
wcstring do_complete_param;
|
||||
|
||||
wcstring_list_t cmd;
|
||||
wcstring_list_t cmd_to_complete;
|
||||
wcstring_list_t path;
|
||||
wcstring_list_t wrap_targets;
|
||||
|
||||
static int recursion_level = 0;
|
||||
|
||||
argc = builtin_count_args(argv);
|
||||
|
||||
w.woptind = 0;
|
||||
|
||||
while (!res) {
|
||||
static const struct woption long_options[] = {{L"exclusive", no_argument, 0, 'x'},
|
||||
{L"no-files", no_argument, 0, 'f'},
|
||||
{L"require-parameter", no_argument, 0, 'r'},
|
||||
{L"path", required_argument, 0, 'p'},
|
||||
{L"command", required_argument, 0, 'c'},
|
||||
{L"short-option", required_argument, 0, 's'},
|
||||
{L"long-option", required_argument, 0, 'l'},
|
||||
{L"old-option", required_argument, 0, 'o'},
|
||||
{L"description", required_argument, 0, 'd'},
|
||||
{L"arguments", required_argument, 0, 'a'},
|
||||
{L"erase", no_argument, 0, 'e'},
|
||||
{L"unauthoritative", no_argument, 0, 'u'},
|
||||
{L"authoritative", no_argument, 0, 'A'},
|
||||
{L"condition", required_argument, 0, 'n'},
|
||||
{L"wraps", required_argument, 0, 'w'},
|
||||
{L"do-complete", optional_argument, 0, 'C'},
|
||||
{L"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
int opt_index = 0;
|
||||
int opt =
|
||||
w.wgetopt_long(argc, argv, L"a:c:p:s:l:o:d:frxeuAn:C::w:h", long_options, &opt_index);
|
||||
if (opt == -1) break;
|
||||
const wchar_t *short_options = L":a:c:p:s:l:o:d:frxeuAn:C::w:h";
|
||||
const struct woption long_options[] = {{L"exclusive", no_argument, NULL, 'x'},
|
||||
{L"no-files", no_argument, NULL, 'f'},
|
||||
{L"require-parameter", no_argument, NULL, 'r'},
|
||||
{L"path", required_argument, NULL, 'p'},
|
||||
{L"command", required_argument, NULL, 'c'},
|
||||
{L"short-option", required_argument, NULL, 's'},
|
||||
{L"long-option", required_argument, NULL, 'l'},
|
||||
{L"old-option", required_argument, NULL, 'o'},
|
||||
{L"description", required_argument, NULL, 'd'},
|
||||
{L"arguments", required_argument, NULL, 'a'},
|
||||
{L"erase", no_argument, NULL, 'e'},
|
||||
{L"unauthoritative", no_argument, NULL, 'u'},
|
||||
{L"authoritative", no_argument, NULL, 'A'},
|
||||
{L"condition", required_argument, NULL, 'n'},
|
||||
{L"wraps", required_argument, NULL, 'w'},
|
||||
{L"do-complete", optional_argument, NULL, 'C'},
|
||||
{L"help", no_argument, NULL, 'h'},
|
||||
{NULL, 0, NULL, 0}};
|
||||
|
||||
int opt;
|
||||
wgetopter_t w;
|
||||
while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 0: {
|
||||
if (long_options[opt_index].flag != 0) break;
|
||||
streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0],
|
||||
long_options[opt_index].name);
|
||||
builtin_print_help(parser, streams, argv[0], streams.err);
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
result_mode |= EXCLUSIVE;
|
||||
break;
|
||||
@@ -199,19 +181,15 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
if (opt == 'p')
|
||||
path.push_back(tmp);
|
||||
else
|
||||
cmd.push_back(tmp);
|
||||
cmd_to_complete.push_back(tmp);
|
||||
} else {
|
||||
streams.err.append_format(L"%ls: Invalid token '%ls'\n", argv[0], w.woptarg);
|
||||
res = true;
|
||||
streams.err.append_format(L"%ls: Invalid token '%ls'\n", cmd, w.woptarg);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
desc = w.woptarg;
|
||||
if (w.woptarg[0] == '\0') {
|
||||
streams.err.append_format(L"%ls: -d requires a non-empty string\n", argv[0]);
|
||||
res = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
@@ -225,24 +203,24 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
case 's': {
|
||||
short_opt.append(w.woptarg);
|
||||
if (w.woptarg[0] == '\0') {
|
||||
streams.err.append_format(L"%ls: -s requires a non-empty string\n", argv[0]);
|
||||
res = true;
|
||||
streams.err.append_format(L"%ls: -s requires a non-empty string\n", cmd);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
gnu_opt.push_back(w.woptarg);
|
||||
if (w.woptarg[0] == '\0') {
|
||||
streams.err.append_format(L"%ls: -l requires a non-empty string\n", argv[0]);
|
||||
res = true;
|
||||
streams.err.append_format(L"%ls: -l requires a non-empty string\n", cmd);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'o': {
|
||||
old_opt.push_back(w.woptarg);
|
||||
if (w.woptarg[0] == '\0') {
|
||||
streams.err.append_format(L"%ls: -o requires a non-empty string\n", argv[0]);
|
||||
res = true;
|
||||
streams.err.append_format(L"%ls: -o requires a non-empty string\n", cmd);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -268,143 +246,142 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
if (arg == NULL) {
|
||||
// This corresponds to using 'complete -C' in non-interactive mode.
|
||||
// See #2361.
|
||||
builtin_missing_argument(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
do_complete_param = arg;
|
||||
break;
|
||||
}
|
||||
case 'h': {
|
||||
builtin_print_help(parser, streams, argv[0], streams.out);
|
||||
return 0;
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
return STATUS_BUILTIN_OK;
|
||||
}
|
||||
case ':': {
|
||||
builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
case '?': {
|
||||
builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
res = true;
|
||||
builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected retval from wgetopt_long");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
if (condition && wcslen(condition)) {
|
||||
const wcstring condition_string = condition;
|
||||
parse_error_list_t errors;
|
||||
if (parse_util_detect_errors(condition_string, &errors,
|
||||
false /* do not accept incomplete */)) {
|
||||
streams.err.append_format(L"%ls: Condition '%ls' contained a syntax error", argv[0],
|
||||
condition);
|
||||
for (size_t i = 0; i < errors.size(); i++) {
|
||||
streams.err.append_format(L"\n%s: ", argv[0]);
|
||||
streams.err.append(errors.at(i).describe(condition_string));
|
||||
}
|
||||
res = true;
|
||||
if (w.woptind != argc) {
|
||||
streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
|
||||
builtin_print_help(parser, streams, cmd, streams.err);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
if (condition && wcslen(condition)) {
|
||||
const wcstring condition_string = condition;
|
||||
parse_error_list_t errors;
|
||||
if (parse_util_detect_errors(condition_string, &errors,
|
||||
false /* do not accept incomplete */)) {
|
||||
streams.err.append_format(L"%ls: Condition '%ls' contained a syntax error", cmd,
|
||||
condition);
|
||||
for (size_t i = 0; i < errors.size(); i++) {
|
||||
streams.err.append_format(L"\n%s: ", cmd);
|
||||
streams.err.append(errors.at(i).describe(condition_string));
|
||||
}
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
if (comp && wcslen(comp)) {
|
||||
wcstring prefix;
|
||||
if (argv[0]) {
|
||||
prefix.append(argv[0]);
|
||||
prefix.append(L": ");
|
||||
}
|
||||
if (comp && wcslen(comp)) {
|
||||
wcstring prefix;
|
||||
prefix.append(cmd);
|
||||
prefix.append(L": ");
|
||||
|
||||
wcstring err_text;
|
||||
if (parser.detect_errors_in_argument_list(comp, &err_text, prefix.c_str())) {
|
||||
streams.err.append_format(L"%ls: Completion '%ls' contained a syntax error\n",
|
||||
argv[0], comp);
|
||||
streams.err.append(err_text);
|
||||
streams.err.push_back(L'\n');
|
||||
res = true;
|
||||
}
|
||||
wcstring err_text;
|
||||
if (parser.detect_errors_in_argument_list(comp, &err_text, prefix.c_str())) {
|
||||
streams.err.append_format(L"%ls: Completion '%ls' contained a syntax error\n", cmd,
|
||||
comp);
|
||||
streams.err.append(err_text);
|
||||
streams.err.push_back(L'\n');
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
if (do_complete) {
|
||||
const wchar_t *token;
|
||||
if (do_complete) {
|
||||
const wchar_t *token;
|
||||
|
||||
parse_util_token_extent(do_complete_param.c_str(), do_complete_param.size(), &token, 0,
|
||||
0, 0);
|
||||
parse_util_token_extent(do_complete_param.c_str(), do_complete_param.size(), &token, 0,
|
||||
0, 0);
|
||||
|
||||
// Create a scoped transient command line, so that bulitin_commandline will see our
|
||||
// argument, not the reader buffer.
|
||||
builtin_commandline_scoped_transient_t temp_buffer(do_complete_param);
|
||||
// Create a scoped transient command line, so that bulitin_commandline will see our
|
||||
// argument, not the reader buffer.
|
||||
builtin_commandline_scoped_transient_t temp_buffer(do_complete_param);
|
||||
|
||||
if (recursion_level < 1) {
|
||||
recursion_level++;
|
||||
if (recursion_level < 1) {
|
||||
recursion_level++;
|
||||
|
||||
std::vector<completion_t> comp;
|
||||
complete(do_complete_param, &comp, COMPLETION_REQUEST_DEFAULT,
|
||||
env_vars_snapshot_t::current());
|
||||
std::vector<completion_t> comp;
|
||||
complete(do_complete_param, &comp, COMPLETION_REQUEST_DEFAULT,
|
||||
env_vars_snapshot_t::current());
|
||||
|
||||
for (size_t i = 0; i < comp.size(); i++) {
|
||||
const completion_t &next = comp.at(i);
|
||||
for (size_t i = 0; i < comp.size(); i++) {
|
||||
const completion_t &next = comp.at(i);
|
||||
|
||||
// Make a fake commandline, and then apply the completion to it.
|
||||
const wcstring faux_cmdline = token;
|
||||
size_t tmp_cursor = faux_cmdline.size();
|
||||
wcstring faux_cmdline_with_completion = completion_apply_to_command_line(
|
||||
next.completion, next.flags, faux_cmdline, &tmp_cursor, false);
|
||||
// Make a fake commandline, and then apply the completion to it.
|
||||
const wcstring faux_cmdline = token;
|
||||
size_t tmp_cursor = faux_cmdline.size();
|
||||
wcstring faux_cmdline_with_completion = completion_apply_to_command_line(
|
||||
next.completion, next.flags, faux_cmdline, &tmp_cursor, false);
|
||||
|
||||
// completion_apply_to_command_line will append a space unless COMPLETE_NO_SPACE
|
||||
// is set. We don't want to set COMPLETE_NO_SPACE because that won't close
|
||||
// quotes. What we want is to close the quote, but not append the space. So we
|
||||
// just look for the space and clear it.
|
||||
if (!(next.flags & COMPLETE_NO_SPACE) &&
|
||||
string_suffixes_string(L" ", faux_cmdline_with_completion)) {
|
||||
faux_cmdline_with_completion.resize(faux_cmdline_with_completion.size() -
|
||||
1);
|
||||
}
|
||||
|
||||
// The input data is meant to be something like you would have on the command
|
||||
// line, e.g. includes backslashes. The output should be raw, i.e. unescaped. So
|
||||
// we need to unescape the command line. See #1127.
|
||||
unescape_string_in_place(&faux_cmdline_with_completion, UNESCAPE_DEFAULT);
|
||||
streams.out.append(faux_cmdline_with_completion);
|
||||
|
||||
// Append any description.
|
||||
if (!next.description.empty()) {
|
||||
streams.out.push_back(L'\t');
|
||||
streams.out.append(next.description);
|
||||
}
|
||||
streams.out.push_back(L'\n');
|
||||
// completion_apply_to_command_line will append a space unless COMPLETE_NO_SPACE
|
||||
// is set. We don't want to set COMPLETE_NO_SPACE because that won't close
|
||||
// quotes. What we want is to close the quote, but not append the space. So we
|
||||
// just look for the space and clear it.
|
||||
if (!(next.flags & COMPLETE_NO_SPACE) &&
|
||||
string_suffixes_string(L" ", faux_cmdline_with_completion)) {
|
||||
faux_cmdline_with_completion.resize(faux_cmdline_with_completion.size() -
|
||||
1);
|
||||
}
|
||||
|
||||
recursion_level--;
|
||||
}
|
||||
} else if (w.woptind != argc) {
|
||||
streams.err.append_format(_(L"%ls: Too many arguments\n"), argv[0]);
|
||||
builtin_print_help(parser, streams, argv[0], streams.err);
|
||||
// The input data is meant to be something like you would have on the command
|
||||
// line, e.g. includes backslashes. The output should be raw, i.e. unescaped. So
|
||||
// we need to unescape the command line. See #1127.
|
||||
unescape_string_in_place(&faux_cmdline_with_completion, UNESCAPE_DEFAULT);
|
||||
streams.out.append(faux_cmdline_with_completion);
|
||||
|
||||
res = true;
|
||||
} else if (cmd.empty() && path.empty()) {
|
||||
// No arguments specified, meaning we print the definitions of all specified completions
|
||||
// to stdout.
|
||||
streams.out.append(complete_print());
|
||||
// Append any description.
|
||||
if (!next.description.empty()) {
|
||||
streams.out.push_back(L'\t');
|
||||
streams.out.append(next.description);
|
||||
}
|
||||
streams.out.push_back(L'\n');
|
||||
}
|
||||
|
||||
recursion_level--;
|
||||
}
|
||||
} else if (cmd_to_complete.empty() && path.empty()) {
|
||||
// No arguments specified, meaning we print the definitions of all specified completions
|
||||
// to stdout.
|
||||
streams.out.append(complete_print());
|
||||
} else {
|
||||
int flags = COMPLETE_AUTO_SPACE;
|
||||
|
||||
if (remove) {
|
||||
builtin_complete_remove(cmd_to_complete, path, short_opt.c_str(), gnu_opt, old_opt);
|
||||
} else {
|
||||
int flags = COMPLETE_AUTO_SPACE;
|
||||
builtin_complete_add(cmd_to_complete, path, short_opt.c_str(), gnu_opt, old_opt,
|
||||
result_mode, authoritative, condition, comp, desc, flags);
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
builtin_complete_remove(cmd, path, short_opt.c_str(), gnu_opt, old_opt);
|
||||
|
||||
} else {
|
||||
builtin_complete_add(cmd, path, short_opt.c_str(), gnu_opt, old_opt, result_mode,
|
||||
authoritative, condition, comp, desc, flags);
|
||||
}
|
||||
|
||||
// Handle wrap targets (probably empty). We only wrap commands, not paths.
|
||||
for (size_t w = 0; w < wrap_targets.size(); w++) {
|
||||
const wcstring &wrap_target = wrap_targets.at(w);
|
||||
for (size_t i = 0; i < cmd.size(); i++) {
|
||||
(remove ? complete_remove_wrapper : complete_add_wrapper)(cmd.at(i),
|
||||
wrap_target);
|
||||
}
|
||||
// Handle wrap targets (probably empty). We only wrap commands, not paths.
|
||||
for (size_t w = 0; w < wrap_targets.size(); w++) {
|
||||
const wcstring &wrap_target = wrap_targets.at(w);
|
||||
for (size_t i = 0; i < cmd_to_complete.size(); i++) {
|
||||
(remove ? complete_remove_wrapper : complete_add_wrapper)(cmd_to_complete.at(i),
|
||||
wrap_target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res ? 1 : 0;
|
||||
return STATUS_BUILTIN_OK;
|
||||
}
|
||||
|
||||
@@ -101,6 +101,10 @@ static void builtin_jobs_print(const job_t *j, int mode, int header, io_streams_
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected mode");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +163,10 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
return 1;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected opt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,11 +186,8 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
int i;
|
||||
|
||||
for (i = w.woptind; i < argc; i++) {
|
||||
int pid;
|
||||
wchar_t *end;
|
||||
errno = 0;
|
||||
pid = fish_wcstoi(argv[i], &end, 10);
|
||||
if (errno || *end) {
|
||||
int pid = fish_wcstoi(argv[i]);
|
||||
if (errno || pid < 0) {
|
||||
streams.err.append_format(_(L"%ls: '%ls' is not a job\n"), argv[0], argv[i]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <wchar.h>
|
||||
@@ -508,39 +508,48 @@ void builtin_printf_state_t::print_direc(const wchar_t *start, size_t length, wc
|
||||
case L'G': {
|
||||
long double arg = string_to_scalar_type<long double>(argument, this);
|
||||
if (!have_field_width) {
|
||||
if (!have_precision)
|
||||
if (!have_precision) {
|
||||
this->append_format_output(fmt.c_str(), arg);
|
||||
else
|
||||
} else {
|
||||
this->append_format_output(fmt.c_str(), precision, arg);
|
||||
}
|
||||
} else {
|
||||
if (!have_precision)
|
||||
if (!have_precision) {
|
||||
this->append_format_output(fmt.c_str(), field_width, arg);
|
||||
else
|
||||
} else {
|
||||
this->append_format_output(fmt.c_str(), field_width, precision, arg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case L'c': {
|
||||
if (!have_field_width)
|
||||
if (!have_field_width) {
|
||||
this->append_format_output(fmt.c_str(), *argument);
|
||||
else
|
||||
} else {
|
||||
this->append_format_output(fmt.c_str(), field_width, *argument);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case L's': {
|
||||
if (!have_field_width) {
|
||||
if (!have_precision) {
|
||||
this->append_format_output(fmt.c_str(), argument);
|
||||
} else
|
||||
} else {
|
||||
this->append_format_output(fmt.c_str(), precision, argument);
|
||||
}
|
||||
} else {
|
||||
if (!have_precision)
|
||||
if (!have_precision) {
|
||||
this->append_format_output(fmt.c_str(), field_width, argument);
|
||||
else
|
||||
} else {
|
||||
this->append_format_output(fmt.c_str(), field_width, precision, argument);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected opt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,8 +597,7 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch
|
||||
}
|
||||
|
||||
modify_allowed_format_specifiers(ok, "aAcdeEfFgGiosuxX", true);
|
||||
|
||||
for (;; f++, direc_length++) {
|
||||
for (bool continue_looking_for_flags = true; continue_looking_for_flags;) {
|
||||
switch (*f) {
|
||||
case L'I':
|
||||
case L'\'': {
|
||||
@@ -609,10 +617,16 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch
|
||||
modify_allowed_format_specifiers(ok, "cs", false);
|
||||
break;
|
||||
}
|
||||
default: { goto no_more_flag_characters; }
|
||||
default: {
|
||||
continue_looking_for_flags = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (continue_looking_for_flags) {
|
||||
f++;
|
||||
direc_length++;
|
||||
}
|
||||
}
|
||||
no_more_flag_characters:;
|
||||
|
||||
if (*f == L'*') {
|
||||
++f;
|
||||
@@ -687,7 +701,10 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch
|
||||
f += print_esc(f, false);
|
||||
break;
|
||||
}
|
||||
default: { this->append_output(*f); }
|
||||
default: {
|
||||
this->append_output(*f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return save_argc - argc;
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include <algorithm>
|
||||
@@ -77,12 +79,10 @@ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope,
|
||||
struct stat buff;
|
||||
if (wstat(dir, &buff) == -1) {
|
||||
error = true;
|
||||
}
|
||||
else if (!S_ISDIR(buff.st_mode)) {
|
||||
} else if (!S_ISDIR(buff.st_mode)) {
|
||||
error = true;
|
||||
errno = ENOTDIR;
|
||||
}
|
||||
else if (waccess(dir, X_OK) == -1) {
|
||||
} else if (waccess(dir, X_OK) == -1) {
|
||||
error = true;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope,
|
||||
any_success = true;
|
||||
} else {
|
||||
streams.err.append_format(_(BUILTIN_SET_PATH_ERROR), L"set", key, dir.c_str(),
|
||||
strerror(errno));
|
||||
strerror(errno));
|
||||
const wchar_t *colon = wcschr(dir.c_str(), L':');
|
||||
|
||||
if (colon && *(colon + 1)) {
|
||||
@@ -123,6 +123,9 @@ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope,
|
||||
}
|
||||
|
||||
switch (env_set(key, val_str, scope | ENV_USER)) {
|
||||
case ENV_OK: {
|
||||
break;
|
||||
}
|
||||
case ENV_PERM: {
|
||||
streams.err.append_format(_(L"%ls: Tried to change the read-only variable '%ls'\n"),
|
||||
L"set", key);
|
||||
@@ -143,6 +146,10 @@ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope,
|
||||
retcode = 1;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected env_set() ret val");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retcode;
|
||||
@@ -159,7 +166,6 @@ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope,
|
||||
static int parse_index(std::vector<long> &indexes, const wchar_t *src, const wchar_t *name,
|
||||
size_t var_count, io_streams_t &streams) {
|
||||
size_t len;
|
||||
|
||||
int count = 0;
|
||||
const wchar_t *src_orig = src;
|
||||
|
||||
@@ -167,9 +173,7 @@ static int parse_index(std::vector<long> &indexes, const wchar_t *src, const wch
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*src != L'\0' && (iswalnum(*src) || *src == L'_')) {
|
||||
src++;
|
||||
}
|
||||
while (*src != L'\0' && (iswalnum(*src) || *src == L'_')) src++;
|
||||
|
||||
if (*src != L'[') {
|
||||
streams.err.append_format(_(BUILTIN_SET_ARG_COUNT), L"set");
|
||||
@@ -177,7 +181,6 @@ static int parse_index(std::vector<long> &indexes, const wchar_t *src, const wch
|
||||
}
|
||||
|
||||
len = src - src_orig;
|
||||
|
||||
if ((wcsncmp(src_orig, name, len) != 0) || (wcslen(name) != (len))) {
|
||||
streams.err.append_format(
|
||||
_(L"%ls: Multiple variable names specified in single call (%ls and %.*ls)\n"), L"set",
|
||||
@@ -186,37 +189,26 @@ static int parse_index(std::vector<long> &indexes, const wchar_t *src, const wch
|
||||
}
|
||||
|
||||
src++;
|
||||
|
||||
while (iswspace(*src)) {
|
||||
src++;
|
||||
}
|
||||
while (iswspace(*src)) src++;
|
||||
|
||||
while (*src != L']') {
|
||||
wchar_t *end;
|
||||
|
||||
long l_ind;
|
||||
|
||||
errno = 0;
|
||||
|
||||
l_ind = wcstol(src, &end, 10);
|
||||
|
||||
if (end == src || errno) {
|
||||
const wchar_t *end;
|
||||
long l_ind = fish_wcstol(src, &end);
|
||||
if (errno > 0) { // ignore errno == -1 meaning the int did not end with a '\0'
|
||||
streams.err.append_format(_(L"%ls: Invalid index starting at '%ls'\n"), L"set", src);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (l_ind < 0) {
|
||||
l_ind = var_count + l_ind + 1;
|
||||
}
|
||||
if (l_ind < 0) l_ind = var_count + l_ind + 1;
|
||||
|
||||
src = end;
|
||||
src = end; //!OCLINT(parameter reassignment)
|
||||
if (*src == L'.' && *(src + 1) == L'.') {
|
||||
src += 2;
|
||||
long l_ind2 = wcstol(src, &end, 10);
|
||||
if (end == src || errno) {
|
||||
long l_ind2 = fish_wcstol(src, &end);
|
||||
if (errno > 0) { // ignore errno == -1 meaning the int did not end with a '\0'
|
||||
return 1;
|
||||
}
|
||||
src = end;
|
||||
src = end; //!OCLINT(parameter reassignment)
|
||||
|
||||
if (l_ind2 < 0) {
|
||||
l_ind2 = var_count + l_ind2 + 1;
|
||||
@@ -231,6 +223,7 @@ static int parse_index(std::vector<long> &indexes, const wchar_t *src, const wch
|
||||
indexes.push_back(l_ind);
|
||||
count++;
|
||||
}
|
||||
|
||||
while (iswspace(*src)) src++;
|
||||
}
|
||||
|
||||
@@ -342,7 +335,7 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
int erase = 0, list = 0, unexport = 0;
|
||||
int universal = 0, query = 0;
|
||||
bool shorten_ok = true;
|
||||
bool preserve_incoming_failure_exit_status = true;
|
||||
bool preserve_failure_exit_status = true;
|
||||
const int incoming_exit_status = proc_get_last_status();
|
||||
|
||||
// Variables used for performing the actual work.
|
||||
@@ -351,8 +344,6 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
int scope;
|
||||
int slice = 0;
|
||||
|
||||
const wchar_t *bad_char = NULL;
|
||||
|
||||
// Parse options to obtain the requested operation and the modifiers.
|
||||
w.woptind = 0;
|
||||
while (1) {
|
||||
@@ -368,12 +359,12 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
}
|
||||
case 'e': {
|
||||
erase = 1;
|
||||
preserve_incoming_failure_exit_status = false;
|
||||
preserve_failure_exit_status = false;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
list = 1;
|
||||
preserve_incoming_failure_exit_status = false;
|
||||
preserve_failure_exit_status = false;
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
@@ -402,7 +393,7 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
}
|
||||
case 'q': {
|
||||
query = 1;
|
||||
preserve_incoming_failure_exit_status = false;
|
||||
preserve_failure_exit_status = false;
|
||||
break;
|
||||
}
|
||||
case 'h': {
|
||||
@@ -528,18 +519,11 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
*wcschr(dest, L'[') = 0;
|
||||
}
|
||||
|
||||
if (!wcslen(dest)) {
|
||||
free(dest);
|
||||
streams.err.append_format(BUILTIN_ERR_VARNAME_ZERO, argv[0]);
|
||||
wcstring errstr;
|
||||
if (!builtin_is_valid_varname(dest, errstr, argv[0])) {
|
||||
streams.err.append(errstr);
|
||||
builtin_print_help(parser, streams, argv[0], streams.err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((bad_char = wcsvarname(dest))) {
|
||||
streams.err.append_format(BUILTIN_ERR_VARCHAR, argv[0], *bad_char);
|
||||
builtin_print_help(parser, streams, argv[0], streams.err);
|
||||
free(dest);
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
// Set assignment can work in two modes, either using slices or using the whole array. We detect
|
||||
@@ -633,7 +617,7 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
|
||||
free(dest);
|
||||
|
||||
if (retcode == STATUS_BUILTIN_OK && preserve_incoming_failure_exit_status)
|
||||
if (retcode == STATUS_BUILTIN_OK && preserve_failure_exit_status)
|
||||
retcode = incoming_exit_status;
|
||||
return retcode;
|
||||
}
|
||||
|
||||
@@ -77,13 +77,13 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
// Parse options to obtain the requested operation and the modifiers.
|
||||
w.woptind = 0;
|
||||
while (1) {
|
||||
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
|
||||
if (c == -1) {
|
||||
if (opt == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
switch (opt) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
@@ -110,6 +110,10 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
case '?': {
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected opt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,19 +163,17 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
builtin_set_color_output.clear();
|
||||
output_set_writer(set_color_builtin_outputter);
|
||||
|
||||
if (bold) {
|
||||
if (enter_bold_mode) writembs(tparm(enter_bold_mode));
|
||||
if (bold && enter_bold_mode) {
|
||||
writembs(tparm(enter_bold_mode));
|
||||
}
|
||||
|
||||
if (underline) {
|
||||
if (enter_underline_mode) writembs(enter_underline_mode);
|
||||
if (underline && enter_underline_mode) {
|
||||
writembs(enter_underline_mode);
|
||||
}
|
||||
|
||||
if (bgcolor != NULL) {
|
||||
if (bg.is_normal()) {
|
||||
write_color(rgb_color_t::black(), false /* not is_fg */);
|
||||
writembs(tparm(exit_attribute_mode));
|
||||
}
|
||||
if (bgcolor != NULL && bg.is_normal()) {
|
||||
write_color(rgb_color_t::black(), false /* not is_fg */);
|
||||
writembs(tparm(exit_attribute_mode));
|
||||
}
|
||||
|
||||
if (!fg.is_none()) {
|
||||
@@ -188,10 +190,8 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if (bgcolor != NULL) {
|
||||
if (!bg.is_normal() && !bg.is_reset()) {
|
||||
write_color(bg, false /* not is_fg */);
|
||||
}
|
||||
if (bgcolor != NULL && !bg.is_normal() && !bg.is_reset()) {
|
||||
write_color(bg, false /* not is_fg */);
|
||||
}
|
||||
|
||||
// Restore saved writer function.
|
||||
|
||||
@@ -100,12 +100,13 @@ static int string_escape(parser_t &parser, io_streams_t &streams, int argc, wcha
|
||||
escape_flags_t flags = ESCAPE_ALL;
|
||||
wgetopter_t w;
|
||||
for (;;) {
|
||||
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
|
||||
if (c == -1) {
|
||||
if (opt == -1) {
|
||||
break;
|
||||
}
|
||||
switch (c) {
|
||||
|
||||
switch (opt) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
@@ -117,6 +118,10 @@ static int string_escape(parser_t &parser, io_streams_t &streams, int argc, wcha
|
||||
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected opt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,11 +150,13 @@ static int string_join(parser_t &parser, io_streams_t &streams, int argc, wchar_
|
||||
bool quiet = false;
|
||||
wgetopter_t w;
|
||||
for (;;) {
|
||||
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
if (c == -1) {
|
||||
int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
|
||||
if (opt == -1) {
|
||||
break;
|
||||
}
|
||||
switch (c) {
|
||||
|
||||
switch (opt) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
@@ -161,6 +168,10 @@ static int string_join(parser_t &parser, io_streams_t &streams, int argc, wchar_
|
||||
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected opt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,12 +213,12 @@ static int string_length(parser_t &parser, io_streams_t &streams, int argc, wcha
|
||||
bool quiet = false;
|
||||
wgetopter_t w;
|
||||
for (;;) {
|
||||
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
|
||||
if (c == -1) {
|
||||
if (opt == -1) {
|
||||
break;
|
||||
}
|
||||
switch (c) {
|
||||
switch (opt) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
@@ -219,6 +230,10 @@ static int string_length(parser_t &parser, io_streams_t &streams, int argc, wcha
|
||||
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected opt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,12 +514,12 @@ static int string_match(parser_t &parser, io_streams_t &streams, int argc, wchar
|
||||
bool regex = false;
|
||||
wgetopter_t w;
|
||||
for (;;) {
|
||||
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
|
||||
if (c == -1) {
|
||||
if (opt == -1) {
|
||||
break;
|
||||
}
|
||||
switch (c) {
|
||||
switch (opt) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
@@ -536,6 +551,10 @@ static int string_match(parser_t &parser, io_streams_t &streams, int argc, wchar
|
||||
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected opt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -666,59 +685,63 @@ class regex_replacer_t : public string_replacer_t {
|
||||
regex(argv0, pattern, opts.ignore_case, streams),
|
||||
replacement(interpret_escapes(replacement_)) {}
|
||||
|
||||
bool replace_matches(const wchar_t *arg) {
|
||||
// A return value of true means all is well (even if no replacements were performed), false
|
||||
// indicates an unrecoverable error.
|
||||
if (regex.code == 0) {
|
||||
// pcre2_compile() failed
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t options = PCRE2_SUBSTITUTE_OVERFLOW_LENGTH | PCRE2_SUBSTITUTE_EXTENDED |
|
||||
(opts.all ? PCRE2_SUBSTITUTE_GLOBAL : 0);
|
||||
size_t arglen = wcslen(arg);
|
||||
PCRE2_SIZE bufsize = (arglen == 0) ? 16 : 2 * arglen;
|
||||
wchar_t *output = (wchar_t *)malloc(sizeof(wchar_t) * bufsize);
|
||||
int pcre2_rc = 0;
|
||||
for (;;) {
|
||||
if (output == NULL) {
|
||||
DIE_MEM();
|
||||
}
|
||||
PCRE2_SIZE outlen = bufsize;
|
||||
pcre2_rc = pcre2_substitute(regex.code, PCRE2_SPTR(arg), arglen,
|
||||
0, // start offset
|
||||
options, regex.match,
|
||||
0, // match context
|
||||
PCRE2_SPTR(replacement.c_str()), PCRE2_ZERO_TERMINATED,
|
||||
(PCRE2_UCHAR *)output, &outlen);
|
||||
|
||||
if (pcre2_rc == PCRE2_ERROR_NOMEMORY && bufsize < outlen) {
|
||||
bufsize = outlen;
|
||||
// cppcheck-suppress memleakOnRealloc
|
||||
output = (wchar_t *)realloc(output, sizeof(wchar_t) * bufsize);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
bool rc = true;
|
||||
if (pcre2_rc < 0) {
|
||||
string_error(streams, _(L"%ls: Regular expression substitute error: %ls\n"), argv0,
|
||||
pcre2_strerror(pcre2_rc).c_str());
|
||||
rc = false;
|
||||
} else {
|
||||
if (!opts.quiet) {
|
||||
streams.out.append(output);
|
||||
streams.out.append(L'\n');
|
||||
}
|
||||
total_replaced += pcre2_rc;
|
||||
}
|
||||
|
||||
free(output);
|
||||
return rc;
|
||||
}
|
||||
bool replace_matches(const wchar_t *arg);
|
||||
};
|
||||
|
||||
/// A return value of true means all is well (even if no replacements were performed), false
|
||||
/// indicates an unrecoverable error.
|
||||
bool regex_replacer_t::replace_matches(const wchar_t *arg) {
|
||||
if (regex.code == 0) {
|
||||
// pcre2_compile() failed
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t options = PCRE2_SUBSTITUTE_OVERFLOW_LENGTH | PCRE2_SUBSTITUTE_EXTENDED |
|
||||
(opts.all ? PCRE2_SUBSTITUTE_GLOBAL : 0);
|
||||
size_t arglen = wcslen(arg);
|
||||
PCRE2_SIZE bufsize = (arglen == 0) ? 16 : 2 * arglen;
|
||||
wchar_t *output = (wchar_t *)malloc(sizeof(wchar_t) * bufsize);
|
||||
int pcre2_rc;
|
||||
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
if (output == NULL) {
|
||||
DIE_MEM();
|
||||
}
|
||||
PCRE2_SIZE outlen = bufsize;
|
||||
pcre2_rc = pcre2_substitute(regex.code, PCRE2_SPTR(arg), arglen,
|
||||
0, // start offset
|
||||
options, regex.match,
|
||||
0, // match context
|
||||
PCRE2_SPTR(replacement.c_str()), PCRE2_ZERO_TERMINATED,
|
||||
(PCRE2_UCHAR *)output, &outlen);
|
||||
|
||||
if (pcre2_rc != PCRE2_ERROR_NOMEMORY || bufsize >= outlen) {
|
||||
done = true;
|
||||
} else {
|
||||
bufsize = outlen;
|
||||
wchar_t *new_output = (wchar_t *)realloc(output, sizeof(wchar_t) * bufsize);
|
||||
if (new_output) output = new_output;
|
||||
}
|
||||
}
|
||||
|
||||
bool rc = true;
|
||||
if (pcre2_rc < 0) {
|
||||
string_error(streams, _(L"%ls: Regular expression substitute error: %ls\n"), argv0,
|
||||
pcre2_strerror(pcre2_rc).c_str());
|
||||
rc = false;
|
||||
} else {
|
||||
if (!opts.quiet) {
|
||||
streams.out.append(output);
|
||||
streams.out.append(L'\n');
|
||||
}
|
||||
total_replaced += pcre2_rc;
|
||||
}
|
||||
|
||||
free(output);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int string_replace(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) {
|
||||
const wchar_t *short_options = L"aiqr";
|
||||
const struct woption long_options[] = {{L"all", no_argument, 0, 'a'},
|
||||
@@ -731,12 +754,12 @@ static int string_replace(parser_t &parser, io_streams_t &streams, int argc, wch
|
||||
bool regex = false;
|
||||
wgetopter_t w;
|
||||
for (;;) {
|
||||
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
|
||||
if (c == -1) {
|
||||
if (opt == -1) {
|
||||
break;
|
||||
}
|
||||
switch (c) {
|
||||
switch (opt) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
@@ -760,6 +783,10 @@ static int string_replace(parser_t &parser, io_streams_t &streams, int argc, wch
|
||||
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected opt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -851,10 +878,8 @@ static int string_split(parser_t &parser, io_streams_t &streams, int argc, wchar
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
errno = 0;
|
||||
wchar_t *endptr = 0;
|
||||
max = wcstol(w.woptarg, &endptr, 10);
|
||||
if (*endptr != L'\0' || errno != 0) {
|
||||
max = fish_wcstol(w.woptarg);
|
||||
if (errno) {
|
||||
string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
@@ -876,6 +901,10 @@ static int string_split(parser_t &parser, io_streams_t &streams, int argc, wchar
|
||||
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected opt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,7 +967,7 @@ static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t
|
||||
long length = -1;
|
||||
bool quiet = false;
|
||||
wgetopter_t w;
|
||||
wchar_t *endptr = NULL;
|
||||
|
||||
for (;;) {
|
||||
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
|
||||
@@ -950,16 +979,14 @@ static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
errno = 0;
|
||||
length = wcstol(w.woptarg, &endptr, 10);
|
||||
if (*endptr != L'\0' || (errno != 0 && errno != ERANGE)) {
|
||||
string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
length = fish_wcstol(w.woptarg);
|
||||
if (length < 0 || errno == ERANGE) {
|
||||
string_error(streams, _(L"%ls: Invalid length value '%ls'\n"), argv[0],
|
||||
w.woptarg);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
} else if (errno) {
|
||||
string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -968,16 +995,14 @@ static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
errno = 0;
|
||||
start = wcstol(w.woptarg, &endptr, 10);
|
||||
if (*endptr != L'\0' || (errno != 0 && errno != ERANGE)) {
|
||||
string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
start = fish_wcstol(w.woptarg);
|
||||
if (start == 0 || start == LONG_MIN || errno == ERANGE) {
|
||||
string_error(streams, _(L"%ls: Invalid start value '%ls'\n"), argv[0],
|
||||
w.woptarg);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
} else if (errno) {
|
||||
string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -989,6 +1014,10 @@ static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t
|
||||
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected opt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1078,6 +1107,10 @@ static int string_trim(parser_t &parser, io_streams_t &streams, int argc, wchar_
|
||||
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
return BUILTIN_STRING_ERROR;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected opt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1124,7 +1157,8 @@ static int string_trim(parser_t &parser, io_streams_t &streams, int argc, wchar_
|
||||
|
||||
static const struct string_subcommand {
|
||||
const wchar_t *name;
|
||||
int (*handler)(parser_t &, io_streams_t &, int argc, wchar_t **argv);
|
||||
int (*handler)(parser_t &, io_streams_t &, int argc, //!OCLINT(unused param)
|
||||
wchar_t **argv); //!OCLINT(unused param)
|
||||
}
|
||||
|
||||
string_subcommands[] = {
|
||||
|
||||
@@ -518,8 +518,8 @@ expression *test_parser::parse_expression(unsigned int start, unsigned int end)
|
||||
unsigned int argc = end - start;
|
||||
switch (argc) {
|
||||
case 0: {
|
||||
assert(0); // should have been caught by the above test
|
||||
return NULL;
|
||||
DIE("argc should not be zero"); // should have been caught by the above test
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
return error(L"Missing argument at index %u", start + 1);
|
||||
@@ -579,62 +579,55 @@ bool binary_primary::evaluate(wcstring_list_t &errors) {
|
||||
}
|
||||
|
||||
bool unary_operator::evaluate(wcstring_list_t &errors) {
|
||||
switch (token) {
|
||||
case test_bang: {
|
||||
assert(subject.get());
|
||||
return !subject->evaluate(errors);
|
||||
}
|
||||
default: {
|
||||
errors.push_back(format_string(L"Unknown token type in %s", __func__));
|
||||
return false;
|
||||
}
|
||||
if (token == test_bang) {
|
||||
assert(subject.get());
|
||||
return !subject->evaluate(errors);
|
||||
}
|
||||
|
||||
errors.push_back(format_string(L"Unknown token type in %s", __func__));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool combining_expression::evaluate(wcstring_list_t &errors) {
|
||||
switch (token) {
|
||||
case test_combine_and:
|
||||
case test_combine_or: {
|
||||
// One-element case.
|
||||
if (subjects.size() == 1) return subjects.at(0)->evaluate(errors);
|
||||
if (token == test_combine_and || token == test_combine_or) {
|
||||
assert(!subjects.empty()); //!OCLINT(multiple unary operator)
|
||||
assert(combiners.size() + 1 == subjects.size());
|
||||
|
||||
// Evaluate our lists, remembering that AND has higher precedence than OR. We can
|
||||
// visualize this as a sequence of OR expressions of AND expressions.
|
||||
assert(combiners.size() + 1 == subjects.size());
|
||||
assert(!subjects.empty());
|
||||
// One-element case.
|
||||
if (subjects.size() == 1) return subjects.at(0)->evaluate(errors);
|
||||
|
||||
size_t idx = 0, max = subjects.size();
|
||||
bool or_result = false;
|
||||
while (idx < max) {
|
||||
if (or_result) { // short circuit
|
||||
// Evaluate our lists, remembering that AND has higher precedence than OR. We can
|
||||
// visualize this as a sequence of OR expressions of AND expressions.
|
||||
size_t idx = 0, max = subjects.size();
|
||||
bool or_result = false;
|
||||
while (idx < max) {
|
||||
if (or_result) { // short circuit
|
||||
break;
|
||||
}
|
||||
|
||||
// Evaluate a stream of AND starting at given subject index. It may only have one
|
||||
// element.
|
||||
bool and_result = true;
|
||||
for (; idx < max; idx++) {
|
||||
// Evaluate it, short-circuiting.
|
||||
and_result = and_result && subjects.at(idx)->evaluate(errors);
|
||||
|
||||
// If the combiner at this index (which corresponding to how we combine with the
|
||||
// next subject) is not AND, then exit the loop.
|
||||
if (idx + 1 < max && combiners.at(idx) != test_combine_and) {
|
||||
idx++;
|
||||
break;
|
||||
}
|
||||
|
||||
// Evaluate a stream of AND starting at given subject index. It may only have one
|
||||
// element.
|
||||
bool and_result = true;
|
||||
for (; idx < max; idx++) {
|
||||
// Evaluate it, short-circuiting.
|
||||
and_result = and_result && subjects.at(idx)->evaluate(errors);
|
||||
|
||||
// If the combiner at this index (which corresponding to how we combine with the
|
||||
// next subject) is not AND, then exit the loop.
|
||||
if (idx + 1 < max && combiners.at(idx) != test_combine_and) {
|
||||
idx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// OR it in.
|
||||
or_result = or_result || and_result;
|
||||
}
|
||||
return or_result;
|
||||
}
|
||||
default: {
|
||||
errors.push_back(format_string(L"Unknown token type in %s", __func__));
|
||||
return BUILTIN_TEST_FAIL;
|
||||
|
||||
// OR it in.
|
||||
or_result = or_result || and_result;
|
||||
}
|
||||
return or_result;
|
||||
}
|
||||
|
||||
errors.push_back(format_string(L"Unknown token type in %s", __func__));
|
||||
return BUILTIN_TEST_FAIL;
|
||||
}
|
||||
|
||||
bool parenthetical_expression::evaluate(wcstring_list_t &errors) {
|
||||
@@ -798,42 +791,36 @@ int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
// Collect the arguments into a list.
|
||||
const wcstring_list_t args(argv + 1, argv + 1 + argc);
|
||||
|
||||
switch (argc) {
|
||||
case 0: {
|
||||
// Per 1003.1, exit false.
|
||||
return BUILTIN_TEST_FAIL;
|
||||
}
|
||||
case 1: {
|
||||
// Per 1003.1, exit true if the arg is non-empty.
|
||||
return args.at(0).empty() ? BUILTIN_TEST_FAIL : BUILTIN_TEST_SUCCESS;
|
||||
}
|
||||
default: {
|
||||
// Try parsing. If expr is not nil, we are responsible for deleting it.
|
||||
wcstring err;
|
||||
expression *expr = test_parser::parse_args(args, err);
|
||||
if (!expr) {
|
||||
#if 0
|
||||
printf("Oops! test was given args:\n");
|
||||
for (size_t i=0; i < argc; i++) {
|
||||
printf("\t%ls\n", args.at(i).c_str());
|
||||
}
|
||||
printf("and returned parse error: %ls\n", err.c_str());
|
||||
#endif
|
||||
streams.err.append(err);
|
||||
return BUILTIN_TEST_FAIL;
|
||||
}
|
||||
if (argc == 0) {
|
||||
return BUILTIN_TEST_FAIL; // Per 1003.1, exit false.
|
||||
} else if (argc == 1) {
|
||||
// Per 1003.1, exit true if the arg is non-empty.
|
||||
return args.at(0).empty() ? BUILTIN_TEST_FAIL : BUILTIN_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
wcstring_list_t eval_errors;
|
||||
bool result = expr->evaluate(eval_errors);
|
||||
if (!eval_errors.empty()) {
|
||||
printf("test returned eval errors:\n");
|
||||
for (size_t i = 0; i < eval_errors.size(); i++) {
|
||||
printf("\t%ls\n", eval_errors.at(i).c_str());
|
||||
}
|
||||
}
|
||||
delete expr;
|
||||
return result ? BUILTIN_TEST_SUCCESS : BUILTIN_TEST_FAIL;
|
||||
// Try parsing. If expr is not nil, we are responsible for deleting it.
|
||||
wcstring err;
|
||||
expression *expr = test_parser::parse_args(args, err);
|
||||
if (!expr) {
|
||||
#if 0
|
||||
printf("Oops! test was given args:\n");
|
||||
for (size_t i=0; i < argc; i++) {
|
||||
printf("\t%ls\n", args.at(i).c_str());
|
||||
}
|
||||
printf("and returned parse error: %ls\n", err.c_str());
|
||||
#endif
|
||||
streams.err.append(err);
|
||||
return BUILTIN_TEST_FAIL;
|
||||
}
|
||||
|
||||
wcstring_list_t eval_errors;
|
||||
bool result = expr->evaluate(eval_errors);
|
||||
if (!eval_errors.empty()) {
|
||||
printf("test returned eval errors:\n");
|
||||
for (size_t i = 0; i < eval_errors.size(); i++) {
|
||||
printf("\t%ls\n", eval_errors.at(i).c_str());
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
delete expr;
|
||||
return result ? BUILTIN_TEST_SUCCESS : BUILTIN_TEST_FAIL;
|
||||
}
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/resource.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "builtin.h"
|
||||
#include "common.h"
|
||||
#include "fallback.h" // IWYU pragma: keep
|
||||
#include "io.h"
|
||||
#include "proc.h"
|
||||
#include "util.h"
|
||||
#include "wgetopt.h"
|
||||
#include "wutil.h" // IWYU pragma: keep
|
||||
@@ -120,14 +121,11 @@ static const wchar_t *get_desc(int what) {
|
||||
|
||||
/// Set the new value of the specified resource limit. This function does _not_ multiply the limit
|
||||
// value by the multiplier constant used by the commandline ulimit.
|
||||
static int set(int resource, int hard, int soft, rlim_t value, io_streams_t &streams) {
|
||||
static int set_limit(int resource, int hard, int soft, rlim_t value, io_streams_t &streams) {
|
||||
struct rlimit ls;
|
||||
|
||||
getrlimit(resource, &ls);
|
||||
|
||||
if (hard) {
|
||||
ls.rlim_max = value;
|
||||
}
|
||||
|
||||
if (hard) ls.rlim_max = value;
|
||||
if (soft) {
|
||||
ls.rlim_cur = value;
|
||||
|
||||
@@ -139,185 +137,169 @@ static int set(int resource, int hard, int soft, rlim_t value, io_streams_t &str
|
||||
}
|
||||
|
||||
if (setrlimit(resource, &ls)) {
|
||||
if (errno == EPERM)
|
||||
if (errno == EPERM) {
|
||||
streams.err.append_format(
|
||||
L"ulimit: Permission denied when changing resource of type '%ls'\n",
|
||||
get_desc(resource));
|
||||
else
|
||||
} else {
|
||||
builtin_wperror(L"ulimit", streams);
|
||||
return 1;
|
||||
}
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
return 0;
|
||||
return STATUS_BUILTIN_OK;
|
||||
}
|
||||
|
||||
/// The ulimit builtin, used for setting resource limits.
|
||||
int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
wgetopter_t w;
|
||||
int hard = 0;
|
||||
int soft = 0;
|
||||
|
||||
int what = RLIMIT_FSIZE;
|
||||
int report_all = 0;
|
||||
|
||||
wchar_t *cmd = argv[0];
|
||||
int argc = builtin_count_args(argv);
|
||||
bool report_all = false;
|
||||
bool hard = false;
|
||||
bool soft = false;
|
||||
int what = RLIMIT_FSIZE;
|
||||
|
||||
w.woptind = 0;
|
||||
|
||||
while (1) {
|
||||
static const struct woption long_options[] = {
|
||||
{L"all", no_argument, 0, 'a'},
|
||||
{L"hard", no_argument, 0, 'H'},
|
||||
{L"soft", no_argument, 0, 'S'},
|
||||
{L"core-size", no_argument, 0, 'c'},
|
||||
{L"data-size", no_argument, 0, 'd'},
|
||||
{L"file-size", no_argument, 0, 'f'},
|
||||
{L"lock-size", no_argument, 0, 'l'},
|
||||
{L"resident-set-size", no_argument, 0, 'm'},
|
||||
{L"file-descriptor-count", no_argument, 0, 'n'},
|
||||
{L"stack-size", no_argument, 0, 's'},
|
||||
{L"cpu-time", no_argument, 0, 't'},
|
||||
{L"process-count", no_argument, 0, 'u'},
|
||||
{L"virtual-memory-size", no_argument, 0, 'v'},
|
||||
{L"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
int opt_index = 0;
|
||||
|
||||
int opt = w.wgetopt_long(argc, argv, L"aHScdflmnstuvh", long_options, &opt_index);
|
||||
if (opt == -1) break;
|
||||
const wchar_t *short_options = L":HSacdflmnstuvh";
|
||||
const struct woption long_options[] = {{L"all", no_argument, NULL, 'a'},
|
||||
{L"hard", no_argument, NULL, 'H'},
|
||||
{L"soft", no_argument, NULL, 'S'},
|
||||
{L"core-size", no_argument, NULL, 'c'},
|
||||
{L"data-size", no_argument, NULL, 'd'},
|
||||
{L"file-size", no_argument, NULL, 'f'},
|
||||
{L"lock-size", no_argument, NULL, 'l'},
|
||||
{L"resident-set-size", no_argument, NULL, 'm'},
|
||||
{L"file-descriptor-count", no_argument, NULL, 'n'},
|
||||
{L"stack-size", no_argument, NULL, 's'},
|
||||
{L"cpu-time", no_argument, NULL, 't'},
|
||||
{L"process-count", no_argument, NULL, 'u'},
|
||||
{L"virtual-memory-size", no_argument, NULL, 'v'},
|
||||
{L"help", no_argument, NULL, 'h'},
|
||||
{NULL, 0, NULL, 0}};
|
||||
|
||||
int opt;
|
||||
wgetopter_t w;
|
||||
while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 0: {
|
||||
if (long_options[opt_index].flag != 0) break;
|
||||
streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0],
|
||||
long_options[opt_index].name);
|
||||
builtin_print_help(parser, streams, argv[0], streams.err);
|
||||
return 1;
|
||||
}
|
||||
case L'a': {
|
||||
report_all = 1;
|
||||
case 'a': {
|
||||
report_all = true;
|
||||
break;
|
||||
}
|
||||
case L'H': {
|
||||
hard = 1;
|
||||
case 'H': {
|
||||
hard = true;
|
||||
break;
|
||||
}
|
||||
case L'S': {
|
||||
soft = 1;
|
||||
case 'S': {
|
||||
soft = true;
|
||||
break;
|
||||
}
|
||||
case L'c': {
|
||||
case 'c': {
|
||||
what = RLIMIT_CORE;
|
||||
break;
|
||||
}
|
||||
case L'd': {
|
||||
case 'd': {
|
||||
what = RLIMIT_DATA;
|
||||
break;
|
||||
}
|
||||
case L'f': {
|
||||
case 'f': {
|
||||
what = RLIMIT_FSIZE;
|
||||
break;
|
||||
}
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
case L'l': {
|
||||
case 'l': {
|
||||
what = RLIMIT_MEMLOCK;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef RLIMIT_RSS
|
||||
case L'm': {
|
||||
case 'm': {
|
||||
what = RLIMIT_RSS;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case L'n': {
|
||||
case 'n': {
|
||||
what = RLIMIT_NOFILE;
|
||||
break;
|
||||
}
|
||||
case L's': {
|
||||
case 's': {
|
||||
what = RLIMIT_STACK;
|
||||
break;
|
||||
}
|
||||
case L't': {
|
||||
case 't': {
|
||||
what = RLIMIT_CPU;
|
||||
break;
|
||||
}
|
||||
#ifdef RLIMIT_NPROC
|
||||
case L'u': {
|
||||
case 'u': {
|
||||
what = RLIMIT_NPROC;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef RLIMIT_AS
|
||||
case L'v': {
|
||||
case 'v': {
|
||||
what = RLIMIT_AS;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case L'h': {
|
||||
builtin_print_help(parser, streams, argv[0], streams.out);
|
||||
case 'h': {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
return 0;
|
||||
}
|
||||
case L'?': {
|
||||
builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
return 1;
|
||||
case ':': {
|
||||
streams.err.append_format(BUILTIN_ERR_MISSING, cmd, argv[w.woptind - 1]);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
case '?': {
|
||||
builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected retval from wgetopt_long");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (report_all) {
|
||||
if (argc - w.woptind == 0) {
|
||||
print_all(hard, streams);
|
||||
} else {
|
||||
streams.err.append(argv[0]);
|
||||
streams.err.append(L": Too many arguments\n");
|
||||
builtin_print_help(parser, streams, argv[0], streams.err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
print_all(hard, streams);
|
||||
return STATUS_BUILTIN_OK;
|
||||
}
|
||||
|
||||
switch (argc - w.woptind) {
|
||||
case 0: { // show current limit value
|
||||
print(what, hard, streams);
|
||||
break;
|
||||
}
|
||||
case 1: { // change current limit value
|
||||
rlim_t new_limit;
|
||||
wchar_t *end;
|
||||
|
||||
// Set both hard and soft limits if nothing else was specified.
|
||||
if (!(hard + soft)) {
|
||||
hard = soft = 1;
|
||||
}
|
||||
|
||||
if (wcscasecmp(argv[w.woptind], L"unlimited") == 0) {
|
||||
new_limit = RLIM_INFINITY;
|
||||
} else if (wcscasecmp(argv[w.woptind], L"hard") == 0) {
|
||||
new_limit = get(what, 1);
|
||||
} else if (wcscasecmp(argv[w.woptind], L"soft") == 0) {
|
||||
new_limit = get(what, soft);
|
||||
} else {
|
||||
errno = 0;
|
||||
new_limit = wcstol(argv[w.woptind], &end, 10);
|
||||
if (errno || *end) {
|
||||
streams.err.append_format(L"%ls: Invalid limit '%ls'\n", argv[0],
|
||||
argv[w.woptind]);
|
||||
builtin_print_help(parser, streams, argv[0], streams.err);
|
||||
return 1;
|
||||
}
|
||||
new_limit *= get_multiplier(what);
|
||||
}
|
||||
|
||||
return set(what, hard, soft, new_limit, streams);
|
||||
}
|
||||
default: {
|
||||
streams.err.append(argv[0]);
|
||||
streams.err.append(L": Too many arguments\n");
|
||||
builtin_print_help(parser, streams, argv[0], streams.err);
|
||||
return 1;
|
||||
}
|
||||
int arg_count = argc - w.woptind;
|
||||
if (arg_count == 0) {
|
||||
// Show current limit value.
|
||||
print(what, hard, streams);
|
||||
return STATUS_BUILTIN_OK;
|
||||
} else if (arg_count != 1) {
|
||||
streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
|
||||
builtin_print_help(parser, streams, cmd, streams.err);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
return 0;
|
||||
|
||||
// Change current limit value.
|
||||
if (!hard && !soft) {
|
||||
// Set both hard and soft limits if neither was specified.
|
||||
hard = soft = true;
|
||||
}
|
||||
|
||||
rlim_t new_limit;
|
||||
if (*argv[w.woptind] == L'\0') {
|
||||
streams.err.append_format(_(L"%ls: New limit cannot be an empty string\n"), cmd);
|
||||
builtin_print_help(parser, streams, cmd, streams.err);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
} else if (wcscasecmp(argv[w.woptind], L"unlimited") == 0) {
|
||||
new_limit = RLIM_INFINITY;
|
||||
} else if (wcscasecmp(argv[w.woptind], L"hard") == 0) {
|
||||
new_limit = get(what, 1);
|
||||
} else if (wcscasecmp(argv[w.woptind], L"soft") == 0) {
|
||||
new_limit = get(what, soft);
|
||||
} else {
|
||||
new_limit = fish_wcstol(argv[w.woptind]);
|
||||
if (errno) {
|
||||
streams.err.append_format(_(L"%ls: Invalid limit '%ls'\n"), cmd, argv[w.woptind]);
|
||||
builtin_print_help(parser, streams, cmd, streams.err);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
new_limit *= get_multiplier(what);
|
||||
}
|
||||
|
||||
return set_limit(what, hard, soft, new_limit, streams);
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ class rgb_color_t {
|
||||
color24_t to_color24() const;
|
||||
|
||||
/// Returns whether the color is bold.
|
||||
bool is_bold() const { return !!(flags & flag_bold); }
|
||||
bool is_bold() const { return static_cast<bool>(flags & flag_bold); }
|
||||
|
||||
/// Set whether the color is bold.
|
||||
void set_bold(bool x) {
|
||||
@@ -107,7 +107,7 @@ class rgb_color_t {
|
||||
}
|
||||
|
||||
/// Returns whether the color is underlined.
|
||||
bool is_underline() const { return !!(flags & flag_underline); }
|
||||
bool is_underline() const { return static_cast<bool>(flags & flag_underline); }
|
||||
|
||||
/// Set whether the color is underlined.
|
||||
void set_underline(bool x) {
|
||||
|
||||
105
src/common.cpp
105
src/common.cpp
@@ -43,7 +43,7 @@ struct termios shell_modes;
|
||||
|
||||
// Note we foolishly assume that pthread_t is just a primitive. But it might be a struct.
|
||||
static pthread_t main_thread_id = 0;
|
||||
static bool thread_assertions_configured_for_testing = false;
|
||||
static bool thread_asserts_cfg_for_testing = false;
|
||||
|
||||
wchar_t ellipsis_char;
|
||||
wchar_t omitted_newline_char;
|
||||
@@ -56,7 +56,7 @@ int debug_stack_frames = 0; // default number of stack frames to show on debug(
|
||||
static pid_t initial_pid = 0;
|
||||
|
||||
/// Be able to restore the term's foreground process group.
|
||||
static pid_t initial_foreground_process_group = -1;
|
||||
static pid_t initial_fg_process_group = -1;
|
||||
|
||||
/// This struct maintains the current state of the terminal size. It is updated on demand after
|
||||
/// receiving a SIGWINCH. Do not touch this struct directly, it's managed with a rwlock. Use
|
||||
@@ -107,6 +107,7 @@ demangled_backtrace(int max_frames, int skip_levels) {
|
||||
void __attribute__((noinline))
|
||||
show_stackframe(const wchar_t msg_level, int frame_count, int skip_levels) {
|
||||
ASSERT_IS_NOT_FORKED_CHILD();
|
||||
if (frame_count < 1) return;
|
||||
|
||||
// TODO: Decide if this is still needed. I'm commenting it out because it caused me some grief
|
||||
// while trying to debug a test failure. And the tests run just fine without spurious failures
|
||||
@@ -115,7 +116,6 @@ show_stackframe(const wchar_t msg_level, int frame_count, int skip_levels) {
|
||||
// Hack to avoid showing backtraces in the tester.
|
||||
// if (program_name && !wcscmp(program_name, L"(ignore)")) return;
|
||||
|
||||
if (frame_count < 1) frame_count = 999;
|
||||
debug_shared(msg_level, L"Backtrace:");
|
||||
std::vector<wcstring> bt = demangled_backtrace(frame_count, skip_levels + 2);
|
||||
for (int i = 0; (size_t)i < bt.size(); i++) {
|
||||
@@ -196,15 +196,14 @@ static wcstring str2wcs_internal(const char *in, const size_t in_len) {
|
||||
// Protect against broken mbrtowc() implementations which attempt to encode UTF-8
|
||||
// sequences longer than four bytes (e.g., OS X Snow Leopard).
|
||||
use_encode_direct = true;
|
||||
} else if (sizeof(wchar_t) == 2 && (in[in_pos] & 0xF8) == 0xF0) {
|
||||
} else if (sizeof(wchar_t) == 2 && //!OCLINT(constant if expression)
|
||||
(in[in_pos] & 0xF8) == 0xF0) {
|
||||
// Assume we are in a UTF-16 environment (e.g., Cygwin) using a UTF-8 encoding.
|
||||
// The bits set check will be true for a four byte UTF-8 sequence that requires
|
||||
// two UTF-16 chars. Something that doesn't work with our simple use of mbrtowc().
|
||||
use_encode_direct = true;
|
||||
} else {
|
||||
ret = mbrtowc(&wc, &in[in_pos], in_len - in_pos, &state);
|
||||
// fprintf(stderr, "WTF in_pos %d ret %d\n", in_pos, ret);
|
||||
|
||||
// Determine whether to encode this character with our crazy scheme.
|
||||
if (wc >= ENCODE_DIRECT_BASE && wc < ENCODE_DIRECT_BASE + 256) {
|
||||
use_encode_direct = true;
|
||||
@@ -219,7 +218,8 @@ static wcstring str2wcs_internal(const char *in, const size_t in_len) {
|
||||
} else if (ret > in_len - in_pos) {
|
||||
// Other error codes? Terrifying, should never happen.
|
||||
use_encode_direct = true;
|
||||
} else if (sizeof(wchar_t) == 2 && wc >= 0xD800 && wc <= 0xDFFF) {
|
||||
} else if (sizeof(wchar_t) == 2 && wc >= 0xD800 && //!OCLINT(constant if expression)
|
||||
wc <= 0xDFFF) {
|
||||
// If we get a surrogate pair char on a UTF-16 system (e.g., Cygwin) then
|
||||
// it's guaranteed the UTF-8 decoding is wrong so use direct encoding.
|
||||
use_encode_direct = true;
|
||||
@@ -227,24 +227,20 @@ static wcstring str2wcs_internal(const char *in, const size_t in_len) {
|
||||
}
|
||||
|
||||
if (use_encode_direct) {
|
||||
// fprintf(stderr, "WTF use_encode_direct\n");
|
||||
wc = ENCODE_DIRECT_BASE + (unsigned char)in[in_pos];
|
||||
result.push_back(wc);
|
||||
in_pos++;
|
||||
memset(&state, 0, sizeof state);
|
||||
} else if (ret == 0) {
|
||||
// fprintf(stderr, "WTF null byte\n");
|
||||
// Embedded null byte!
|
||||
} else if (ret == 0) { // embedded null byte!
|
||||
result.push_back(L'\0');
|
||||
in_pos++;
|
||||
memset(&state, 0, sizeof state);
|
||||
} else {
|
||||
// fprintf(stderr, "WTF null byte\n");
|
||||
// Normal case.
|
||||
} else { // normal case
|
||||
result.push_back(wc);
|
||||
in_pos += ret;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -286,16 +282,15 @@ std::string wcs2string(const wcstring &input) {
|
||||
result.reserve(input.size());
|
||||
|
||||
mbstate_t state = {};
|
||||
char converted[MB_LEN_MAX + 1];
|
||||
char converted[MB_LEN_MAX];
|
||||
|
||||
for (size_t i = 0; i < input.size(); i++) {
|
||||
wchar_t wc = input[i];
|
||||
if (wc == INTERNAL_SEPARATOR) {
|
||||
// Do nothing.
|
||||
; // do nothing
|
||||
} else if (wc >= ENCODE_DIRECT_BASE && wc < ENCODE_DIRECT_BASE + 256) {
|
||||
result.push_back(wc - ENCODE_DIRECT_BASE);
|
||||
} else if (MB_CUR_MAX == 1) // single-byte locale (C/POSIX/ISO-8859)
|
||||
{
|
||||
} else if (MB_CUR_MAX == 1) { // single-byte locale (C/POSIX/ISO-8859)
|
||||
// If `wc` contains a wide character we emit a question-mark.
|
||||
if (wc & ~0xFF) {
|
||||
wc = '?';
|
||||
@@ -305,8 +300,8 @@ std::string wcs2string(const wcstring &input) {
|
||||
} else {
|
||||
memset(converted, 0, sizeof converted);
|
||||
size_t len = wcrtomb(converted, wc, &state);
|
||||
if (len == (size_t)(-1)) {
|
||||
debug(1, L"Wide character %d has no narrow representation", wc);
|
||||
if (len == (size_t)-1) {
|
||||
debug(1, L"Wide character U+%4X has no narrow representation", wc);
|
||||
memset(&state, 0, sizeof(state));
|
||||
} else {
|
||||
result.append(converted, len);
|
||||
@@ -332,7 +327,7 @@ static char *wcs2str_internal(const wchar_t *in, char *out) {
|
||||
|
||||
while (in[in_pos]) {
|
||||
if (in[in_pos] == INTERNAL_SEPARATOR) {
|
||||
// Do nothing.
|
||||
; // do nothing
|
||||
} else if (in[in_pos] >= ENCODE_DIRECT_BASE && in[in_pos] < ENCODE_DIRECT_BASE + 256) {
|
||||
out[out_pos++] = in[in_pos] - ENCODE_DIRECT_BASE;
|
||||
} else if (MB_CUR_MAX == 1) // single-byte locale (C/POSIX/ISO-8859)
|
||||
@@ -346,7 +341,7 @@ static char *wcs2str_internal(const wchar_t *in, char *out) {
|
||||
} else {
|
||||
size_t len = wcrtomb(&out[out_pos], in[in_pos], &state);
|
||||
if (len == (size_t)-1) {
|
||||
debug(1, L"Wide character %d has no narrow representation", in[in_pos]);
|
||||
debug(1, L"Wide character U+%4X has no narrow representation", in[in_pos]);
|
||||
memset(&state, 0, sizeof(state));
|
||||
} else {
|
||||
out_pos += len;
|
||||
@@ -359,6 +354,14 @@ static char *wcs2str_internal(const wchar_t *in, char *out) {
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Test if the character can be encoded using the current locale.
|
||||
static bool can_be_encoded(wchar_t wc) {
|
||||
char converted[MB_LEN_MAX];
|
||||
mbstate_t state = {};
|
||||
|
||||
return wcrtomb(converted, wc, &state) != (size_t)-1;
|
||||
}
|
||||
|
||||
wcstring format_string(const wchar_t *format, ...) {
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
@@ -449,11 +452,11 @@ wchar_t *quote_end(const wchar_t *pos) {
|
||||
}
|
||||
|
||||
void fish_setlocale() {
|
||||
// Use ellipsis if on known unicode system, otherwise use $.
|
||||
ellipsis_char = (fish_wcwidth(L'\x2026') > 0) ? L'\x2026' : L'$';
|
||||
// Use the Unicode "ellipsis" symbol if it can be encoded using the current locale.
|
||||
ellipsis_char = can_be_encoded(L'\x2026') ? L'\x2026' : L'$';
|
||||
|
||||
// U+23CE is the "return" character
|
||||
omitted_newline_char = (fish_wcwidth(L'\x23CE') > 0) ? L'\x23CE' : L'~';
|
||||
// Use the Unicode "return" symbol if it can be encoded using the current locale.
|
||||
omitted_newline_char = can_be_encoded(L'\x23CE') ? L'\x23CE' : L'~';
|
||||
}
|
||||
|
||||
bool contains_internal(const wchar_t *a, int vararg_handle, ...) {
|
||||
@@ -768,9 +771,9 @@ static void escape_string_internal(const wchar_t *orig_in, size_t in_len, wcstri
|
||||
assert(orig_in != NULL);
|
||||
|
||||
const wchar_t *in = orig_in;
|
||||
bool escape_all = !!(flags & ESCAPE_ALL);
|
||||
bool no_quoted = !!(flags & ESCAPE_NO_QUOTED);
|
||||
bool no_tilde = !!(flags & ESCAPE_NO_TILDE);
|
||||
bool escape_all = static_cast<bool>(flags & ESCAPE_ALL);
|
||||
bool no_quoted = static_cast<bool>(flags & ESCAPE_NO_QUOTED);
|
||||
bool no_tilde = static_cast<bool>(flags & ESCAPE_NO_TILDE);
|
||||
|
||||
int need_escape = 0;
|
||||
int need_complex_escape = 0;
|
||||
@@ -1117,8 +1120,8 @@ static bool unescape_string_internal(const wchar_t *const input, const size_t in
|
||||
wcstring result;
|
||||
result.reserve(input_len);
|
||||
|
||||
const bool unescape_special = !!(flags & UNESCAPE_SPECIAL);
|
||||
const bool allow_incomplete = !!(flags & UNESCAPE_INCOMPLETE);
|
||||
const bool unescape_special = static_cast<bool>(flags & UNESCAPE_SPECIAL);
|
||||
const bool allow_incomplete = static_cast<bool>(flags & UNESCAPE_INCOMPLETE);
|
||||
|
||||
int bracket_count = 0;
|
||||
|
||||
@@ -1220,6 +1223,7 @@ static bool unescape_string_internal(const wchar_t *const input, const size_t in
|
||||
to_append_or_none = unescape_special ? INTERNAL_SEPARATOR : NOT_A_WCHAR;
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
}
|
||||
} else if (mode == mode_single_quotes) {
|
||||
if (c == L'\\') {
|
||||
@@ -1297,6 +1301,7 @@ static bool unescape_string_internal(const wchar_t *const input, const size_t in
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1505,7 +1510,7 @@ bool list_contains_string(const wcstring_list_t &list, const wcstring &str) {
|
||||
}
|
||||
|
||||
int create_directory(const wcstring &d) {
|
||||
int ok = 0;
|
||||
bool ok = false;
|
||||
struct stat buf;
|
||||
int stat_res = 0;
|
||||
|
||||
@@ -1514,18 +1519,10 @@ int create_directory(const wcstring &d) {
|
||||
}
|
||||
|
||||
if (stat_res == 0) {
|
||||
if (S_ISDIR(buf.st_mode)) {
|
||||
ok = 1;
|
||||
}
|
||||
} else {
|
||||
if (errno == ENOENT) {
|
||||
wcstring dir = wdirname(d);
|
||||
if (!create_directory(dir)) {
|
||||
if (!wmkdir(d, 0700)) {
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (S_ISDIR(buf.st_mode)) ok = true;
|
||||
} else if (errno == ENOENT) {
|
||||
wcstring dir = wdirname(d);
|
||||
if (!create_directory(dir) && !wmkdir(d, 0700)) ok = true;
|
||||
}
|
||||
|
||||
return ok ? 0 : -1;
|
||||
@@ -1682,9 +1679,7 @@ __attribute__((noinline)) void debug_thread_error(void) {
|
||||
|
||||
void set_main_thread() { main_thread_id = pthread_self(); }
|
||||
|
||||
void configure_thread_assertions_for_testing(void) {
|
||||
thread_assertions_configured_for_testing = true;
|
||||
}
|
||||
void configure_thread_assertions_for_testing(void) { thread_asserts_cfg_for_testing = true; }
|
||||
|
||||
bool is_forked_child(void) {
|
||||
// Just bail if nobody's called setup_fork_guards, e.g. some of our tools.
|
||||
@@ -1704,14 +1699,14 @@ void setup_fork_guards(void) {
|
||||
}
|
||||
|
||||
void save_term_foreground_process_group(void) {
|
||||
initial_foreground_process_group = tcgetpgrp(STDIN_FILENO);
|
||||
initial_fg_process_group = tcgetpgrp(STDIN_FILENO);
|
||||
}
|
||||
|
||||
void restore_term_foreground_process_group(void) {
|
||||
if (initial_foreground_process_group != -1) {
|
||||
if (initial_fg_process_group != -1) {
|
||||
// This is called during shutdown and from a signal handler. We don't bother to complain on
|
||||
// failure.
|
||||
tcsetpgrp(STDIN_FILENO, initial_foreground_process_group);
|
||||
tcsetpgrp(STDIN_FILENO, initial_fg_process_group);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1721,7 +1716,7 @@ bool is_main_thread() {
|
||||
}
|
||||
|
||||
void assert_is_main_thread(const char *who) {
|
||||
if (!is_main_thread() && !thread_assertions_configured_for_testing) {
|
||||
if (!is_main_thread() && !thread_asserts_cfg_for_testing) {
|
||||
fprintf(stderr,
|
||||
"Warning: %s called off of main thread. Break on debug_thread_error to debug.\n",
|
||||
who);
|
||||
@@ -1739,7 +1734,7 @@ void assert_is_not_forked_child(const char *who) {
|
||||
}
|
||||
|
||||
void assert_is_background_thread(const char *who) {
|
||||
if (is_main_thread() && !thread_assertions_configured_for_testing) {
|
||||
if (is_main_thread() && !thread_asserts_cfg_for_testing) {
|
||||
fprintf(stderr,
|
||||
"Warning: %s called on the main thread (may block!). Break on debug_thread_error "
|
||||
"to debug.\n",
|
||||
@@ -1761,7 +1756,7 @@ void assert_is_locked(void *vmutex, const char *who, const char *caller) {
|
||||
}
|
||||
|
||||
void scoped_lock::lock(void) {
|
||||
assert(!locked);
|
||||
assert(!locked); //!OCLINT(multiple unary operator)
|
||||
ASSERT_IS_NOT_FORKED_CHILD();
|
||||
VOMIT_ON_FAILURE_NO_ERRNO(pthread_mutex_lock(lock_obj));
|
||||
locked = true;
|
||||
@@ -1785,7 +1780,7 @@ scoped_lock::~scoped_lock() {
|
||||
}
|
||||
|
||||
void scoped_rwlock::lock(void) {
|
||||
assert(!(locked || locked_shared));
|
||||
assert(!(locked || locked_shared)); //!OCLINT(multiple unary operator)
|
||||
ASSERT_IS_NOT_FORKED_CHILD();
|
||||
VOMIT_ON_FAILURE_NO_ERRNO(pthread_rwlock_rdlock(rwlock_obj));
|
||||
locked = true;
|
||||
@@ -1799,7 +1794,7 @@ void scoped_rwlock::unlock(void) {
|
||||
}
|
||||
|
||||
void scoped_rwlock::lock_shared(void) {
|
||||
assert(!(locked || locked_shared));
|
||||
assert(!(locked || locked_shared)); //!OCLINT(multiple unary operator)
|
||||
ASSERT_IS_NOT_FORKED_CHILD();
|
||||
VOMIT_ON_FAILURE_NO_ERRNO(pthread_rwlock_wrlock(rwlock_obj));
|
||||
locked_shared = true;
|
||||
|
||||
52
src/common.h
52
src/common.h
@@ -211,6 +211,9 @@ extern bool has_working_tty_timestamps;
|
||||
}
|
||||
|
||||
/// Pause for input, then exit the program. If supported, print a backtrace first.
|
||||
// The `return` will never be run but silences oclint warnings. Especially when this is called
|
||||
// from within a `switch` block. As of the time I'm writing this oclint doesn't recognize the
|
||||
// `__attribute__((noreturn))` on the exit_without_destructors() function.
|
||||
#define FATAL_EXIT() \
|
||||
{ \
|
||||
char exit_read_buff; \
|
||||
@@ -258,7 +261,7 @@ extern bool has_working_tty_timestamps;
|
||||
#define contains(str, ...) contains_internal(str, 0, __VA_ARGS__, NULL)
|
||||
|
||||
/// Print a stack trace to stderr.
|
||||
void show_stackframe(const wchar_t msg_level, int frame_count = -1, int skip_levels = 0);
|
||||
void show_stackframe(const wchar_t msg_level, int frame_count = 100, int skip_levels = 0);
|
||||
|
||||
/// Read a line from the stream f into the string. Returns the number of bytes read or -1 on
|
||||
/// failure.
|
||||
@@ -775,7 +778,50 @@ long convert_digit(wchar_t d, int base);
|
||||
(void)(expr); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
// Return true if the character is in a range reserved for fish's private use.
|
||||
bool fish_reserved_codepoint(wchar_t c);
|
||||
|
||||
/// Used for constructing mappings between enums and strings. The resulting array must be sorted
|
||||
/// according to the `str` member since str_to_enum() does a binary search. Also the last entry must
|
||||
/// have NULL for the `str` member and the default value for `val` to be returned if the string
|
||||
/// isn't found.
|
||||
template <typename T>
|
||||
struct enum_map {
|
||||
T val;
|
||||
const wchar_t *const str;
|
||||
};
|
||||
|
||||
/// Given a string return the matching enum. Return the sentinal enum if no match is made. The map
|
||||
/// must be sorted by the `str` member. A binary search is twice as fast as a linear search with 16
|
||||
/// elements in the map.
|
||||
template <typename T>
|
||||
static T str_to_enum(const wchar_t *name, const enum_map<T> map[], int len) {
|
||||
// Ignore the sentinel value when searching as it is the "not found" value.
|
||||
size_t left = 0, right = len - 1;
|
||||
|
||||
while (left < right) {
|
||||
size_t mid = left + (right - left) / 2;
|
||||
int cmp = wcscmp(name, map[mid].str);
|
||||
if (cmp < 0) {
|
||||
right = mid; // name was smaller than mid
|
||||
} else if (cmp > 0) {
|
||||
left = mid + 1; // name was larger than mid
|
||||
} else {
|
||||
return map[mid].val; // found it
|
||||
}
|
||||
}
|
||||
return map[len - 1].val; // return the sentinel value
|
||||
}
|
||||
|
||||
/// Given an enum return the matching string.
|
||||
template <typename T>
|
||||
static const wchar_t *enum_to_str(T enum_val, const enum_map<T> map[]) {
|
||||
for (const enum_map<T> *entry = map; entry->str; entry++) {
|
||||
if (enum_val == entry->val) {
|
||||
return entry->str;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
286
src/complete.cpp
286
src/complete.cpp
@@ -119,7 +119,7 @@ typedef struct complete_entry_opt {
|
||||
case option_type_double_long:
|
||||
return 2;
|
||||
}
|
||||
assert(0 && "Unreachable");
|
||||
DIE("unreachable");
|
||||
}
|
||||
|
||||
} complete_entry_opt_t;
|
||||
@@ -289,9 +289,11 @@ class completer_t {
|
||||
return flags & COMPLETION_REQUEST_AUTOSUGGESTION ? COMPLETE_AUTOSUGGEST : COMPLETE_DEFAULT;
|
||||
}
|
||||
|
||||
bool wants_descriptions() const { return !!(flags & COMPLETION_REQUEST_DESCRIPTIONS); }
|
||||
bool wants_descriptions() const {
|
||||
return static_cast<bool>(flags & COMPLETION_REQUEST_DESCRIPTIONS);
|
||||
}
|
||||
|
||||
bool fuzzy() const { return !!(flags & COMPLETION_REQUEST_FUZZY_MATCH); }
|
||||
bool fuzzy() const { return static_cast<bool>(flags & COMPLETION_REQUEST_FUZZY_MATCH); }
|
||||
|
||||
fuzzy_match_type_t max_fuzzy_match_type() const {
|
||||
// If we are doing fuzzy matching, request all types; if not request only prefix matching.
|
||||
@@ -668,22 +670,22 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
|
||||
std::vector<completion_t> possible_comp;
|
||||
|
||||
if (use_command) {
|
||||
if (expand_string(str_cmd, &this->completions,
|
||||
EXPAND_SPECIAL_FOR_COMMAND | EXPAND_FOR_COMPLETIONS | EXECUTABLES_ONLY |
|
||||
this->expand_flags(),
|
||||
NULL) != EXPAND_ERROR) {
|
||||
if (this->wants_descriptions()) {
|
||||
this->complete_cmd_desc(str_cmd);
|
||||
expand_error_t result = expand_string(str_cmd, &this->completions,
|
||||
EXPAND_SPECIAL_FOR_COMMAND | EXPAND_FOR_COMPLETIONS |
|
||||
EXECUTABLES_ONLY | this->expand_flags(),
|
||||
NULL);
|
||||
if (result != EXPAND_ERROR && this->wants_descriptions()) {
|
||||
this->complete_cmd_desc(str_cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (use_implicit_cd) {
|
||||
if (!expand_string(str_cmd, &this->completions,
|
||||
EXPAND_FOR_COMPLETIONS | DIRECTORIES_ONLY | this->expand_flags(),
|
||||
NULL)) {
|
||||
// Not valid as implicit cd.
|
||||
}
|
||||
// We don't really care if this succeeds or fails. If it succeeds this->completions will be
|
||||
// updated with choices for the user.
|
||||
(void)expand_string(str_cmd, &this->completions,
|
||||
EXPAND_FOR_COMPLETIONS | DIRECTORIES_ONLY | this->expand_flags(), NULL);
|
||||
}
|
||||
|
||||
if (str_cmd.find(L'/') == wcstring::npos && str_cmd.at(0) != L'~') {
|
||||
if (use_function) {
|
||||
wcstring_list_t names = function_get_names(str_cmd.at(0) == L'_');
|
||||
@@ -875,11 +877,10 @@ bool completer_t::complete_param(const wcstring &scmd_orig, const wcstring &spop
|
||||
if (this->type() == COMPLETE_DEFAULT) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
complete_load(cmd, true);
|
||||
} else if (this->type() == COMPLETE_AUTOSUGGEST) {
|
||||
// Maybe load this command (on the main thread).
|
||||
if (!completion_autoloader.has_tried_loading(cmd)) {
|
||||
iothread_perform_on_main(complete_load_no_reload, &cmd);
|
||||
}
|
||||
} else if (this->type() == COMPLETE_AUTOSUGGEST &&
|
||||
!completion_autoloader.has_tried_loading(cmd)) {
|
||||
// Load this command (on the main thread).
|
||||
iothread_perform_on_main(complete_load_no_reload, &cmd);
|
||||
}
|
||||
|
||||
// Make a list of lists of all options that we care about.
|
||||
@@ -925,13 +926,12 @@ bool completer_t::complete_param(const wcstring &scmd_orig, const wcstring &spop
|
||||
for (option_list_t::const_iterator oiter = options.begin(); oiter != options.end();
|
||||
++oiter) {
|
||||
const complete_entry_opt_t *o = &*oiter;
|
||||
if (o->type == option_type_single_long) {
|
||||
if (param_match(o, popt) && this->condition_test(o->condition)) {
|
||||
old_style_match = true;
|
||||
if (o->result_mode & NO_COMMON) use_common = false;
|
||||
if (o->result_mode & NO_FILES) use_files = false;
|
||||
complete_from_args(str, o->comp, o->localized_desc(), o->flags);
|
||||
}
|
||||
if (o->type == option_type_single_long && param_match(o, popt) &&
|
||||
this->condition_test(o->condition)) {
|
||||
old_style_match = true;
|
||||
if (o->result_mode & NO_COMMON) use_common = false;
|
||||
if (o->result_mode & NO_FILES) use_files = false;
|
||||
complete_from_args(str, o->comp, o->localized_desc(), o->flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -956,71 +956,73 @@ bool completer_t::complete_param(const wcstring &scmd_orig, const wcstring &spop
|
||||
}
|
||||
}
|
||||
|
||||
if (use_common) {
|
||||
for (option_list_t::const_iterator oiter = options.begin(); oiter != options.end();
|
||||
++oiter) {
|
||||
const complete_entry_opt_t *o = &*oiter;
|
||||
// If this entry is for the base command, check if any of the arguments match.
|
||||
if (!this->condition_test(o->condition)) continue;
|
||||
if (o->option.empty()) {
|
||||
use_files = use_files && ((o->result_mode & NO_FILES) == 0);
|
||||
complete_from_args(str, o->comp, o->localized_desc(), o->flags);
|
||||
}
|
||||
if (!use_common) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wcslen(str) > 0 && use_switches) {
|
||||
// Check if the short style option matches.
|
||||
if (short_ok(str, o, options)) {
|
||||
// It's a match.
|
||||
const wcstring desc = o->localized_desc();
|
||||
append_completion(&this->completions, o->option, desc, 0);
|
||||
}
|
||||
|
||||
// Check if the long style option matches.
|
||||
if (o->type == option_type_single_long || o->type == option_type_double_long) {
|
||||
int match = 0, match_no_case = 0;
|
||||
|
||||
wcstring whole_opt(o->expected_dash_count(), L'-');
|
||||
whole_opt.append(o->option);
|
||||
|
||||
match = string_prefixes_string(str, whole_opt);
|
||||
|
||||
if (!match) {
|
||||
match_no_case = wcsncasecmp(str, whole_opt.c_str(), wcslen(str)) == 0;
|
||||
}
|
||||
|
||||
if (match || match_no_case) {
|
||||
int has_arg = 0; // does this switch have any known arguments
|
||||
int req_arg = 0; // does this switch _require_ an argument
|
||||
|
||||
size_t offset = 0;
|
||||
complete_flags_t flags = 0;
|
||||
|
||||
if (match) {
|
||||
offset = wcslen(str);
|
||||
} else {
|
||||
flags = COMPLETE_REPLACES_TOKEN;
|
||||
}
|
||||
|
||||
has_arg = !o->comp.empty();
|
||||
req_arg = (o->result_mode & NO_COMMON);
|
||||
|
||||
if (o->type == option_type_double_long && (has_arg && !req_arg)) {
|
||||
// Optional arguments to a switch can only be handled using the '=',
|
||||
// so we add it as a completion. By default we avoid using '=' and
|
||||
// instead rely on '--switch switch-arg', since it is more commonly
|
||||
// supported by homebrew getopt-like functions.
|
||||
wcstring completion =
|
||||
format_string(L"%ls=", whole_opt.c_str() + offset);
|
||||
append_completion(&this->completions, completion, C_(o->desc),
|
||||
flags);
|
||||
}
|
||||
|
||||
append_completion(&this->completions, whole_opt.c_str() + offset,
|
||||
C_(o->desc), flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (option_list_t::const_iterator oiter = options.begin(); oiter != options.end();
|
||||
++oiter) {
|
||||
const complete_entry_opt_t *o = &*oiter;
|
||||
// If this entry is for the base command, check if any of the arguments match.
|
||||
if (!this->condition_test(o->condition)) continue;
|
||||
if (o->option.empty()) {
|
||||
use_files = use_files && ((o->result_mode & NO_FILES) == 0);
|
||||
complete_from_args(str, o->comp, o->localized_desc(), o->flags);
|
||||
}
|
||||
|
||||
if (wcslen(str) == 0 || !use_switches) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the short style option matches.
|
||||
if (short_ok(str, o, options)) {
|
||||
// It's a match.
|
||||
const wcstring desc = o->localized_desc();
|
||||
append_completion(&this->completions, o->option, desc, 0);
|
||||
}
|
||||
|
||||
// Check if the long style option matches.
|
||||
if (o->type != option_type_single_long && o->type != option_type_double_long) {
|
||||
continue;
|
||||
}
|
||||
int match = 0, match_no_case = 0;
|
||||
|
||||
wcstring whole_opt(o->expected_dash_count(), L'-');
|
||||
whole_opt.append(o->option);
|
||||
|
||||
match = string_prefixes_string(str, whole_opt);
|
||||
if (!match) {
|
||||
match_no_case = wcsncasecmp(str, whole_opt.c_str(), wcslen(str)) == 0;
|
||||
}
|
||||
|
||||
if (!match && !match_no_case) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int has_arg = 0; // does this switch have any known arguments
|
||||
int req_arg = 0; // does this switch _require_ an argument
|
||||
size_t offset = 0;
|
||||
complete_flags_t flags = 0;
|
||||
|
||||
if (match) {
|
||||
offset = wcslen(str);
|
||||
} else {
|
||||
flags = COMPLETE_REPLACES_TOKEN;
|
||||
}
|
||||
|
||||
has_arg = !o->comp.empty();
|
||||
req_arg = (o->result_mode & NO_COMMON);
|
||||
|
||||
if (o->type == option_type_double_long && (has_arg && !req_arg)) {
|
||||
// Optional arguments to a switch can only be handled using the '=', so we add it as
|
||||
// a completion. By default we avoid using '=' and instead rely on '--switch
|
||||
// switch-arg', since it is more commonly supported by homebrew getopt-like
|
||||
// functions.
|
||||
wcstring completion = format_string(L"%ls=", whole_opt.c_str() + offset);
|
||||
append_completion(&this->completions, completion, C_(o->desc), flags);
|
||||
}
|
||||
|
||||
append_completion(&this->completions, whole_opt.c_str() + offset, C_(o->desc), flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1144,31 +1146,35 @@ bool completer_t::try_complete_variable(const wcstring &str) {
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case L'\\':
|
||||
case L'\\': {
|
||||
in_pos++;
|
||||
break;
|
||||
|
||||
case L'$':
|
||||
}
|
||||
case L'$': {
|
||||
if (mode == e_unquoted || mode == e_double_quoted) {
|
||||
variable_start = in_pos;
|
||||
}
|
||||
break;
|
||||
|
||||
case L'\'':
|
||||
}
|
||||
case L'\'': {
|
||||
if (mode == e_single_quoted) {
|
||||
mode = e_unquoted;
|
||||
} else if (mode == e_unquoted) {
|
||||
mode = e_single_quoted;
|
||||
}
|
||||
break;
|
||||
|
||||
case L'"':
|
||||
}
|
||||
case L'"': {
|
||||
if (mode == e_double_quoted) {
|
||||
mode = e_unquoted;
|
||||
} else if (mode == e_unquoted) {
|
||||
mode = e_double_quoted;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break; // all other chars ignored here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1196,50 +1202,52 @@ bool completer_t::try_complete_user(const wcstring &str) {
|
||||
#else
|
||||
const wchar_t *cmd = str.c_str();
|
||||
const wchar_t *first_char = cmd;
|
||||
int res = 0;
|
||||
double start_time = timef();
|
||||
|
||||
if (*first_char == L'~' && !wcschr(first_char, L'/')) {
|
||||
const wchar_t *user_name = first_char + 1;
|
||||
const wchar_t *name_end = wcschr(user_name, L'~');
|
||||
if (name_end == 0) {
|
||||
struct passwd *pw;
|
||||
size_t name_len = wcslen(user_name);
|
||||
|
||||
setpwent();
|
||||
|
||||
while ((pw = getpwent()) != 0) {
|
||||
double current_time = timef();
|
||||
|
||||
if (current_time - start_time > 0.2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pw->pw_name) {
|
||||
const wcstring pw_name_str = str2wcstring(pw->pw_name);
|
||||
const wchar_t *pw_name = pw_name_str.c_str();
|
||||
if (wcsncmp(user_name, pw_name, name_len) == 0) {
|
||||
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
|
||||
append_completion(&this->completions, &pw_name[name_len], desc,
|
||||
COMPLETE_NO_SPACE);
|
||||
|
||||
res = 1;
|
||||
} else if (wcsncasecmp(user_name, pw_name, name_len) == 0) {
|
||||
wcstring name = format_string(L"~%ls", pw_name);
|
||||
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
|
||||
|
||||
append_completion(&this->completions, name, desc, COMPLETE_REPLACES_TOKEN |
|
||||
COMPLETE_DONT_ESCAPE |
|
||||
COMPLETE_NO_SPACE);
|
||||
res = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
endpwent();
|
||||
}
|
||||
if (*first_char != L'~' || wcschr(first_char, L'/')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return res;
|
||||
const wchar_t *user_name = first_char + 1;
|
||||
const wchar_t *name_end = wcschr(user_name, L'~');
|
||||
if (name_end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double start_time = timef();
|
||||
bool result = false;
|
||||
struct passwd *pw;
|
||||
size_t name_len = wcslen(user_name);
|
||||
|
||||
setpwent();
|
||||
while ((pw = getpwent()) != 0) {
|
||||
double current_time = timef();
|
||||
if (current_time - start_time > 0.2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!pw->pw_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const wcstring pw_name_str = str2wcstring(pw->pw_name);
|
||||
const wchar_t *pw_name = pw_name_str.c_str();
|
||||
if (wcsncmp(user_name, pw_name, name_len) == 0) {
|
||||
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
|
||||
append_completion(&this->completions, &pw_name[name_len], desc, COMPLETE_NO_SPACE);
|
||||
|
||||
result = true;
|
||||
} else if (wcsncasecmp(user_name, pw_name, name_len) == 0) {
|
||||
wcstring name = format_string(L"~%ls", pw_name);
|
||||
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
|
||||
|
||||
append_completion(&this->completions, name, desc, COMPLETE_REPLACES_TOKEN |
|
||||
COMPLETE_DONT_ESCAPE |
|
||||
COMPLETE_NO_SPACE);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
endpwent();
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1534,7 +1542,7 @@ wcstring complete_print() {
|
||||
break;
|
||||
}
|
||||
case option_type_short: {
|
||||
assert(!o->option.empty());
|
||||
assert(!o->option.empty()); //!OCLINT(multiple unary operator)
|
||||
append_format(out, L" --short-option '%lc'", o->option.at(0));
|
||||
break;
|
||||
}
|
||||
|
||||
60
src/env.cpp
60
src/env.cpp
@@ -8,15 +8,12 @@
|
||||
#include <pwd.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE__NL_MSG_CAT_CNTR
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <set>
|
||||
@@ -283,10 +280,6 @@ static void universal_callback(fish_message_type_t type, const wchar_t *name) {
|
||||
str = L"ERASE";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(0 && "Unhandled fish_message_type_t constant!");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (str) {
|
||||
@@ -418,10 +411,10 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
|
||||
const env_var_t shlvl_str = env_get_string(L"SHLVL");
|
||||
wcstring nshlvl_str = L"1";
|
||||
if (!shlvl_str.missing()) {
|
||||
wchar_t *end;
|
||||
long shlvl_i = wcstol(shlvl_str.c_str(), &end, 10);
|
||||
while (iswspace(*end)) ++end; // skip trailing whitespace
|
||||
if (shlvl_i >= 0 && *end == '\0') {
|
||||
const wchar_t *end;
|
||||
// TODO: Figure out how to handle invalid numbers better. Shouldn't we issue a diagnostic?
|
||||
long shlvl_i = fish_wcstol(shlvl_str.c_str(), &end);
|
||||
if (!errno && shlvl_i >= 0) {
|
||||
nshlvl_str = to_string<long>(shlvl_i + 1);
|
||||
}
|
||||
}
|
||||
@@ -476,6 +469,25 @@ static env_node_t *env_get_node(const wcstring &key) {
|
||||
return env;
|
||||
}
|
||||
|
||||
/// Set the value of the environment variable whose name matches key to val.
|
||||
///
|
||||
/// Memory policy: All keys and values are copied, the parameters can and should be freed by the
|
||||
/// caller afterwards
|
||||
///
|
||||
/// \param key The key
|
||||
/// \param val The value
|
||||
/// \param var_mode The type of the variable. Can be any combination of ENV_GLOBAL, ENV_LOCAL,
|
||||
/// ENV_EXPORT and ENV_USER. If mode is zero, the current variable space is searched and the current
|
||||
/// mode is used. If no current variable with the same name is found, ENV_LOCAL is assumed.
|
||||
///
|
||||
/// Returns:
|
||||
///
|
||||
/// * ENV_OK on success.
|
||||
/// * ENV_PERM, can only be returned when setting as a user, e.g. ENV_USER is set. This means that
|
||||
/// the user tried to change a read-only variable.
|
||||
/// * ENV_SCOPE, the variable cannot be set in the given scope. This applies to readonly/electric
|
||||
/// variables set from the local or universal scopes, or set as exported.
|
||||
/// * ENV_INVALID, the variable value was invalid. This applies only to special variables.
|
||||
int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
bool has_changed_old = has_changed_exported;
|
||||
@@ -501,18 +513,14 @@ int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode)
|
||||
}
|
||||
|
||||
if (key == L"umask") {
|
||||
wchar_t *end;
|
||||
|
||||
// Set the new umask.
|
||||
if (val && wcslen(val)) {
|
||||
errno = 0;
|
||||
long mask = wcstol(val, &end, 8);
|
||||
|
||||
if (!errno && (!*end) && (mask <= 0777) && (mask >= 0)) {
|
||||
long mask = fish_wcstol(val, NULL, 8);
|
||||
if (!errno && mask <= 0777 && mask >= 0) {
|
||||
umask(mask);
|
||||
// Do not actually create a umask variable, on env_get, it will be calculated
|
||||
// dynamically.
|
||||
return 0;
|
||||
return ENV_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -521,7 +529,7 @@ int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode)
|
||||
|
||||
// Zero element arrays are internaly not coded as null but as this placeholder string.
|
||||
if (!val) {
|
||||
val = ENV_NULL;
|
||||
val = ENV_NULL; //!OCLINT(parameter reassignment)
|
||||
}
|
||||
|
||||
if (var_mode & ENV_UNIVERSAL) {
|
||||
@@ -566,10 +574,10 @@ int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode)
|
||||
node = top;
|
||||
} else if (preexisting_node != NULL) {
|
||||
node = preexisting_node;
|
||||
|
||||
if ((var_mode & (ENV_EXPORT | ENV_UNEXPORT)) == 0) {
|
||||
// use existing entry's exportv
|
||||
var_mode = preexisting_entry_exportv ? ENV_EXPORT : 0;
|
||||
var_mode = //!OCLINT(parameter reassignment)
|
||||
preexisting_entry_exportv ? ENV_EXPORT : 0;
|
||||
}
|
||||
} else {
|
||||
if (!get_proc_had_barrier()) {
|
||||
@@ -635,7 +643,7 @@ int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode)
|
||||
// debug( 1, L"env_set: return from event firing" );
|
||||
|
||||
react_to_variable_change(key);
|
||||
return 0;
|
||||
return ENV_OK;
|
||||
}
|
||||
|
||||
/// Attempt to remove/free the specified key/value pair from the specified map.
|
||||
@@ -713,7 +721,7 @@ int env_remove(const wcstring &key, int var_mode) {
|
||||
}
|
||||
|
||||
const wchar_t *env_var_t::c_str(void) const {
|
||||
assert(!is_missing);
|
||||
assert(!is_missing); //!OCLINT(multiple unary operator)
|
||||
return wcstring::c_str();
|
||||
}
|
||||
|
||||
@@ -864,9 +872,7 @@ void env_push(bool new_scope) {
|
||||
node->next = top;
|
||||
node->new_scope = new_scope;
|
||||
|
||||
if (new_scope) {
|
||||
if (local_scope_exports(top)) mark_changed_exported();
|
||||
}
|
||||
if (new_scope && local_scope_exports(top)) mark_changed_exported();
|
||||
top = node;
|
||||
}
|
||||
|
||||
@@ -884,7 +890,7 @@ void env_pop() {
|
||||
}
|
||||
}
|
||||
|
||||
if (killme->new_scope) {
|
||||
if (killme->new_scope) { //!OCLINT(collapsible if statements)
|
||||
if (killme->exportv || local_scope_exports(killme->next)) mark_changed_exported();
|
||||
}
|
||||
|
||||
|
||||
24
src/env.h
24
src/env.h
@@ -36,8 +36,8 @@ enum {
|
||||
};
|
||||
typedef uint32_t env_mode_flags_t;
|
||||
|
||||
/// Error code for trying to alter read-only variable.
|
||||
enum { ENV_PERM = 1, ENV_SCOPE, ENV_INVALID };
|
||||
/// Return values for `env_set()`.
|
||||
enum { ENV_OK, ENV_PERM, ENV_SCOPE, ENV_INVALID };
|
||||
|
||||
/// A struct of configuration directories, determined in main() that fish will optionally pass to
|
||||
/// env_init.
|
||||
@@ -51,26 +51,6 @@ struct config_paths_t {
|
||||
/// Initialize environment variable data.
|
||||
void env_init(const struct config_paths_t *paths = NULL);
|
||||
|
||||
/// Set the value of the environment variable whose name matches key to val.
|
||||
///
|
||||
/// Memory policy: All keys and values are copied, the parameters can and should be freed by the
|
||||
/// caller afterwards
|
||||
///
|
||||
/// \param key The key
|
||||
/// \param val The value
|
||||
/// \param mode The type of the variable. Can be any combination of ENV_GLOBAL, ENV_LOCAL,
|
||||
/// ENV_EXPORT and ENV_USER. If mode is zero, the current variable space is searched and the current
|
||||
/// mode is used. If no current variable with the same name is found, ENV_LOCAL is assumed.
|
||||
///
|
||||
/// \returns 0 on success or an error code on failiure.
|
||||
///
|
||||
/// The current error codes are:
|
||||
///
|
||||
/// * ENV_PERM, can only be returned when setting as a user, e.g. ENV_USER is set. This means that
|
||||
/// the user tried to change a read-only variable.
|
||||
/// * ENV_SCOPE, the variable cannot be set in the given scope. This applies to readonly/electric
|
||||
/// variables set from the local or universal scopes, or set as exported.
|
||||
/// * ENV_INVALID, the variable value was invalid. This applies only to special variables.
|
||||
int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t mode);
|
||||
|
||||
class env_var_t : public wcstring {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include <string>
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
@@ -231,7 +230,7 @@ static bool append_file_entry(fish_message_type_t type, const wcstring &key_in,
|
||||
result->push_back(' ');
|
||||
|
||||
// Append variable name like "fish_color_cwd".
|
||||
if (wcsvarname(key_in.c_str())) {
|
||||
if (wcsvarname(key_in)) {
|
||||
debug(0, L"Illegal variable name: '%ls'", key_in.c_str());
|
||||
success = false;
|
||||
}
|
||||
@@ -930,23 +929,24 @@ static bool get_mac_address(unsigned char macaddr[MAC_ADDRESS_MAX_LEN],
|
||||
struct ifaddrs *ifap;
|
||||
bool ok = false;
|
||||
|
||||
if (getifaddrs(&ifap) == 0) {
|
||||
for (const ifaddrs *p = ifap; p; p = p->ifa_next) {
|
||||
if (p->ifa_addr && p->ifa_addr->sa_family == AF_LINK) {
|
||||
if (p->ifa_name && p->ifa_name[0] &&
|
||||
!strcmp((const char *)p->ifa_name, interface)) {
|
||||
const sockaddr_dl &sdl = *reinterpret_cast<sockaddr_dl *>(p->ifa_addr);
|
||||
|
||||
size_t alen = sdl.sdl_alen;
|
||||
if (alen > MAC_ADDRESS_MAX_LEN) alen = MAC_ADDRESS_MAX_LEN;
|
||||
memcpy(macaddr, sdl.sdl_data + sdl.sdl_nlen, alen);
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
if (getifaddrs(&ifap) != 0) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
for (const ifaddrs *p = ifap; p; p = p->ifa_next) {
|
||||
bool is_af_link = p->ifa_addr && p->ifa_addr->sa_family == AF_LINK;
|
||||
if (is_af_link && p->ifa_name && p->ifa_name[0] &&
|
||||
!strcmp((const char *)p->ifa_name, interface)) {
|
||||
const sockaddr_dl &sdl = *reinterpret_cast<sockaddr_dl *>(p->ifa_addr);
|
||||
|
||||
size_t alen = sdl.sdl_alen;
|
||||
if (alen > MAC_ADDRESS_MAX_LEN) alen = MAC_ADDRESS_MAX_LEN;
|
||||
memcpy(macaddr, sdl.sdl_data + sdl.sdl_nlen, alen);
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -978,11 +978,8 @@ wcstring get_machine_identifier() {
|
||||
for (size_t i = 0; i < MAC_ADDRESS_MAX_LEN; i++) {
|
||||
append_format(result, L"%02x", mac_addr[i]);
|
||||
}
|
||||
} else if (get_hostname_identifier(&result)) {
|
||||
// Hooray
|
||||
} else {
|
||||
// Fallback
|
||||
result.assign(L"nohost");
|
||||
} else if (!get_hostname_identifier(&result)) {
|
||||
result.assign(L"nohost"); // fallback to a dummy value
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1033,12 +1030,11 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t {
|
||||
}
|
||||
|
||||
// Set the size, if it's too small.
|
||||
if (!errored && size < (off_t)sizeof(universal_notifier_shmem_t)) {
|
||||
if (ftruncate(fd, sizeof(universal_notifier_shmem_t)) < 0) {
|
||||
int err = errno;
|
||||
report_error(err, L"Unable to truncate shared memory object with path '%s'", path);
|
||||
errored = true;
|
||||
}
|
||||
bool set_size = !errored && size < (off_t)sizeof(universal_notifier_shmem_t);
|
||||
if (set_size && ftruncate(fd, sizeof(universal_notifier_shmem_t)) < 0) {
|
||||
int err = errno;
|
||||
report_error(err, L"Unable to truncate shared memory object with path '%s'", path);
|
||||
errored = true;
|
||||
}
|
||||
|
||||
// Memory map the region.
|
||||
@@ -1074,7 +1070,7 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t {
|
||||
void post_notification() {
|
||||
if (region != NULL) {
|
||||
/* Read off the seed */
|
||||
uint32_t seed = ntohl(region->universal_variable_seed);
|
||||
uint32_t seed = ntohl(region->universal_variable_seed); //!OCLINT(constant cond op)
|
||||
|
||||
// Increment it. Don't let it wrap to zero.
|
||||
do {
|
||||
@@ -1083,9 +1079,9 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t {
|
||||
last_seed = seed;
|
||||
|
||||
// Write out our data.
|
||||
region->magic = htonl(SHMEM_MAGIC_NUMBER);
|
||||
region->version = htonl(SHMEM_VERSION_CURRENT);
|
||||
region->universal_variable_seed = htonl(seed);
|
||||
region->magic = htonl(SHMEM_MAGIC_NUMBER); //!OCLINT(constant cond op)
|
||||
region->version = htonl(SHMEM_VERSION_CURRENT); //!OCLINT(constant cond op)
|
||||
region->universal_variable_seed = htonl(seed); //!OCLINT(constant cond op)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1106,7 +1102,7 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t {
|
||||
bool poll() {
|
||||
bool result = false;
|
||||
if (region != NULL) {
|
||||
uint32_t seed = ntohl(region->universal_variable_seed);
|
||||
uint32_t seed = ntohl(region->universal_variable_seed); //!OCLINT(constant cond op)
|
||||
if (seed != last_seed) {
|
||||
result = true;
|
||||
last_seed = seed;
|
||||
@@ -1237,10 +1233,12 @@ class universal_notifier_named_pipe_t : public universal_notifier_t {
|
||||
int fd = wopen_cloexec(vars_path, O_RDWR | O_NONBLOCK, 0600);
|
||||
if (fd < 0 && errno == ENOENT) {
|
||||
// File doesn't exist, try creating it.
|
||||
if (mkfifo(narrow_path.c_str(), 0600) >= 0) {
|
||||
int mkfifo_status = mkfifo(narrow_path.c_str(), 0600);
|
||||
if (mkfifo_status != -1) {
|
||||
fd = wopen_cloexec(vars_path, O_RDWR | O_NONBLOCK, 0600);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
// Maybe open failed, maybe mkfifo failed.
|
||||
int err = errno;
|
||||
@@ -1314,13 +1312,11 @@ class universal_notifier_named_pipe_t : public universal_notifier_t {
|
||||
if (pipe_fd >= 0) {
|
||||
// We need to write some data (any data) to the pipe, then wait for a while, then read
|
||||
// it back. Nobody is expected to read it except us.
|
||||
int pid_nbo = htonl(getpid());
|
||||
int pid_nbo = htonl(getpid()); //!OCLINT(constant cond op)
|
||||
ssize_t amt_written = write(this->pipe_fd, &pid_nbo, sizeof pid_nbo);
|
||||
if (amt_written < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
// Very unsual: the pipe is full!
|
||||
drain_excessive_data();
|
||||
}
|
||||
if (amt_written < 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) {
|
||||
// Very unsual: the pipe is full!
|
||||
drain_excessive_data();
|
||||
}
|
||||
|
||||
// Now schedule a read for some time in the future.
|
||||
@@ -1358,8 +1354,6 @@ class universal_notifier_named_pipe_t : public universal_notifier_t {
|
||||
}
|
||||
|
||||
bool poll() {
|
||||
bool result = false;
|
||||
|
||||
// Check if we are past the readback time.
|
||||
if (this->readback_time_usec > 0 && get_time() >= this->readback_time_usec) {
|
||||
// Read back what we wrote. We do nothing with the value.
|
||||
@@ -1374,30 +1368,29 @@ class universal_notifier_named_pipe_t : public universal_notifier_t {
|
||||
}
|
||||
|
||||
// Check to see if we are doing readability polling.
|
||||
if (polling_due_to_readable_fd && pipe_fd >= 0) {
|
||||
// We are polling, so we are definitely going to sync.
|
||||
result = true;
|
||||
|
||||
// See if this is still readable.
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(this->pipe_fd, &fds);
|
||||
struct timeval timeout = {};
|
||||
select(this->pipe_fd + 1, &fds, NULL, NULL, &timeout);
|
||||
if (!FD_ISSET(this->pipe_fd, &fds)) {
|
||||
// No longer readable, no longer polling.
|
||||
polling_due_to_readable_fd = false;
|
||||
drain_if_still_readable_time_usec = 0;
|
||||
} else {
|
||||
// Still readable. If it's been readable for a long time, there is probably
|
||||
// lingering data on the pipe.
|
||||
if (get_time() >= drain_if_still_readable_time_usec) {
|
||||
drain_excessive_data();
|
||||
}
|
||||
}
|
||||
if (!polling_due_to_readable_fd || pipe_fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
// We are polling, so we are definitely going to sync.
|
||||
// See if this is still readable.
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(this->pipe_fd, &fds);
|
||||
struct timeval timeout = {};
|
||||
select(this->pipe_fd + 1, &fds, NULL, NULL, &timeout);
|
||||
if (!FD_ISSET(this->pipe_fd, &fds)) {
|
||||
// No longer readable, no longer polling.
|
||||
polling_due_to_readable_fd = false;
|
||||
drain_if_still_readable_time_usec = 0;
|
||||
} else {
|
||||
// Still readable. If it's been readable for a long time, there is probably
|
||||
// lingering data on the pipe.
|
||||
if (get_time() >= drain_if_still_readable_time_usec) {
|
||||
drain_excessive_data();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1416,23 +1409,25 @@ static universal_notifier_t::notifier_strategy_t fetch_default_strategy_from_env
|
||||
const size_t opt_count = sizeof options / sizeof *options;
|
||||
|
||||
const char *var = getenv(UNIVERSAL_NOTIFIER_ENV_NAME);
|
||||
if (var != NULL && var[0] != '\0') {
|
||||
size_t i;
|
||||
for (i = 0; i < opt_count; i++) {
|
||||
if (!strcmp(var, options[i].name)) {
|
||||
result = options[i].strat;
|
||||
break;
|
||||
}
|
||||
if (var == NULL || var[0] == '\0') {
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < opt_count; i++) {
|
||||
if (!strcmp(var, options[i].name)) {
|
||||
result = options[i].strat;
|
||||
break;
|
||||
}
|
||||
if (i >= opt_count) {
|
||||
fprintf(stderr, "Warning: unrecognized value for %s: '%s'\n",
|
||||
UNIVERSAL_NOTIFIER_ENV_NAME, var);
|
||||
fprintf(stderr, "Warning: valid values are ");
|
||||
for (size_t j = 0; j < opt_count; j++) {
|
||||
fprintf(stderr, "%s%s", j > 0 ? ", " : "", options[j].name);
|
||||
}
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
if (i >= opt_count) {
|
||||
fprintf(stderr, "Warning: unrecognized value for %s: '%s'\n",
|
||||
UNIVERSAL_NOTIFIER_ENV_NAME, var);
|
||||
fprintf(stderr, "Warning: valid values are ");
|
||||
for (size_t j = 0; j < opt_count; j++) {
|
||||
fprintf(stderr, "%s%s", j > 0 ? ", " : "", options[j].name);
|
||||
}
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1460,7 +1455,7 @@ universal_notifier_t &universal_notifier_t::default_notifier() {
|
||||
universal_notifier_t *universal_notifier_t::new_notifier_for_strategy(
|
||||
universal_notifier_t::notifier_strategy_t strat, const wchar_t *test_path) {
|
||||
if (strat == strategy_default) {
|
||||
strat = resolve_default_strategy();
|
||||
strat = resolve_default_strategy(); //!OCLINT(parameter reassignment)
|
||||
}
|
||||
switch (strat) {
|
||||
case strategy_shmem_polling: {
|
||||
|
||||
@@ -88,6 +88,10 @@ static int event_match(const event_t &classv, const event_t &instance) {
|
||||
case EVENT_GENERIC: {
|
||||
return instance.str_param1 == classv.str_param1;
|
||||
}
|
||||
default: {
|
||||
DIE("unexpected classv.type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// This should never be reached.
|
||||
@@ -226,7 +230,10 @@ static wcstring event_desc_compact(const event_t &event) {
|
||||
res = format_string(L"EVENT_GENERIC(%ls)", event.str_param1.c_str());
|
||||
break;
|
||||
}
|
||||
default: { res = format_string(L"unknown/illegal event(%x)", event.type); }
|
||||
default: {
|
||||
res = format_string(L"unknown/illegal event(%x)", event.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (event.function_name.size()) {
|
||||
return format_string(L"%ls: \"%ls\"", res.c_str(), event.function_name.c_str());
|
||||
|
||||
150
src/exec.cpp
150
src/exec.cpp
@@ -9,16 +9,13 @@
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <wchar.h>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#ifdef HAVE_SPAWN_H
|
||||
#include <spawn.h>
|
||||
#endif
|
||||
#include <wctype.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -282,11 +279,6 @@ static bool io_transmogrify(const io_chain_t &in_chain, io_chain_t *out_chain,
|
||||
out.reset(new io_fd_t(in->fd, fd, false));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Unknown type, should never happen.
|
||||
assert(0 && "Unhandled io_mode constant");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (out.get() != NULL) result_chain.push_back(out);
|
||||
@@ -353,7 +345,7 @@ static void internal_exec_helper(parser_t &parser, const wcstring &def, node_off
|
||||
// foreground process group, we don't use posix_spawn if we're going to foreground the process. (If
|
||||
// we use fork(), we can call tcsetpgrp after the fork, before the exec, and avoid the race).
|
||||
static bool can_use_posix_spawn_for_job(const job_t *job, const process_t *process) {
|
||||
if (job_get_flag(job, JOB_CONTROL)) {
|
||||
if (job_get_flag(job, JOB_CONTROL)) { //!OCLINT(collapsible if statements)
|
||||
// We are going to use job control; therefore when we launch this job it will get its own
|
||||
// process group ID. But will it be foregrounded?
|
||||
if (job_get_flag(job, JOB_TERMINAL) && job_get_flag(job, JOB_FOREGROUND)) {
|
||||
@@ -406,7 +398,7 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||
|
||||
if ((io->io_mode == IO_BUFFER)) {
|
||||
io_buffer_t *io_buffer = static_cast<io_buffer_t *>(io.get());
|
||||
assert(!io_buffer->is_input);
|
||||
assert(!io_buffer->is_input); //!OCLINT(multiple unary operator)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,10 +418,8 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||
const env_var_t shlvl_str = env_get_string(L"SHLVL", ENV_GLOBAL | ENV_EXPORT);
|
||||
wcstring nshlvl_str = L"0";
|
||||
if (!shlvl_str.missing()) {
|
||||
wchar_t *end;
|
||||
long shlvl_i = wcstol(shlvl_str.c_str(), &end, 10);
|
||||
while (iswspace(*end)) ++end; // skip trailing whitespace
|
||||
if (shlvl_i > 0 && *end == '\0') {
|
||||
long shlvl_i = fish_wcstol(shlvl_str.c_str());
|
||||
if (!errno && shlvl_i > 0) {
|
||||
nshlvl_str = to_string<long>(shlvl_i - 1);
|
||||
}
|
||||
}
|
||||
@@ -442,7 +432,7 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||
j->first_process->completed = 1;
|
||||
return;
|
||||
}
|
||||
assert(0 && "This should be unreachable");
|
||||
DIE("this should be unreachable");
|
||||
}
|
||||
|
||||
// We may have block IOs that conflict with fd redirections. For example, we may have a command
|
||||
@@ -827,9 +817,7 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||
|
||||
case INTERNAL_EXEC:
|
||||
// We should have handled exec up above.
|
||||
assert(
|
||||
0 &&
|
||||
"INTERNAL_EXEC process found in pipeline, where it should never be. Aborting.");
|
||||
DIE("INTERNAL_EXEC process found in pipeline, where it should never be. Aborting.");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -913,45 +901,42 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||
// output, so that we can truncate the file. Does not apply to /dev/null.
|
||||
bool must_fork = redirection_is_to_real_file(stdout_io.get()) ||
|
||||
redirection_is_to_real_file(stderr_io.get());
|
||||
if (!must_fork) {
|
||||
if (p->next == NULL) {
|
||||
const bool stdout_is_to_buffer =
|
||||
stdout_io && stdout_io->io_mode == IO_BUFFER;
|
||||
const bool no_stdout_output = stdout_buffer.empty();
|
||||
const bool no_stderr_output = stderr_buffer.empty();
|
||||
if (!must_fork && p->next == NULL) {
|
||||
const bool stdout_is_to_buffer = stdout_io && stdout_io->io_mode == IO_BUFFER;
|
||||
const bool no_stdout_output = stdout_buffer.empty();
|
||||
const bool no_stderr_output = stderr_buffer.empty();
|
||||
|
||||
if (no_stdout_output && no_stderr_output) {
|
||||
// The builtin produced no output and is not inside of a pipeline. No
|
||||
// need to fork or even output anything.
|
||||
debug(3, L"Skipping fork: no output for internal builtin '%ls'",
|
||||
p->argv0());
|
||||
fork_was_skipped = true;
|
||||
} else if (no_stderr_output && stdout_is_to_buffer) {
|
||||
// The builtin produced no stderr, and its stdout is going to an
|
||||
// internal buffer. There is no need to fork. This helps out the
|
||||
// performance quite a bit in complex completion code.
|
||||
debug(3, L"Skipping fork: buffered output for internal builtin '%ls'",
|
||||
p->argv0());
|
||||
if (no_stdout_output && no_stderr_output) {
|
||||
// The builtin produced no output and is not inside of a pipeline. No
|
||||
// need to fork or even output anything.
|
||||
debug(3, L"Skipping fork: no output for internal builtin '%ls'",
|
||||
p->argv0());
|
||||
fork_was_skipped = true;
|
||||
} else if (no_stderr_output && stdout_is_to_buffer) {
|
||||
// The builtin produced no stderr, and its stdout is going to an
|
||||
// internal buffer. There is no need to fork. This helps out the
|
||||
// performance quite a bit in complex completion code.
|
||||
debug(3, L"Skipping fork: buffered output for internal builtin '%ls'",
|
||||
p->argv0());
|
||||
|
||||
io_buffer_t *io_buffer = static_cast<io_buffer_t *>(stdout_io.get());
|
||||
const std::string res = wcs2string(builtin_io_streams->out.buffer());
|
||||
io_buffer_t *io_buffer = static_cast<io_buffer_t *>(stdout_io.get());
|
||||
const std::string res = wcs2string(builtin_io_streams->out.buffer());
|
||||
|
||||
io_buffer->out_buffer_append(res.data(), res.size());
|
||||
fork_was_skipped = true;
|
||||
} else if (stdout_io.get() == NULL && stderr_io.get() == NULL) {
|
||||
// We are writing to normal stdout and stderr. Just do it - no need to
|
||||
// fork.
|
||||
debug(3, L"Skipping fork: ordinary output for internal builtin '%ls'",
|
||||
p->argv0());
|
||||
const std::string outbuff = wcs2string(stdout_buffer);
|
||||
const std::string errbuff = wcs2string(stderr_buffer);
|
||||
bool builtin_io_done = do_builtin_io(outbuff.data(), outbuff.size(),
|
||||
errbuff.data(), errbuff.size());
|
||||
if (!builtin_io_done && errno != EPIPE) {
|
||||
show_stackframe(L'E');
|
||||
}
|
||||
fork_was_skipped = true;
|
||||
io_buffer->out_buffer_append(res.data(), res.size());
|
||||
fork_was_skipped = true;
|
||||
} else if (stdout_io.get() == NULL && stderr_io.get() == NULL) {
|
||||
// We are writing to normal stdout and stderr. Just do it - no need to
|
||||
// fork.
|
||||
debug(3, L"Skipping fork: ordinary output for internal builtin '%ls'",
|
||||
p->argv0());
|
||||
const std::string outbuff = wcs2string(stdout_buffer);
|
||||
const std::string errbuff = wcs2string(stderr_buffer);
|
||||
bool builtin_io_done = do_builtin_io(outbuff.data(), outbuff.size(),
|
||||
errbuff.data(), errbuff.size());
|
||||
if (!builtin_io_done && errno != EPIPE) {
|
||||
show_stackframe(L'E');
|
||||
}
|
||||
fork_was_skipped = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1074,7 +1059,7 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||
setup_child_process(j, p, process_net_io_chain);
|
||||
safe_launch_process(p, actual_cmd, argv, envv);
|
||||
// safe_launch_process _never_ returns...
|
||||
assert(0 && "safe_launch_process should not have returned");
|
||||
DIE("safe_launch_process should not have returned");
|
||||
} else {
|
||||
debug(2, L"Fork #%d, pid %d: external command '%s' from '%ls'\n",
|
||||
g_fork_count, pid, p->argv0(), file ? file : L"<no file>");
|
||||
@@ -1088,17 +1073,13 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||
// This is the parent process. Store away information on the child, and possibly
|
||||
// fice it control over the terminal.
|
||||
p->pid = pid;
|
||||
|
||||
set_child_group(j, p, 0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case INTERNAL_EXEC: {
|
||||
// We should have handled exec up above.
|
||||
assert(
|
||||
0 &&
|
||||
"INTERNAL_EXEC process found in pipeline, where it should never be. Aborting.");
|
||||
DIE("INTERNAL_EXEC process found in pipeline, where it should never be. Aborting.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1177,37 +1158,38 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst,
|
||||
// If the caller asked us to preserve the exit status, restore the old status. Otherwise set the
|
||||
// status of the subcommand.
|
||||
proc_set_last_status(apply_exit_status ? subcommand_status : prev_status);
|
||||
|
||||
is_subshell = prev_subshell;
|
||||
|
||||
if (lst != NULL && io_buffer.get() != NULL) {
|
||||
const char *begin = io_buffer->out_buffer_ptr();
|
||||
const char *end = begin + io_buffer->out_buffer_size();
|
||||
if (split_output) {
|
||||
const char *cursor = begin;
|
||||
while (cursor < end) {
|
||||
// Look for the next separator.
|
||||
const char *stop = (const char *)memchr(cursor, '\n', end - cursor);
|
||||
const bool hit_separator = (stop != NULL);
|
||||
if (!hit_separator) {
|
||||
// If it's not found, just use the end.
|
||||
stop = end;
|
||||
}
|
||||
// Stop now points at the first character we do not want to copy.
|
||||
const wcstring wc = str2wcstring(cursor, stop - cursor);
|
||||
lst->push_back(wc);
|
||||
if (lst == NULL || io_buffer.get() == NULL) {
|
||||
return subcommand_status;
|
||||
}
|
||||
|
||||
// If we hit a separator, skip over it; otherwise we're at the end.
|
||||
cursor = stop + (hit_separator ? 1 : 0);
|
||||
const char *begin = io_buffer->out_buffer_ptr();
|
||||
const char *end = begin + io_buffer->out_buffer_size();
|
||||
if (split_output) {
|
||||
const char *cursor = begin;
|
||||
while (cursor < end) {
|
||||
// Look for the next separator.
|
||||
const char *stop = (const char *)memchr(cursor, '\n', end - cursor);
|
||||
const bool hit_separator = (stop != NULL);
|
||||
if (!hit_separator) {
|
||||
// If it's not found, just use the end.
|
||||
stop = end;
|
||||
}
|
||||
} else {
|
||||
// we're not splitting output, but we still want to trim off a trailing newline.
|
||||
if (end != begin && end[-1] == '\n') {
|
||||
--end;
|
||||
}
|
||||
const wcstring wc = str2wcstring(begin, end - begin);
|
||||
// Stop now points at the first character we do not want to copy.
|
||||
const wcstring wc = str2wcstring(cursor, stop - cursor);
|
||||
lst->push_back(wc);
|
||||
|
||||
// If we hit a separator, skip over it; otherwise we're at the end.
|
||||
cursor = stop + (hit_separator ? 1 : 0);
|
||||
}
|
||||
} else {
|
||||
// We're not splitting output, but we still want to trim off a trailing newline.
|
||||
if (end != begin && end[-1] == '\n') {
|
||||
--end;
|
||||
}
|
||||
const wcstring wc = str2wcstring(begin, end - begin);
|
||||
lst->push_back(wc);
|
||||
}
|
||||
|
||||
return subcommand_status;
|
||||
|
||||
574
src/expand.cpp
574
src/expand.cpp
@@ -166,36 +166,31 @@ wcstring expand_escape_variable(const wcstring &in) {
|
||||
|
||||
tokenize_variable_array(in, lst);
|
||||
|
||||
switch (lst.size()) {
|
||||
case 0: {
|
||||
buff.append(L"''");
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
const wcstring &el = lst.at(0);
|
||||
size_t size = lst.size();
|
||||
if (size == 0) {
|
||||
buff.append(L"''");
|
||||
} else if (size == 1) {
|
||||
const wcstring &el = lst.at(0);
|
||||
|
||||
if (el.find(L' ') != wcstring::npos && is_quotable(el)) {
|
||||
if (el.find(L' ') != wcstring::npos && is_quotable(el)) {
|
||||
buff.append(L"'");
|
||||
buff.append(el);
|
||||
buff.append(L"'");
|
||||
} else {
|
||||
buff.append(escape_string(el, 1));
|
||||
}
|
||||
} else {
|
||||
for (size_t j = 0; j < lst.size(); j++) {
|
||||
const wcstring &el = lst.at(j);
|
||||
if (j) buff.append(L" ");
|
||||
|
||||
if (is_quotable(el)) {
|
||||
buff.append(L"'");
|
||||
buff.append(el);
|
||||
buff.append(L"'");
|
||||
} else {
|
||||
buff.append(escape_string(el, 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
for (size_t j = 0; j < lst.size(); j++) {
|
||||
const wcstring &el = lst.at(j);
|
||||
if (j) buff.append(L" ");
|
||||
|
||||
if (is_quotable(el)) {
|
||||
buff.append(L"'");
|
||||
buff.append(el);
|
||||
buff.append(L"'");
|
||||
} else {
|
||||
buff.append(escape_string(el, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return buff;
|
||||
@@ -225,10 +220,8 @@ static bool match_pid(const wcstring &cmd, const wchar_t *proc, size_t *offset)
|
||||
const wcstring base_cmd = wbasename(cmd);
|
||||
|
||||
bool result = string_prefixes_string(proc, base_cmd);
|
||||
if (result) {
|
||||
// It's a match. Return the offset within the full command.
|
||||
if (offset) *offset = cmd.size() - base_cmd.size();
|
||||
}
|
||||
// It's a match. Return the offset within the full command.
|
||||
if (result && offset) *offset = cmd.size() - base_cmd.size();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -400,7 +393,10 @@ bool process_iterator_t::next_process(wcstring *out_str, pid_t *out_pid) {
|
||||
if (buf.st_uid != getuid()) continue;
|
||||
|
||||
// Remember the pid.
|
||||
pid = fish_wcstoi(name.c_str(), NULL, 10);
|
||||
pid = fish_wcstoi(name.c_str());
|
||||
if (errno || pid < 0) {
|
||||
debug(1, _(L"Unexpected failure to convert pid '%ls' to integer\n"), name.c_str());
|
||||
}
|
||||
|
||||
// The 'cmdline' file exists, it should contain the commandline.
|
||||
FILE *cmdfile;
|
||||
@@ -442,7 +438,7 @@ struct find_job_data_t {
|
||||
|
||||
/// The following function is invoked on the main thread, because the job list is not thread safe.
|
||||
/// It should search the job list for something matching the given proc, and then return 1 to stop
|
||||
/// the search, 0 to continue it .
|
||||
/// the search, 0 to continue it.
|
||||
static int find_job(const struct find_job_data_t *info) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
|
||||
@@ -484,12 +480,8 @@ static int find_job(const struct find_job_data_t *info) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int jid;
|
||||
wchar_t *end;
|
||||
|
||||
errno = 0;
|
||||
jid = fish_wcstoi(proc, &end, 10);
|
||||
if (jid > 0 && !errno && !*end) {
|
||||
int jid = fish_wcstoi(proc);
|
||||
if (!errno && jid > 0) {
|
||||
j = job_get(jid);
|
||||
if ((j != 0) && (j->command_wcstr() != 0) && (!j->command_is_empty())) {
|
||||
append_completion(&completions, to_string<long>(j->pgid));
|
||||
@@ -501,42 +493,45 @@ static int find_job(const struct find_job_data_t *info) {
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
job_iterator_t jobs;
|
||||
while ((j = jobs.next())) {
|
||||
if (j->command_is_empty()) continue;
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
|
||||
size_t offset;
|
||||
if (match_pid(j->command(), proc, &offset)) {
|
||||
if (flags & EXPAND_FOR_COMPLETIONS) {
|
||||
append_completion(&completions, j->command_wcstr() + offset + wcslen(proc),
|
||||
COMPLETE_JOB_DESC, 0);
|
||||
} else {
|
||||
append_completion(&completions, to_string<long>(j->pgid));
|
||||
found = 1;
|
||||
}
|
||||
job_iterator_t jobs;
|
||||
while ((j = jobs.next())) {
|
||||
if (j->command_is_empty()) continue;
|
||||
|
||||
size_t offset;
|
||||
if (match_pid(j->command(), proc, &offset)) {
|
||||
if (flags & EXPAND_FOR_COMPLETIONS) {
|
||||
append_completion(&completions, j->command_wcstr() + offset + wcslen(proc),
|
||||
COMPLETE_JOB_DESC, 0);
|
||||
} else {
|
||||
append_completion(&completions, to_string<long>(j->pgid));
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
jobs.reset();
|
||||
while ((j = jobs.next())) {
|
||||
process_t *p;
|
||||
if (j->command_is_empty()) continue;
|
||||
for (p = j->first_process; p; p = p->next) {
|
||||
if (p->actual_cmd.empty()) continue;
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
|
||||
size_t offset;
|
||||
if (match_pid(p->actual_cmd, proc, &offset)) {
|
||||
if (flags & EXPAND_FOR_COMPLETIONS) {
|
||||
append_completion(&completions,
|
||||
wcstring(p->actual_cmd, offset + wcslen(proc)),
|
||||
COMPLETE_CHILD_PROCESS_DESC, 0);
|
||||
} else {
|
||||
append_completion(&completions, to_string<long>(p->pid), L"", 0);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
jobs.reset();
|
||||
while ((j = jobs.next())) {
|
||||
process_t *p;
|
||||
if (j->command_is_empty()) continue;
|
||||
for (p = j->first_process; p; p = p->next) {
|
||||
if (p->actual_cmd.empty()) continue;
|
||||
|
||||
size_t offset;
|
||||
if (match_pid(p->actual_cmd, proc, &offset)) {
|
||||
if (flags & EXPAND_FOR_COMPLETIONS) {
|
||||
append_completion(&completions, wcstring(p->actual_cmd, offset + wcslen(proc)),
|
||||
COMPLETE_CHILD_PROCESS_DESC, 0);
|
||||
} else {
|
||||
append_completion(&completions, to_string<long>(p->pid), L"", 0);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -632,13 +627,11 @@ static bool expand_pid(const wcstring &instr_with_sep, expand_flags_t flags,
|
||||
const size_t prev_count = out->size();
|
||||
find_process(in + 1, flags, out);
|
||||
|
||||
if (prev_count == out->size()) {
|
||||
if (!(flags & EXPAND_FOR_COMPLETIONS)) {
|
||||
// We failed to find anything.
|
||||
append_syntax_error(errors, 1, FAILED_EXPANSION_PROCESS_ERR_MSG,
|
||||
escape(in + 1, ESCAPE_NO_QUOTED).c_str());
|
||||
return false;
|
||||
}
|
||||
if (prev_count == out->size() && !(flags & EXPAND_FOR_COMPLETIONS)) {
|
||||
// We failed to find anything.
|
||||
append_syntax_error(errors, 1, FAILED_EXPANSION_PROCESS_ERR_MSG,
|
||||
escape(in + 1, ESCAPE_NO_QUOTED).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -649,25 +642,22 @@ static bool expand_pid(const wcstring &instr_with_sep, expand_flags_t flags,
|
||||
/// with [.
|
||||
static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector<long> &idx,
|
||||
std::vector<size_t> &source_positions, size_t array_size) {
|
||||
wchar_t *end;
|
||||
|
||||
const long size = (long)array_size;
|
||||
size_t pos = 1; // skip past the opening square bracket
|
||||
// debug( 0, L"parse_slice on '%ls'", in );
|
||||
|
||||
while (1) {
|
||||
long tmp;
|
||||
|
||||
while (iswspace(in[pos]) || (in[pos] == INTERNAL_SEPARATOR)) pos++;
|
||||
if (in[pos] == L']') {
|
||||
pos++;
|
||||
break;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
const size_t i1_src_pos = pos;
|
||||
tmp = wcstol(&in[pos], &end, 10);
|
||||
if ((errno) || (end == &in[pos])) {
|
||||
const wchar_t *end;
|
||||
long tmp = fish_wcstol(&in[pos], &end);
|
||||
// We don't test `*end` as is typically done because we expect it to not be the null char.
|
||||
// Ignore the case of errno==-1 because it means the end char wasn't the null char.
|
||||
if (errno > 0) {
|
||||
return pos;
|
||||
}
|
||||
// debug( 0, L"Push idx %d", tmp );
|
||||
@@ -680,8 +670,9 @@ static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector<long
|
||||
while (in[pos] == INTERNAL_SEPARATOR) pos++;
|
||||
|
||||
const size_t number_start = pos;
|
||||
long tmp1 = wcstol(&in[pos], &end, 10);
|
||||
if ((errno) || (end == &in[pos])) {
|
||||
long tmp1 = fish_wcstol(&in[pos], &end);
|
||||
// Ignore the case of errno==-1 because it means the end char wasn't the null char.
|
||||
if (errno > 0) {
|
||||
return pos;
|
||||
}
|
||||
pos = end - in;
|
||||
@@ -704,11 +695,8 @@ static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector<long
|
||||
}
|
||||
|
||||
if (end_ptr) {
|
||||
// debug( 0, L"Remainder is '%ls', slice def was %d characters long", in+pos, pos );
|
||||
|
||||
*end_ptr = (wchar_t *)(in + pos);
|
||||
}
|
||||
// debug( 0, L"ok, done" );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -755,193 +743,196 @@ static int expand_variables(const wcstring &instr, std::vector<completion_t> *ou
|
||||
|
||||
for (long i = last_idx - 1; (i >= 0) && is_ok && !empty; i--) {
|
||||
const wchar_t c = instr.at(i);
|
||||
if ((c == VARIABLE_EXPAND) || (c == VARIABLE_EXPAND_SINGLE)) {
|
||||
size_t start_pos = i + 1;
|
||||
size_t stop_pos;
|
||||
long var_len;
|
||||
int is_single = (c == VARIABLE_EXPAND_SINGLE);
|
||||
if (c != VARIABLE_EXPAND && c != VARIABLE_EXPAND_SINGLE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stop_pos = start_pos;
|
||||
while (stop_pos < insize) {
|
||||
const wchar_t nc = instr.at(stop_pos);
|
||||
if (nc == VARIABLE_EXPAND_EMPTY) {
|
||||
stop_pos++;
|
||||
break;
|
||||
}
|
||||
if (!wcsvarchr(nc)) break;
|
||||
long var_len;
|
||||
int is_single = (c == VARIABLE_EXPAND_SINGLE);
|
||||
size_t start_pos = i + 1;
|
||||
size_t stop_pos = start_pos;
|
||||
|
||||
while (stop_pos < insize) {
|
||||
const wchar_t nc = instr.at(stop_pos);
|
||||
if (nc == VARIABLE_EXPAND_EMPTY) {
|
||||
stop_pos++;
|
||||
}
|
||||
|
||||
// printf( "Stop for '%c'\n", in[stop_pos]);
|
||||
var_len = stop_pos - start_pos;
|
||||
|
||||
if (var_len == 0) {
|
||||
if (errors) {
|
||||
parse_util_expand_variable_error(instr, 0 /* global_token_pos */, i, errors);
|
||||
}
|
||||
|
||||
is_ok = false;
|
||||
break;
|
||||
}
|
||||
if (!wcsvarchr(nc)) break;
|
||||
|
||||
var_tmp.append(instr, start_pos, var_len);
|
||||
env_var_t var_val;
|
||||
if (var_len == 1 && var_tmp[0] == VARIABLE_EXPAND_EMPTY) {
|
||||
var_val = env_var_t::missing_var();
|
||||
} else {
|
||||
var_val = expand_var(var_tmp.c_str());
|
||||
stop_pos++;
|
||||
}
|
||||
|
||||
// printf( "Stop for '%c'\n", in[stop_pos]);
|
||||
var_len = stop_pos - start_pos;
|
||||
|
||||
if (var_len == 0) {
|
||||
if (errors) {
|
||||
parse_util_expand_variable_error(instr, 0 /* global_token_pos */, i, errors);
|
||||
}
|
||||
|
||||
if (!var_val.missing()) {
|
||||
int all_vars = 1;
|
||||
wcstring_list_t var_item_list;
|
||||
is_ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_ok) {
|
||||
tokenize_variable_array(var_val, var_item_list);
|
||||
var_tmp.append(instr, start_pos, var_len);
|
||||
env_var_t var_val;
|
||||
if (var_len == 1 && var_tmp[0] == VARIABLE_EXPAND_EMPTY) {
|
||||
var_val = env_var_t::missing_var();
|
||||
} else {
|
||||
var_val = expand_var(var_tmp.c_str());
|
||||
}
|
||||
|
||||
const size_t slice_start = stop_pos;
|
||||
if (slice_start < insize && instr.at(slice_start) == L'[') {
|
||||
wchar_t *slice_end;
|
||||
size_t bad_pos;
|
||||
all_vars = 0;
|
||||
const wchar_t *in = instr.c_str();
|
||||
bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_list,
|
||||
var_pos_list, var_item_list.size());
|
||||
if (bad_pos != 0) {
|
||||
append_syntax_error(errors, stop_pos + bad_pos, L"Invalid index value");
|
||||
if (!var_val.missing()) {
|
||||
int all_vars = 1;
|
||||
wcstring_list_t var_item_list;
|
||||
|
||||
if (is_ok) {
|
||||
tokenize_variable_array(var_val, var_item_list);
|
||||
|
||||
const size_t slice_start = stop_pos;
|
||||
if (slice_start < insize && instr.at(slice_start) == L'[') {
|
||||
wchar_t *slice_end;
|
||||
size_t bad_pos;
|
||||
all_vars = 0;
|
||||
const wchar_t *in = instr.c_str();
|
||||
bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_list, var_pos_list,
|
||||
var_item_list.size());
|
||||
if (bad_pos != 0) {
|
||||
append_syntax_error(errors, stop_pos + bad_pos, L"Invalid index value");
|
||||
is_ok = false;
|
||||
break;
|
||||
}
|
||||
stop_pos = (slice_end - in);
|
||||
}
|
||||
|
||||
if (!all_vars) {
|
||||
wcstring_list_t string_values(var_idx_list.size());
|
||||
for (size_t j = 0; j < var_idx_list.size(); j++) {
|
||||
long tmp = var_idx_list.at(j);
|
||||
// Check that we are within array bounds. If not, truncate the list to
|
||||
// exit.
|
||||
if (tmp < 1 || (size_t)tmp > var_item_list.size()) {
|
||||
size_t var_src_pos = var_pos_list.at(j);
|
||||
// The slice was parsed starting at stop_pos, so we have to add that
|
||||
// to the error position.
|
||||
append_syntax_error(errors, slice_start + var_src_pos,
|
||||
ARRAY_BOUNDS_ERR);
|
||||
is_ok = false;
|
||||
var_idx_list.resize(j);
|
||||
break;
|
||||
} else {
|
||||
// Replace each index in var_idx_list inplace with the string value
|
||||
// at the specified index.
|
||||
// al_set( var_idx_list, j, wcsdup((const wchar_t *)al_get(
|
||||
// &var_item_list, tmp-1 ) ) );
|
||||
string_values.at(j) = var_item_list.at(tmp - 1);
|
||||
}
|
||||
stop_pos = (slice_end - in);
|
||||
}
|
||||
|
||||
if (!all_vars) {
|
||||
wcstring_list_t string_values(var_idx_list.size());
|
||||
for (size_t j = 0; j < var_idx_list.size(); j++) {
|
||||
long tmp = var_idx_list.at(j);
|
||||
// Check that we are within array bounds. If not, truncate the list to
|
||||
// exit.
|
||||
if (tmp < 1 || (size_t)tmp > var_item_list.size()) {
|
||||
size_t var_src_pos = var_pos_list.at(j);
|
||||
// The slice was parsed starting at stop_pos, so we have to add that
|
||||
// to the error position.
|
||||
append_syntax_error(errors, slice_start + var_src_pos,
|
||||
ARRAY_BOUNDS_ERR);
|
||||
is_ok = false;
|
||||
var_idx_list.resize(j);
|
||||
break;
|
||||
} else {
|
||||
// Replace each index in var_idx_list inplace with the string value
|
||||
// at the specified index.
|
||||
// al_set( var_idx_list, j, wcsdup((const wchar_t *)al_get(
|
||||
// &var_item_list, tmp-1 ) ) );
|
||||
string_values.at(j) = var_item_list.at(tmp - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// string_values is the new var_item_list.
|
||||
var_item_list.swap(string_values);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_ok) {
|
||||
if (is_single) {
|
||||
wcstring res(instr, 0, i);
|
||||
if (i > 0) {
|
||||
if (instr.at(i - 1) != VARIABLE_EXPAND_SINGLE) {
|
||||
res.push_back(INTERNAL_SEPARATOR);
|
||||
} else if (var_item_list.empty() || var_item_list.front().empty()) {
|
||||
// First expansion is empty, but we need to recursively expand.
|
||||
res.push_back(VARIABLE_EXPAND_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < var_item_list.size(); j++) {
|
||||
const wcstring &next = var_item_list.at(j);
|
||||
if (is_ok) {
|
||||
if (j != 0) res.append(L" ");
|
||||
res.append(next);
|
||||
}
|
||||
}
|
||||
assert(stop_pos <= insize);
|
||||
res.append(instr, stop_pos, insize - stop_pos);
|
||||
is_ok &= expand_variables(res, out, i, errors);
|
||||
} else {
|
||||
for (size_t j = 0; j < var_item_list.size(); j++) {
|
||||
const wcstring &next = var_item_list.at(j);
|
||||
if (is_ok && (i == 0) && stop_pos == insize) {
|
||||
append_completion(out, next);
|
||||
} else {
|
||||
if (is_ok) {
|
||||
wcstring new_in;
|
||||
new_in.append(instr, 0, i);
|
||||
|
||||
if (i > 0) {
|
||||
if (instr.at(i - 1) != VARIABLE_EXPAND) {
|
||||
new_in.push_back(INTERNAL_SEPARATOR);
|
||||
} else if (next.empty()) {
|
||||
new_in.push_back(VARIABLE_EXPAND_EMPTY);
|
||||
}
|
||||
}
|
||||
assert(stop_pos <= insize);
|
||||
new_in.append(next);
|
||||
new_in.append(instr, stop_pos, insize - stop_pos);
|
||||
is_ok &= expand_variables(new_in, out, i, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// string_values is the new var_item_list.
|
||||
var_item_list.swap(string_values);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_ok) {
|
||||
return is_ok;
|
||||
}
|
||||
|
||||
// Even with no value, we still need to parse out slice syntax. Behave as though we
|
||||
// had 1 value, so $foo[1] always works.
|
||||
const size_t slice_start = stop_pos;
|
||||
if (slice_start < insize && instr.at(slice_start) == L'[') {
|
||||
const wchar_t *in = instr.c_str();
|
||||
wchar_t *slice_end;
|
||||
size_t bad_pos;
|
||||
|
||||
bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_list, var_pos_list, 1);
|
||||
if (bad_pos != 0) {
|
||||
append_syntax_error(errors, stop_pos + bad_pos, L"Invalid index value");
|
||||
is_ok = 0;
|
||||
return is_ok;
|
||||
}
|
||||
stop_pos = (slice_end - in);
|
||||
|
||||
// Validate that the parsed indexes are valid.
|
||||
for (size_t j = 0; j < var_idx_list.size(); j++) {
|
||||
long tmp = var_idx_list.at(j);
|
||||
if (tmp != 1) {
|
||||
size_t var_src_pos = var_pos_list.at(j);
|
||||
append_syntax_error(errors, slice_start + var_src_pos, ARRAY_BOUNDS_ERR);
|
||||
is_ok = 0;
|
||||
return is_ok;
|
||||
if (is_single) {
|
||||
wcstring res(instr, 0, i);
|
||||
if (i > 0) {
|
||||
if (instr.at(i - 1) != VARIABLE_EXPAND_SINGLE) {
|
||||
res.push_back(INTERNAL_SEPARATOR);
|
||||
} else if (var_item_list.empty() || var_item_list.front().empty()) {
|
||||
// First expansion is empty, but we need to recursively expand.
|
||||
res.push_back(VARIABLE_EXPAND_EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expand a non-existing variable.
|
||||
if (c == VARIABLE_EXPAND) {
|
||||
// Regular expansion, i.e. expand this argument to nothing.
|
||||
empty = true;
|
||||
} else {
|
||||
// Expansion to single argument.
|
||||
wcstring res;
|
||||
res.append(instr, 0, i);
|
||||
if (i > 0 && instr.at(i - 1) == VARIABLE_EXPAND_SINGLE) {
|
||||
res.push_back(VARIABLE_EXPAND_EMPTY);
|
||||
for (size_t j = 0; j < var_item_list.size(); j++) {
|
||||
const wcstring &next = var_item_list.at(j);
|
||||
if (is_ok) {
|
||||
if (j != 0) res.append(L" ");
|
||||
res.append(next);
|
||||
}
|
||||
}
|
||||
assert(stop_pos <= insize);
|
||||
res.append(instr, stop_pos, insize - stop_pos);
|
||||
|
||||
is_ok &= expand_variables(res, out, i, errors);
|
||||
} else {
|
||||
for (size_t j = 0; j < var_item_list.size(); j++) {
|
||||
const wcstring &next = var_item_list.at(j);
|
||||
if (is_ok && i == 0 && stop_pos == insize) {
|
||||
append_completion(out, next);
|
||||
} else {
|
||||
if (is_ok) {
|
||||
wcstring new_in;
|
||||
new_in.append(instr, 0, i);
|
||||
|
||||
if (i > 0) {
|
||||
if (instr.at(i - 1) != VARIABLE_EXPAND) {
|
||||
new_in.push_back(INTERNAL_SEPARATOR);
|
||||
} else if (next.empty()) {
|
||||
new_in.push_back(VARIABLE_EXPAND_EMPTY);
|
||||
}
|
||||
}
|
||||
assert(stop_pos <= insize);
|
||||
new_in.append(next);
|
||||
new_in.append(instr, stop_pos, insize - stop_pos);
|
||||
is_ok &= expand_variables(new_in, out, i, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return is_ok;
|
||||
}
|
||||
|
||||
// Even with no value, we still need to parse out slice syntax. Behave as though we
|
||||
// had 1 value, so $foo[1] always works.
|
||||
const size_t slice_start = stop_pos;
|
||||
if (slice_start < insize && instr.at(slice_start) == L'[') {
|
||||
const wchar_t *in = instr.c_str();
|
||||
wchar_t *slice_end;
|
||||
size_t bad_pos;
|
||||
|
||||
bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_list, var_pos_list, 1);
|
||||
if (bad_pos != 0) {
|
||||
append_syntax_error(errors, stop_pos + bad_pos, L"Invalid index value");
|
||||
is_ok = 0;
|
||||
return is_ok;
|
||||
}
|
||||
stop_pos = (slice_end - in);
|
||||
|
||||
// Validate that the parsed indexes are valid.
|
||||
for (size_t j = 0; j < var_idx_list.size(); j++) {
|
||||
long tmp = var_idx_list.at(j);
|
||||
if (tmp != 1) {
|
||||
size_t var_src_pos = var_pos_list.at(j);
|
||||
append_syntax_error(errors, slice_start + var_src_pos, ARRAY_BOUNDS_ERR);
|
||||
is_ok = 0;
|
||||
return is_ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expand a non-existing variable.
|
||||
if (c == VARIABLE_EXPAND) {
|
||||
// Regular expansion, i.e. expand this argument to nothing.
|
||||
empty = true;
|
||||
} else {
|
||||
// Expansion to single argument.
|
||||
wcstring res;
|
||||
res.append(instr, 0, i);
|
||||
if (i > 0 && instr.at(i - 1) == VARIABLE_EXPAND_SINGLE) {
|
||||
res.push_back(VARIABLE_EXPAND_EMPTY);
|
||||
}
|
||||
assert(stop_pos <= insize);
|
||||
res.append(instr, stop_pos, insize - stop_pos);
|
||||
|
||||
is_ok &= expand_variables(res, out, i, errors);
|
||||
return is_ok;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,6 +976,10 @@ static expand_error_t expand_brackets(const wcstring &instr, expand_flags_t flag
|
||||
}
|
||||
case BRACKET_SEP: {
|
||||
if (bracket_count == 1) last_sep = pos;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break; // we ignore all other characters here
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1025,21 +1020,19 @@ static expand_error_t expand_brackets(const wcstring &instr, expand_flags_t flag
|
||||
tot_len = length_preceding_brackets + length_following_brackets;
|
||||
item_begin = bracket_begin + 1;
|
||||
for (const wchar_t *pos = (bracket_begin + 1); true; pos++) {
|
||||
if (bracket_count == 0) {
|
||||
if ((*pos == BRACKET_SEP) || (pos == bracket_end)) {
|
||||
assert(pos >= item_begin);
|
||||
size_t item_len = pos - item_begin;
|
||||
if (bracket_count == 0 && ((*pos == BRACKET_SEP) || (pos == bracket_end))) {
|
||||
assert(pos >= item_begin);
|
||||
size_t item_len = pos - item_begin;
|
||||
|
||||
wcstring whole_item;
|
||||
whole_item.reserve(tot_len + item_len + 2);
|
||||
whole_item.append(in, length_preceding_brackets);
|
||||
whole_item.append(item_begin, item_len);
|
||||
whole_item.append(bracket_end + 1);
|
||||
expand_brackets(whole_item, flags, out, errors);
|
||||
wcstring whole_item;
|
||||
whole_item.reserve(tot_len + item_len + 2);
|
||||
whole_item.append(in, length_preceding_brackets);
|
||||
whole_item.append(item_begin, item_len);
|
||||
whole_item.append(bracket_end + 1);
|
||||
expand_brackets(whole_item, flags, out, errors);
|
||||
|
||||
item_begin = pos + 1;
|
||||
if (pos == bracket_end) break;
|
||||
}
|
||||
item_begin = pos + 1;
|
||||
if (pos == bracket_end) break;
|
||||
}
|
||||
|
||||
if (*pos == BRACKET_BEGIN) {
|
||||
@@ -1076,6 +1069,10 @@ static int expand_cmdsubst(const wcstring &input, std::vector<completion_t> *out
|
||||
case 1: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DIE("unhandled parse_ret value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const wcstring subcmd(paran_begin + 1, paran_end - paran_begin - 1);
|
||||
@@ -1299,6 +1296,9 @@ static void remove_internal_separator(wcstring *str, bool conv) {
|
||||
str->at(idx) = L'*';
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break; // we ignore all other characters
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1307,8 +1307,10 @@ static void remove_internal_separator(wcstring *str, bool conv) {
|
||||
/// A stage in string expansion is represented as a function that takes an input and returns a list
|
||||
/// of output (by reference). We get flags and errors. It may return an error; if so expansion
|
||||
/// halts.
|
||||
typedef expand_error_t (*expand_stage_t)(const wcstring &input, std::vector<completion_t> *out,
|
||||
expand_flags_t flags, parse_error_list_t *errors);
|
||||
typedef expand_error_t (*expand_stage_t)(const wcstring &input, //!OCLINT(unused param)
|
||||
std::vector<completion_t> *out, //!OCLINT(unused param)
|
||||
expand_flags_t flags, //!OCLINT(unused param)
|
||||
parse_error_list_t *errors); //!OCLINT(unused param)
|
||||
|
||||
static expand_error_t expand_stage_cmdsubst(const wcstring &input, std::vector<completion_t> *out,
|
||||
expand_flags_t flags, parse_error_list_t *errors) {
|
||||
@@ -1389,7 +1391,7 @@ static expand_error_t expand_stage_wildcards(const wcstring &input, std::vector<
|
||||
const bool has_wildcard = wildcard_has(path_to_expand, true /* internal, i.e. ANY_CHAR */);
|
||||
|
||||
if (has_wildcard && (flags & EXECUTABLES_ONLY)) {
|
||||
// Don't do wildcard expansion for executables. See #785. Make them expand to nothing here.
|
||||
; // don't do wildcard expansion for executables, see issue #785
|
||||
} else if (((flags & EXPAND_FOR_COMPLETIONS) && (!(flags & EXPAND_SKIP_WILDCARDS))) ||
|
||||
has_wildcard) {
|
||||
// We either have a wildcard, or we don't have a wildcard but we're doing completion
|
||||
@@ -1401,8 +1403,8 @@ static expand_error_t expand_stage_wildcards(const wcstring &input, std::vector<
|
||||
// which may be CDPATH if the special flag is set.
|
||||
const wcstring working_dir = env_get_pwd_slash();
|
||||
wcstring_list_t effective_working_dirs;
|
||||
bool for_cd = !!(flags & EXPAND_SPECIAL_FOR_CD);
|
||||
bool for_command = !!(flags & EXPAND_SPECIAL_FOR_COMMAND);
|
||||
bool for_cd = static_cast<bool>(flags & EXPAND_SPECIAL_FOR_CD);
|
||||
bool for_command = static_cast<bool>(flags & EXPAND_SPECIAL_FOR_COMMAND);
|
||||
if (!for_cd && !for_command) {
|
||||
// Common case.
|
||||
effective_working_dirs.push_back(working_dir);
|
||||
@@ -1517,19 +1519,17 @@ expand_error_t expand_string(const wcstring &input, std::vector<completion_t> *o
|
||||
|
||||
bool expand_one(wcstring &string, expand_flags_t flags, parse_error_list_t *errors) {
|
||||
std::vector<completion_t> completions;
|
||||
bool result = false;
|
||||
|
||||
if ((!(flags & EXPAND_FOR_COMPLETIONS)) && expand_is_clean(string)) {
|
||||
if (!(flags & EXPAND_FOR_COMPLETIONS) && expand_is_clean(string)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (expand_string(string, &completions, flags | EXPAND_NO_DESCRIPTIONS, errors)) {
|
||||
if (completions.size() == 1) {
|
||||
string = completions.at(0).completion;
|
||||
result = true;
|
||||
}
|
||||
if (expand_string(string, &completions, flags | EXPAND_NO_DESCRIPTIONS, errors) &&
|
||||
completions.size() == 1) {
|
||||
string = completions.at(0).completion;
|
||||
return true;
|
||||
}
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://github.com/fish-shell/fish-shell/issues/367
|
||||
@@ -1556,24 +1556,26 @@ static std::string escape_single_quoted_hack_hack_hack_hack(const char *str) {
|
||||
|
||||
bool fish_xdm_login_hack_hack_hack_hack(std::vector<std::string> *cmds, int argc,
|
||||
const char *const *argv) {
|
||||
bool result = false;
|
||||
if (cmds && cmds->size() == 1) {
|
||||
const std::string &cmd = cmds->at(0);
|
||||
if (cmd == "exec \"${@}\"" || cmd == "exec \"$@\"") {
|
||||
// We're going to construct a new command that starts with exec, and then has the
|
||||
// remaining arguments escaped.
|
||||
std::string new_cmd = "exec";
|
||||
for (int i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (arg) {
|
||||
new_cmd.push_back(' ');
|
||||
new_cmd.append(escape_single_quoted_hack_hack_hack_hack(arg));
|
||||
}
|
||||
}
|
||||
if (!cmds || cmds->size() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cmds->at(0) = new_cmd;
|
||||
result = true;
|
||||
bool result = false;
|
||||
const std::string &cmd = cmds->at(0);
|
||||
if (cmd == "exec \"${@}\"" || cmd == "exec \"$@\"") {
|
||||
// We're going to construct a new command that starts with exec, and then has the
|
||||
// remaining arguments escaped.
|
||||
std::string new_cmd = "exec";
|
||||
for (int i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (arg) {
|
||||
new_cmd.push_back(' ');
|
||||
new_cmd.append(escape_single_quoted_hack_hack_hack_hack(arg));
|
||||
}
|
||||
}
|
||||
|
||||
cmds->at(0) = new_cmd;
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -203,13 +203,10 @@ size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t siz) {
|
||||
|
||||
// Not enough room in dst, add NUL and traverse rest of src.
|
||||
if (n == 0) {
|
||||
if (siz != 0) *d = '\0';
|
||||
// NUL-terminate dst.
|
||||
while (*s++)
|
||||
;
|
||||
if (siz != 0) *d = '\0'; // NUL-terminate dst
|
||||
while (*s++) ; // ignore rest of src
|
||||
}
|
||||
return s - src - 1;
|
||||
// Count does not include NUL.
|
||||
return s - src - 1; // count does not include NUL
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -353,7 +350,7 @@ static int bisearch(wchar_t ucs, const struct interval *table, int max) {
|
||||
if (ucs > table[mid].last)
|
||||
min = mid + 1;
|
||||
else if (ucs < table[mid].first)
|
||||
max = mid - 1;
|
||||
max = mid - 1; //!OCLINT(parameter reassignment)
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
11
src/fish.cpp
11
src/fish.cpp
@@ -17,7 +17,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
@@ -47,13 +46,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
#include "function.h"
|
||||
#include "history.h"
|
||||
#include "input.h"
|
||||
#include "input_common.h"
|
||||
#include "io.h"
|
||||
#include "parser.h"
|
||||
#include "path.h"
|
||||
#include "proc.h"
|
||||
#include "reader.h"
|
||||
#include "wildcard.h"
|
||||
#include "wutil.h" // IWYU pragma: keep
|
||||
|
||||
// PATH_MAX may not exist.
|
||||
@@ -314,6 +311,7 @@ static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *cmds)
|
||||
case 0: {
|
||||
fwprintf(stderr, _(L"getopt_long() unexpectedly returned zero\n"));
|
||||
exit(127);
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
cmds->push_back(optarg);
|
||||
@@ -358,6 +356,7 @@ static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *cmds)
|
||||
case 'v': {
|
||||
fwprintf(stdout, _(L"%s, version %s\n"), PACKAGE_NAME, get_fish_version());
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
case 'D': {
|
||||
char *end;
|
||||
@@ -377,6 +376,7 @@ static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *cmds)
|
||||
default: {
|
||||
// We assume getopt_long() has already emitted a diagnostic msg.
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -424,11 +424,6 @@ int main(int argc, char **argv) {
|
||||
int res = 1;
|
||||
int my_optind = 0;
|
||||
|
||||
// We can't do this at compile time due to the use of enum symbols.
|
||||
assert(EXPAND_SENTINAL >= EXPAND_RESERVED_BASE && EXPAND_SENTINAL <= EXPAND_RESERVED_END);
|
||||
assert(ANY_SENTINAL >= WILDCARD_RESERVED_BASE && ANY_SENTINAL <= WILDCARD_RESERVED_END);
|
||||
assert(R_SENTINAL >= INPUT_COMMON_BASE && R_SENTINAL <= INPUT_COMMON_END);
|
||||
|
||||
program_name = L"fish";
|
||||
set_main_thread();
|
||||
setup_fork_guards();
|
||||
|
||||
@@ -102,7 +102,7 @@ static void dump_node(indent_t node_indent, const parse_node_t &node, const wcst
|
||||
nextc_str[1] = L'c';
|
||||
nextc_str[2] = nextc + '@';
|
||||
}
|
||||
fwprintf(stderr, L"{off %4d, len %4d, indent %2u, kw %ls, %ls} [%ls|%ls|%ls]\n",
|
||||
fwprintf(stderr, L"{off %4u, len %4u, indent %2u, kw %ls, %ls} [%ls|%ls|%ls]\n",
|
||||
node.source_start, node.source_length, node_indent, keyword_description(node.keyword),
|
||||
token_type_description(node.type), prevc_str, source_txt.c_str(), nextc_str);
|
||||
}
|
||||
|
||||
@@ -206,9 +206,8 @@ static void process_input(bool continuous_mode) {
|
||||
output_bind_command(bind_chars);
|
||||
if (first_char_seen && !continuous_mode) {
|
||||
return;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
prev_tstamp = output_elapsed_time(prev_tstamp, first_char_seen);
|
||||
@@ -307,11 +306,13 @@ int main(int argc, char **argv) {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{NULL, 0, NULL, 0}};
|
||||
int opt;
|
||||
while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
|
||||
bool error = false;
|
||||
while (!error && (opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 0: {
|
||||
fprintf(stderr, "getopt_long() unexpectedly returned zero\n");
|
||||
exit(1);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
continuous_mode = true;
|
||||
@@ -320,6 +321,7 @@ int main(int argc, char **argv) {
|
||||
case 'h': {
|
||||
print_help("fish_key_reader", 0);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
char *end;
|
||||
@@ -332,7 +334,7 @@ int main(int argc, char **argv) {
|
||||
debug_level = (int)tmp;
|
||||
} else {
|
||||
fwprintf(stderr, _(L"Invalid value '%s' for debug-level flag"), optarg);
|
||||
exit(1);
|
||||
error = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -347,16 +349,19 @@ int main(int argc, char **argv) {
|
||||
debug_stack_frames = (int)tmp;
|
||||
} else {
|
||||
fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag"), optarg);
|
||||
exit(1);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// We assume getopt_long() has already emitted a diagnostic msg.
|
||||
exit(1);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (error) return 1;
|
||||
|
||||
argc -= optind;
|
||||
if (argc != 0) {
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
// IWYU pragma: no_include <cstring>
|
||||
// IWYU pragma: no_include <cstddef>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -67,8 +69,6 @@
|
||||
static const char *const *s_arguments;
|
||||
static int s_test_run_count = 0;
|
||||
|
||||
bool is_wchar_ucs2() { return sizeof(wchar_t) == 2; }
|
||||
|
||||
// Indicate if we should test the given function. Either we test everything (all arguments) or we
|
||||
// run only tests that have a prefix in s_arguments.
|
||||
static bool should_test_function(const char *func_name) {
|
||||
@@ -95,17 +95,15 @@ static bool should_test_function(const char *func_name) {
|
||||
#define ESCAPE_TEST_LENGTH 100
|
||||
/// The higest character number of character to try and escape.
|
||||
#define ESCAPE_TEST_CHAR 4000
|
||||
/// Number of laps to run performance testing loop.
|
||||
#define LAPS 50
|
||||
|
||||
/// Number of encountered errors.
|
||||
static int err_count = 0;
|
||||
|
||||
/// Print formatted output.
|
||||
static void say(const wchar_t *blah, ...) {
|
||||
static void say(const wchar_t *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, blah);
|
||||
vwprintf(blah, va);
|
||||
va_start(va, fmt);
|
||||
vwprintf(fmt, va);
|
||||
va_end(va);
|
||||
wprintf(L"\n");
|
||||
}
|
||||
@@ -156,21 +154,103 @@ static int chdir_set_pwd(const char *path) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define do_test(e) \
|
||||
do { \
|
||||
if (!(e)) err(L"Test failed on line %lu: %s", __LINE__, #e); \
|
||||
// The odd formulation of these macros is to avoid "multiple unary operator" warnings from oclint
|
||||
// were we to use the more natural "if (!(e)) err(..." form. We have to do this because the rules
|
||||
// for the C preprocessor make it practically impossible to embed a comment in the body of a macro.
|
||||
#define do_test(e) \
|
||||
do { \
|
||||
if (e) { \
|
||||
; \
|
||||
} else { \
|
||||
err(L"Test failed on line %lu: %s", __LINE__, #e); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define do_test_from(e, from_line) \
|
||||
do { \
|
||||
if (!(e)) err(L"Test failed on line %lu (from %lu): %s", __LINE__, from_line, #e); \
|
||||
#define do_test_from(e, from) \
|
||||
do { \
|
||||
if (e) { \
|
||||
; \
|
||||
} else { \
|
||||
err(L"Test failed on line %lu (from %lu): %s", __LINE__, from, #e); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define do_test1(e, msg) \
|
||||
do { \
|
||||
if (!(e)) err(L"Test failed on line %lu: %ls", __LINE__, (msg)); \
|
||||
#define do_test1(e, msg) \
|
||||
do { \
|
||||
if (e) { \
|
||||
; \
|
||||
} else { \
|
||||
err(L"Test failed on line %lu: %ls", __LINE__, (msg)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/// Test that the fish functions for converting strings to numbers work.
|
||||
static void test_str_to_num() {
|
||||
const wchar_t *end;
|
||||
int i;
|
||||
long l;
|
||||
|
||||
i = fish_wcstoi(L"");
|
||||
do_test1(errno == EINVAL && i == 0, L"converting empty string to int did not fail");
|
||||
i = fish_wcstoi(L" \n ");
|
||||
do_test1(errno == EINVAL && i == 0, L"converting whitespace string to int did not fail");
|
||||
i = fish_wcstoi(L"123");
|
||||
do_test1(errno == 0 && i == 123, L"converting valid num to int did not succeed");
|
||||
i = fish_wcstoi(L"-123");
|
||||
do_test1(errno == 0 && i == -123, L"converting valid num to int did not succeed");
|
||||
i = fish_wcstoi(L" 345 ");
|
||||
do_test1(errno == 0 && i == 345, L"converting valid num to int did not succeed");
|
||||
i = fish_wcstoi(L" -345 ");
|
||||
do_test1(errno == 0 && i == -345, L"converting valid num to int did not succeed");
|
||||
i = fish_wcstoi(L"x345");
|
||||
do_test1(errno == EINVAL && i == 0, L"converting invalid num to int did not fail");
|
||||
i = fish_wcstoi(L" x345");
|
||||
do_test1(errno == EINVAL && i == 0, L"converting invalid num to int did not fail");
|
||||
i = fish_wcstoi(L"456 x");
|
||||
do_test1(errno == -1 && i == 456, L"converting invalid num to int did not fail");
|
||||
i = fish_wcstoi(L"99999999999999999999999");
|
||||
do_test1(errno == ERANGE && i == INT_MAX, L"converting invalid num to int did not fail");
|
||||
i = fish_wcstoi(L"-99999999999999999999999");
|
||||
do_test1(errno == ERANGE && i == INT_MIN, L"converting invalid num to int did not fail");
|
||||
i = fish_wcstoi(L"567]", &end);
|
||||
do_test1(errno == -1 && i == 567 && *end == L']',
|
||||
L"converting valid num to int did not succeed");
|
||||
// This is subtle. "567" in base 8 is "375" in base 10. The final "8" is not converted.
|
||||
i = fish_wcstoi(L"5678", &end, 8);
|
||||
do_test1(errno == -1 && i == 375 && *end == L'8',
|
||||
L"converting invalid num to int did not fail");
|
||||
|
||||
l = fish_wcstol(L"");
|
||||
do_test1(errno == EINVAL && l == 0, L"converting empty string to long did not fail");
|
||||
l = fish_wcstol(L" \t ");
|
||||
do_test1(errno == EINVAL && l == 0, L"converting whitespace string to long did not fail");
|
||||
l = fish_wcstol(L"123");
|
||||
do_test1(errno == 0 && l == 123, L"converting valid num to long did not succeed");
|
||||
l = fish_wcstol(L"-123");
|
||||
do_test1(errno == 0 && l == -123, L"converting valid num to long did not succeed");
|
||||
l = fish_wcstol(L" 345 ");
|
||||
do_test1(errno == 0 && l == 345, L"converting valid num to long did not succeed");
|
||||
l = fish_wcstol(L" -345 ");
|
||||
do_test1(errno == 0 && l == -345, L"converting valid num to long did not succeed");
|
||||
l = fish_wcstol(L"x345");
|
||||
do_test1(errno == EINVAL && l == 0, L"converting invalid num to long did not fail");
|
||||
l = fish_wcstol(L" x345");
|
||||
do_test1(errno == EINVAL && l == 0, L"converting invalid num to long did not fail");
|
||||
l = fish_wcstol(L"456 x");
|
||||
do_test1(errno == -1 && l == 456, L"converting invalid num to long did not fail");
|
||||
l = fish_wcstol(L"99999999999999999999999");
|
||||
do_test1(errno == ERANGE && l == LONG_MAX, L"converting invalid num to long did not fail");
|
||||
l = fish_wcstol(L"-99999999999999999999999");
|
||||
do_test1(errno == ERANGE && l == LONG_MIN, L"converting invalid num to long did not fail");
|
||||
l = fish_wcstol(L"567]", &end);
|
||||
do_test1(errno == -1 && l == 567 && *end == L']',
|
||||
L"converting valid num to long did not succeed");
|
||||
// This is subtle. "567" in base 8 is "375" in base 10. The final "8" is not converted.
|
||||
l = fish_wcstol(L"5678", &end, 8);
|
||||
do_test1(errno == -1 && l == 375 && *end == L'8',
|
||||
L"converting invalid num to long did not fail");
|
||||
}
|
||||
|
||||
/// Test sane escapes.
|
||||
static void test_unescape_sane() {
|
||||
const struct test_t {
|
||||
@@ -200,13 +280,12 @@ static void test_unescape_sane() {
|
||||
if (unescape_string(L"echo \\U110000", &output, UNESCAPE_DEFAULT)) {
|
||||
err(L"Should not have been able to unescape \\U110000\n");
|
||||
}
|
||||
if (is_wchar_ucs2()) {
|
||||
// TODO: Make this work on MS Windows.
|
||||
} else {
|
||||
if (!unescape_string(L"echo \\U10FFFF", &output, UNESCAPE_DEFAULT)) {
|
||||
err(L"Should have been able to unescape \\U10FFFF\n");
|
||||
}
|
||||
#if WCHAR_MAX != 0xffff
|
||||
// TODO: Make this work on MS Windows.
|
||||
if (!unescape_string(L"echo \\U10FFFF", &output, UNESCAPE_DEFAULT)) {
|
||||
err(L"Should have been able to unescape \\U10FFFF\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Test the escaping/unescaping code by escaping/unescaping random strings and verifying that the
|
||||
@@ -486,7 +565,7 @@ static parser_test_error_bits_t detect_argument_errors(const wcstring &src) {
|
||||
return PARSER_TEST_ERROR;
|
||||
}
|
||||
|
||||
assert(!tree.empty());
|
||||
assert(!tree.empty()); //!OCLINT(multiple unary operator)
|
||||
const parse_node_t *first_arg = tree.next_node_in_node_list(tree.at(0), symbol_argument, NULL);
|
||||
assert(first_arg != NULL);
|
||||
return parse_util_detect_errors_in_argument(*first_arg, first_arg->get_source(src));
|
||||
@@ -495,7 +574,6 @@ static parser_test_error_bits_t detect_argument_errors(const wcstring &src) {
|
||||
/// Test the parser.
|
||||
static void test_parser() {
|
||||
say(L"Testing parser");
|
||||
parser_t parser;
|
||||
|
||||
say(L"Testing block nesting");
|
||||
if (!parse_util_detect_errors(L"if; end")) {
|
||||
@@ -629,7 +707,8 @@ static void test_parser() {
|
||||
#if 0
|
||||
// This is disabled since it produces a long backtrace. We should find a way to either visually
|
||||
// compress the backtrace, or disable error spewing.
|
||||
parser_t::principal_parser().eval(L"function recursive1 ; recursive2 ; end ; function recursive2 ; recursive1 ; end ; recursive1; ", io_chain_t(), TOP);
|
||||
parser_t::principal_parser().eval(L"function recursive1 ; recursive2 ; end ; "
|
||||
L"function recursive2 ; recursive1 ; end ; recursive1; ", io_chain_t(), TOP);
|
||||
#endif
|
||||
|
||||
say(L"Testing empty function name");
|
||||
@@ -835,19 +914,21 @@ static void test_utf82wchar(const char *src, size_t slen, const wchar_t *dst, si
|
||||
size_t size;
|
||||
wchar_t *mem = NULL;
|
||||
|
||||
#if WCHAR_MAX == 0xffff
|
||||
// Hack: if wchar is only UCS-2, and the UTF-8 input string contains astral characters, then
|
||||
// tweak the expected size to 0.
|
||||
if (src != NULL && is_wchar_ucs2()) {
|
||||
if (src) {
|
||||
// A UTF-8 code unit may represent an astral code point if it has 4 or more leading 1s.
|
||||
const unsigned char astral_mask = 0xF0;
|
||||
for (size_t i = 0; i < slen; i++) {
|
||||
if ((src[i] & astral_mask) == astral_mask) {
|
||||
// Astral char. We expect this conversion to just fail.
|
||||
res = 0;
|
||||
// Astral char. We want this conversion to fail.
|
||||
res = 0; //!OCLINT(parameter reassignment)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!dst) {
|
||||
size = utf8_to_wchar(src, slen, NULL, flags);
|
||||
@@ -884,18 +965,20 @@ static void test_wchar2utf8(const wchar_t *src, size_t slen, const char *dst, si
|
||||
size_t size;
|
||||
char *mem = NULL;
|
||||
|
||||
#if WCHAR_MAX == 0xffff
|
||||
// Hack: if wchar is simulating UCS-2, and the wchar_t input string contains astral characters,
|
||||
// then tweak the expected size to 0.
|
||||
if (src != NULL && is_wchar_ucs2()) {
|
||||
if (src) {
|
||||
const uint32_t astral_mask = 0xFFFF0000U;
|
||||
for (size_t i = 0; i < slen; i++) {
|
||||
if ((src[i] & astral_mask) != 0) {
|
||||
/* astral char */
|
||||
res = 0;
|
||||
// Astral char. We want this conversion to fail.
|
||||
res = 0; //!OCLINT(parameter reassignment)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dst) {
|
||||
mem = (char *)malloc(dlen);
|
||||
@@ -927,10 +1010,7 @@ static void test_utf8() {
|
||||
wchar_t w1[] = {0x54, 0x65, 0x73, 0x74};
|
||||
wchar_t w2[] = {0x0422, 0x0435, 0x0441, 0x0442};
|
||||
wchar_t w3[] = {0x800, 0x1e80, 0x98c4, 0x9910, 0xff00};
|
||||
wchar_t w4[] = {0x15555, 0xf7777, 0x0a};
|
||||
wchar_t wb[] = {(wchar_t)-2, 0xa, (wchar_t)0xffffffff, 0x0441};
|
||||
wchar_t wm[] = {0x41, 0x0441, 0x3042, 0xff67, 0x9b0d};
|
||||
wchar_t wb1[] = {0x0a, 0x0422};
|
||||
wchar_t wb2[] = {0xd800, 0xda00, 0x41, 0xdfff, 0x0a};
|
||||
wchar_t wbom[] = {0xfeff, 0x41, 0x0a};
|
||||
wchar_t wbom2[] = {0x41, 0xa};
|
||||
@@ -939,14 +1019,19 @@ static void test_utf8() {
|
||||
unsigned char u2[] = {0xd0, 0xa2, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82};
|
||||
unsigned char u3[] = {0xe0, 0xa0, 0x80, 0xe1, 0xba, 0x80, 0xe9, 0xa3,
|
||||
0x84, 0xe9, 0xa4, 0x90, 0xef, 0xbc, 0x80};
|
||||
unsigned char u4[] = {0xf0, 0x95, 0x95, 0x95, 0xf3, 0xb7, 0x9d, 0xb7, 0x0a};
|
||||
unsigned char ub[] = {0xa, 0xd1, 0x81};
|
||||
unsigned char um[] = {0x41, 0xd1, 0x81, 0xe3, 0x81, 0x82, 0xef, 0xbd, 0xa7, 0xe9, 0xac, 0x8d};
|
||||
unsigned char ub1[] = {0xa, 0xff, 0xd0, 0xa2, 0xfe, 0x8f, 0xe0, 0x80};
|
||||
unsigned char uc080[] = {0xc0, 0x80};
|
||||
unsigned char ub2[] = {0xed, 0xa1, 0x8c, 0xed, 0xbe, 0xb4, 0x0a};
|
||||
unsigned char ubom[] = {0x41, 0xa};
|
||||
unsigned char ubom2[] = {0xef, 0xbb, 0xbf, 0x41, 0x0a};
|
||||
#if WCHAR_MAX != 0xffff
|
||||
wchar_t w4[] = {0x15555, 0xf7777, 0x0a};
|
||||
wchar_t wb[] = {(wchar_t)-2, 0xa, (wchar_t)0xffffffff, 0x0441};
|
||||
wchar_t wb1[] = {0x0a, 0x0422};
|
||||
unsigned char u4[] = {0xf0, 0x95, 0x95, 0x95, 0xf3, 0xb7, 0x9d, 0xb7, 0x0a};
|
||||
unsigned char ub[] = {0xa, 0xd1, 0x81};
|
||||
unsigned char ub1[] = {0xa, 0xff, 0xd0, 0xa2, 0xfe, 0x8f, 0xe0, 0x80};
|
||||
#endif
|
||||
|
||||
// UTF-8 -> UCS-4 string.
|
||||
test_utf82wchar(ubom2, sizeof(ubom2), wbom2, sizeof(wbom2) / sizeof(*wbom2), UTF8_SKIP_BOM,
|
||||
@@ -990,18 +1075,6 @@ static void test_utf8() {
|
||||
test_wchar2utf8(w1, sizeof(w1) / sizeof(*w1), u1, 0, 0, 0, "invalid params, dst is not NULL");
|
||||
test_wchar2utf8(NULL, 10, nullc, 0, 0, 0, "invalid params, src length is not 0");
|
||||
|
||||
// The following tests won't pass on systems (e.g., Cygwin) where sizeof wchar_t is 2. That's
|
||||
// due to several reasons but the primary one is that narrowing conversions of literals assigned
|
||||
// to the wchar_t arrays above don't result in values that will be treated as errors by the
|
||||
// conversion functions.
|
||||
if (is_wchar_ucs2()) return;
|
||||
test_utf82wchar(u4, sizeof(u4), w4, sizeof(w4) / sizeof(*w4), 0, sizeof(w4) / sizeof(*w4),
|
||||
"u4/w4 4 octets chars");
|
||||
test_wchar2utf8(w4, sizeof(w4) / sizeof(*w4), u4, sizeof(u4), 0, sizeof(u4),
|
||||
"w4/u4 4 octets chars");
|
||||
test_wchar2utf8(wb, sizeof(wb) / sizeof(*wb), ub, sizeof(ub), 0, 0, "wb/ub bad chars");
|
||||
test_wchar2utf8(wb, sizeof(wb) / sizeof(*wb), ub, sizeof(ub), UTF8_IGNORE_ERROR, sizeof(ub),
|
||||
"wb/ub ignore bad chars");
|
||||
test_wchar2utf8(wm, sizeof(wm) / sizeof(*wm), um, sizeof(um), 0, sizeof(um),
|
||||
"wm/um mixed languages");
|
||||
test_wchar2utf8(wm, sizeof(wm) / sizeof(*wm), um, sizeof(um) - 1, 0, 0, "wm/um boundaries -1");
|
||||
@@ -1009,20 +1082,34 @@ static void test_utf8() {
|
||||
"wm/um boundaries +1");
|
||||
test_wchar2utf8(wm, sizeof(wm) / sizeof(*wm), nullc, 0, 0, sizeof(um),
|
||||
"wm/um calculate length");
|
||||
test_utf82wchar(um, sizeof(um), wm, sizeof(wm) / sizeof(*wm), 0, sizeof(wm) / sizeof(*wm),
|
||||
"um/wm mixed languages");
|
||||
test_utf82wchar(um, sizeof(um), wm, sizeof(wm) / sizeof(*wm) + 1, 0, sizeof(wm) / sizeof(*wm),
|
||||
"um/wm boundaries +1");
|
||||
test_utf82wchar(um, sizeof(um), NULL, 0, 0, sizeof(wm) / sizeof(*wm), "um/wm calculate length");
|
||||
|
||||
// The following tests won't pass on systems (e.g., Cygwin) where sizeof wchar_t is 2. That's
|
||||
// due to several reasons but the primary one is that narrowing conversions of literals assigned
|
||||
// to the wchar_t arrays above don't result in values that will be treated as errors by the
|
||||
// conversion functions.
|
||||
#if WCHAR_MAX != 0xffff
|
||||
test_utf82wchar(u4, sizeof(u4), w4, sizeof(w4) / sizeof(*w4), 0, sizeof(w4) / sizeof(*w4),
|
||||
"u4/w4 4 octets chars");
|
||||
test_wchar2utf8(w4, sizeof(w4) / sizeof(*w4), u4, sizeof(u4), 0, sizeof(u4),
|
||||
"w4/u4 4 octets chars");
|
||||
test_wchar2utf8(wb, sizeof(wb) / sizeof(*wb), ub, sizeof(ub), 0, 0, "wb/ub bad chars");
|
||||
test_wchar2utf8(wb, sizeof(wb) / sizeof(*wb), ub, sizeof(ub), UTF8_IGNORE_ERROR, sizeof(ub),
|
||||
"wb/ub ignore bad chars");
|
||||
test_wchar2utf8(wb, sizeof(wb) / sizeof(*wb), nullc, 0, 0, 0,
|
||||
"wb calculate length of bad chars");
|
||||
test_wchar2utf8(wb, sizeof(wb) / sizeof(*wb), nullc, 0, UTF8_IGNORE_ERROR, sizeof(ub),
|
||||
"calculate length, ignore bad chars");
|
||||
test_utf82wchar(ub1, sizeof(ub1), wb1, sizeof(wb1) / sizeof(*wb1), UTF8_IGNORE_ERROR,
|
||||
sizeof(wb1) / sizeof(*wb1), "ub1/wb1 ignore bad chars");
|
||||
test_utf82wchar(um, sizeof(um), wm, sizeof(wm) / sizeof(*wm), 0, sizeof(wm) / sizeof(*wm),
|
||||
"um/wm mixed languages");
|
||||
test_utf82wchar(um, sizeof(um), wm, sizeof(wm) / sizeof(*wm) + 1, 0, sizeof(wm) / sizeof(*wm),
|
||||
"um/wm boundaries +1");
|
||||
test_utf82wchar(um, sizeof(um), NULL, 0, 0, sizeof(wm) / sizeof(*wm), "um/wm calculate length");
|
||||
test_utf82wchar(ub1, sizeof(ub1), NULL, 0, 0, 0, "ub1 calculate length of bad chars");
|
||||
test_utf82wchar(ub1, sizeof(ub1), NULL, 0, UTF8_IGNORE_ERROR, sizeof(wb1) / sizeof(*wb1),
|
||||
"ub1 calculate length, ignore bad chars");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_escape_sequences(void) {
|
||||
@@ -1139,7 +1226,8 @@ static bool expand_test(const wchar_t *in, expand_flags_t flags, ...) {
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
if ((arg = va_arg(va, wchar_t *)) != 0) {
|
||||
arg = va_arg(va, wchar_t *);
|
||||
if (arg) {
|
||||
wcstring msg = L"Expected [";
|
||||
bool first = true;
|
||||
for (wcstring_list_t::const_iterator it = expected.begin(), end = expected.end();
|
||||
@@ -2209,7 +2297,6 @@ static void test_history_matches(history_search_t &search, size_t matches, unsig
|
||||
size_t i;
|
||||
for (i = 0; i < matches; i++) {
|
||||
do_test(search.go_backwards());
|
||||
wcstring item = search.current_string();
|
||||
}
|
||||
// do_test_from(!search.go_backwards(), from_line);
|
||||
bool result = search.go_backwards();
|
||||
@@ -2403,9 +2490,13 @@ bool poll_notifier(universal_notifier_t *note) {
|
||||
|
||||
static void trigger_or_wait_for_notification(universal_notifier_t *notifier,
|
||||
universal_notifier_t::notifier_strategy_t strategy) {
|
||||
// This argument should be removed if it isn't actually needed by these unit tests. I'm going to
|
||||
// silence the warning. See https://github.com/fish-shell/fish-shell/issues/3439.
|
||||
UNUSED(notifier);
|
||||
|
||||
switch (strategy) {
|
||||
case universal_notifier_t::strategy_default: {
|
||||
assert(0 && "strategy_default should be passed");
|
||||
DIE("strategy_default should be passed");
|
||||
break;
|
||||
}
|
||||
case universal_notifier_t::strategy_shmem_polling: {
|
||||
@@ -2815,6 +2906,22 @@ void history_tests_t::test_history_merge(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure incorporate_external_changes doesn't drop items! (#3496)
|
||||
history_t *const writer = hists[0];
|
||||
history_t *const reader = hists[1];
|
||||
const wcstring more_texts[] = {L"Item_#3496_1", L"Item_#3496_2", L"Item_#3496_3",
|
||||
L"Item_#3496_4", L"Item_#3496_5", L"Item_#3496_6"};
|
||||
for (size_t i = 0; i < sizeof more_texts / sizeof *more_texts; i++) {
|
||||
// time_barrier because merging will ignore items that may be newer
|
||||
if (i > 0) time_barrier();
|
||||
writer->add(more_texts[i]);
|
||||
writer->incorporate_external_changes();
|
||||
reader->incorporate_external_changes();
|
||||
for (size_t j = 0; j < i; j++) {
|
||||
do_test(history_contains(reader, more_texts[j]));
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up.
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
delete hists[i];
|
||||
@@ -3063,35 +3170,35 @@ static bool test_1_parse_ll2(const wcstring &src, wcstring *out_cmd, wcstring *o
|
||||
out_joined_args->clear();
|
||||
*out_deco = parse_statement_decoration_none;
|
||||
|
||||
bool result = false;
|
||||
parse_node_tree_t tree;
|
||||
if (parse_tree_from_string(src, parse_flag_none, &tree, NULL)) {
|
||||
// Get the statement. Should only have one.
|
||||
const parse_node_tree_t::parse_node_list_t stmt_nodes =
|
||||
tree.find_nodes(tree.at(0), symbol_plain_statement);
|
||||
if (stmt_nodes.size() != 1) {
|
||||
say(L"Unexpected number of statements (%lu) found in '%ls'", stmt_nodes.size(),
|
||||
src.c_str());
|
||||
return false;
|
||||
}
|
||||
const parse_node_t &stmt = *stmt_nodes.at(0);
|
||||
|
||||
// Return its decoration.
|
||||
*out_deco = tree.decoration_for_plain_statement(stmt);
|
||||
|
||||
// Return its command.
|
||||
tree.command_for_plain_statement(stmt, src, out_cmd);
|
||||
|
||||
// Return arguments separated by spaces.
|
||||
const parse_node_tree_t::parse_node_list_t arg_nodes =
|
||||
tree.find_nodes(stmt, symbol_argument);
|
||||
for (size_t i = 0; i < arg_nodes.size(); i++) {
|
||||
if (i > 0) out_joined_args->push_back(L' ');
|
||||
out_joined_args->append(arg_nodes.at(i)->get_source(src));
|
||||
}
|
||||
result = true;
|
||||
if (!parse_tree_from_string(src, parse_flag_none, &tree, NULL)) {
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
|
||||
// Get the statement. Should only have one.
|
||||
const parse_node_tree_t::parse_node_list_t stmt_nodes =
|
||||
tree.find_nodes(tree.at(0), symbol_plain_statement);
|
||||
if (stmt_nodes.size() != 1) {
|
||||
say(L"Unexpected number of statements (%lu) found in '%ls'", stmt_nodes.size(),
|
||||
src.c_str());
|
||||
return false;
|
||||
}
|
||||
const parse_node_t &stmt = *stmt_nodes.at(0);
|
||||
|
||||
// Return its decoration.
|
||||
*out_deco = tree.decoration_for_plain_statement(stmt);
|
||||
|
||||
// Return its command.
|
||||
tree.command_for_plain_statement(stmt, src, out_cmd);
|
||||
|
||||
// Return arguments separated by spaces.
|
||||
const parse_node_tree_t::parse_node_list_t arg_nodes = tree.find_nodes(stmt, symbol_argument);
|
||||
for (size_t i = 0; i < arg_nodes.size(); i++) {
|
||||
if (i > 0) out_joined_args->push_back(L' ');
|
||||
out_joined_args->append(arg_nodes.at(i)->get_source(src));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test the LL2 (two token lookahead) nature of the parser by exercising the special builtin and
|
||||
@@ -3255,29 +3362,31 @@ static wcstring_list_t separate_by_format_specifiers(const wchar_t *format) {
|
||||
|
||||
// Walk over the format specifier (if any).
|
||||
cursor = next_specifier;
|
||||
if (*cursor == '%') {
|
||||
cursor++;
|
||||
// Flag
|
||||
if (wcschr(L"#0- +'", *cursor)) cursor++;
|
||||
// Minimum field width
|
||||
while (iswdigit(*cursor)) cursor++;
|
||||
// Precision
|
||||
if (*cursor == L'.') {
|
||||
cursor++;
|
||||
while (iswdigit(*cursor)) cursor++;
|
||||
}
|
||||
// Length modifier
|
||||
if (!wcsncmp(cursor, L"ll", 2) || !wcsncmp(cursor, L"hh", 2)) {
|
||||
cursor += 2;
|
||||
} else if (wcschr(L"hljtzqL", *cursor)) {
|
||||
cursor++;
|
||||
}
|
||||
// The format specifier itself. We allow any character except NUL.
|
||||
if (*cursor != L'\0') {
|
||||
cursor += 1;
|
||||
}
|
||||
assert(cursor <= end);
|
||||
if (*cursor != '%') {
|
||||
continue;
|
||||
}
|
||||
|
||||
cursor++;
|
||||
// Flag
|
||||
if (wcschr(L"#0- +'", *cursor)) cursor++;
|
||||
// Minimum field width
|
||||
while (iswdigit(*cursor)) cursor++;
|
||||
// Precision
|
||||
if (*cursor == L'.') {
|
||||
cursor++;
|
||||
while (iswdigit(*cursor)) cursor++;
|
||||
}
|
||||
// Length modifier
|
||||
if (!wcsncmp(cursor, L"ll", 2) || !wcsncmp(cursor, L"hh", 2)) {
|
||||
cursor += 2;
|
||||
} else if (wcschr(L"hljtzqL", *cursor)) {
|
||||
cursor++;
|
||||
}
|
||||
// The format specifier itself. We allow any character except NUL.
|
||||
if (*cursor != L'\0') {
|
||||
cursor += 1;
|
||||
}
|
||||
assert(cursor <= end);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -3852,7 +3961,7 @@ long return_timezone_hour(time_t tstamp, const wchar_t *timezone) {
|
||||
struct tm ltime;
|
||||
char ltime_str[3];
|
||||
char *str_ptr;
|
||||
int n;
|
||||
size_t n;
|
||||
|
||||
env_set(L"TZ", timezone, ENV_EXPORT);
|
||||
localtime_r(&tstamp, <ime);
|
||||
@@ -3904,7 +4013,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
srand(time(0));
|
||||
srand((unsigned int)time(NULL));
|
||||
configure_thread_assertions_for_testing();
|
||||
|
||||
program_name = L"(ignore)";
|
||||
@@ -3927,6 +4036,7 @@ int main(int argc, char **argv) {
|
||||
// Set default signal handlers, so we can ctrl-C out of this.
|
||||
signal_reset_handlers();
|
||||
|
||||
if (should_test_function("str_to_num")) test_str_to_num();
|
||||
if (should_test_function("highlighting")) test_highlighting();
|
||||
if (should_test_function("new_parser_ll2")) test_new_parser_ll2();
|
||||
if (should_test_function("new_parser_fuzzing"))
|
||||
|
||||
@@ -161,7 +161,7 @@ void function_add(const function_data_t &data, const parser_t &parser, int defin
|
||||
UNUSED(parser);
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
|
||||
CHECK(!data.name.empty(), );
|
||||
CHECK(!data.name.empty(), ); //!OCLINT(multiple unary operator)
|
||||
CHECK(data.definition, );
|
||||
scoped_lock locker(functions_lock);
|
||||
|
||||
@@ -272,9 +272,9 @@ bool function_get_desc(const wcstring &name, wcstring *out_desc) {
|
||||
if (out_desc && func && !func->description.empty()) {
|
||||
out_desc->assign(_(func->description.c_str()));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void function_set_desc(const wcstring &name, const wcstring &desc) {
|
||||
@@ -311,8 +311,8 @@ wcstring_list_t function_get_names(int get_hidden) {
|
||||
const wcstring &name = iter->first;
|
||||
|
||||
// Maybe skip hidden.
|
||||
if (!get_hidden) {
|
||||
if (name.empty() || name.at(0) == L'_') continue;
|
||||
if (!get_hidden && (name.empty() || name.at(0) == L'_')) {
|
||||
continue;
|
||||
}
|
||||
names.insert(name);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user