mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-10 09:41:16 -03:00
Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
156d57d270 | ||
|
|
a1653c928e | ||
|
|
0988d2fc15 | ||
|
|
efcfec0ba1 | ||
|
|
f9e131aa93 | ||
|
|
582675c96a | ||
|
|
f95f12f5e7 | ||
|
|
38cd373ca3 | ||
|
|
dfd1e3a362 | ||
|
|
771db6018e | ||
|
|
865abebd11 | ||
|
|
29ebd4a5ff | ||
|
|
3c3bf7ffd7 | ||
|
|
873d7f6bb3 | ||
|
|
018f1f7e20 | ||
|
|
1a03c23b58 | ||
|
|
c23f311956 | ||
|
|
9ab77c7ddc | ||
|
|
3cb105adbd | ||
|
|
7e8b8345e7 | ||
|
|
fd9355966e | ||
|
|
600c0d5b3f | ||
|
|
013a563ed0 | ||
|
|
f204fd147d | ||
|
|
dfebfcf376 | ||
|
|
d2fc1c47ac | ||
|
|
76b6959cad | ||
|
|
9fe2b27bba | ||
|
|
daa3cc17c4 | ||
|
|
a7df92e187 | ||
|
|
4762d52e52 | ||
|
|
4218c1f1a4 | ||
|
|
76f7b3e98e | ||
|
|
274be5eeeb | ||
|
|
762f3aa0ce | ||
|
|
a85edbfbcd | ||
|
|
dbb74f87ba | ||
|
|
c7c9ff9a4a | ||
|
|
56e1109609 | ||
|
|
371516382d | ||
|
|
fe70c29c48 | ||
|
|
f725cd402d | ||
|
|
8a07db8e8f | ||
|
|
e240d81ff8 | ||
|
|
10ef0d9daf | ||
|
|
25d85bdc64 | ||
|
|
a536ab810a | ||
|
|
ddd0e28b4f | ||
|
|
11951a245f | ||
|
|
e7398c0248 | ||
|
|
99e02ba47a | ||
|
|
e450190d50 | ||
|
|
6bc0064a2a | ||
|
|
69c71052ef | ||
|
|
b1c5e003ef | ||
|
|
ece0aa5324 | ||
|
|
8bb2ca95c8 | ||
|
|
a561904afd | ||
|
|
d85bdf120f | ||
|
|
76457bdc4e | ||
|
|
c96a07dc96 | ||
|
|
791b42f065 | ||
|
|
0a3fec5e8b | ||
|
|
a36dbad3b8 | ||
|
|
54ff7b29a9 | ||
|
|
5b4db4a6ea | ||
|
|
edfa6746c6 | ||
|
|
bf801afef8 | ||
|
|
955c0003ca | ||
|
|
119b978cbc | ||
|
|
12e059adf8 | ||
|
|
d948b34420 | ||
|
|
abaa057e5c | ||
|
|
d655d24148 | ||
|
|
63fa8dfd26 |
@@ -1,3 +1,36 @@
|
||||
fish 3.2.1 (released March 18, 2021)
|
||||
====================================
|
||||
|
||||
This release of fish fixes the following problems identified in fish 3.2.0:
|
||||
|
||||
- Commands in key bindings are run with fish's internal terminal modes, instead of the terminal modes typically used for commands. This fixes a bug introduced in 3.2.0, where text would unexpectedly appear on the terminal, especially when pasting (:issue:`7770`).
|
||||
- Prompts which use the internal ``__fish_print_pipestatus`` function will display correctly rather than carrying certain modifiers (such as bold) further than intended (:issue:`7771`).
|
||||
- Redirections to internal file descriptors is allowed again, reversing the changes in 3.2.0. This fixes a problem with Midnight Commander (:issue:`7769`).
|
||||
- Universal variables should be fully reliable regardless of operating system again (:issue:`7774`).
|
||||
- ``fish_git_prompt`` no longer causes screen flickering in certain terminals (:issue:`7775`).
|
||||
- ``fish_add_path`` manipulates the ``fish_user_paths`` variable correctly when moving multiple paths (:issue:`7776`).
|
||||
- Pasting with a multi-line command no longer causes a ``__fish_tokenizer_state`` error (:issue:`7782`).
|
||||
- ``psub`` inside event handlers cleans up temporary files properly (:issue:`7792`).
|
||||
- Event handlers declared with ``--on-job-exit $fish_pid`` no longer run constantly (:issue:`7721`), although these functions should use ``--on-event fish_exit`` instead.
|
||||
- Changing terminal modes inside ``config.fish`` works (:issue:`7783`).
|
||||
- ``set_color --print-colors`` no longer prints all colors in bold (:issue:`7805`)
|
||||
- Completing commands starting with a ``-`` no longer prints an error (:issue:`7809`).
|
||||
- Running ``fish_command_not_found`` directly no longer produces an error on macOS or other OSes which do not have a handler available (:issue:`7777`).
|
||||
- The new ``type`` builtin now has the (deprecated) ``--quiet`` long form of ``-q`` (:issue:`7766`).
|
||||
|
||||
It also includes some small enhancements:
|
||||
|
||||
- ``help`` and ``fish_config`` work correctly when fish is running in a Chrome OS Crostini Linux VM (:issue:`7789`).
|
||||
- The history file can be made a symbolic link without it being overwritten (:issue:`7754`), matching a similar improvement for the universal variable file in 3.2.0.
|
||||
- An unhelpful error ("access: No error"), seen on Cygwin, is no longer produced (:issue:`7785`).
|
||||
- Improvements to the ``rsync`` completions (:issue:`7763`), some completion descriptions (:issue:`7788`), and completions that use IP address (:issue:`7787`).
|
||||
- Improvements to the appearance of ``fish_config`` (:issue:`7811`).
|
||||
|
||||
If you are upgrading from version 3.1.2 or before, please also review
|
||||
the release notes for 3.2.0 (included below).
|
||||
|
||||
--------------
|
||||
|
||||
fish 3.2.0 (released March 1, 2021)
|
||||
===================================
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ set(SPHINX_MANPAGE_DIR "${SPHINX_ROOT_DIR}/man")
|
||||
# Prepend the output dir of fish_indent to PATH.
|
||||
add_custom_target(sphinx-docs
|
||||
mkdir -p ${SPHINX_HTML_DIR}/_static/
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SPHINX_SRC_DIR}/_static/pygments.css ${SPHINX_HTML_DIR}/_static/
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SPHINX_SRC_DIR}/_static/custom.css ${SPHINX_HTML_DIR}/_static/
|
||||
COMMAND env PATH="$<TARGET_FILE_DIR:fish_indent>:$$PATH"
|
||||
${SPHINX_EXECUTABLE}
|
||||
-q -b html
|
||||
|
||||
@@ -113,6 +113,7 @@ endforeach(TESTTYPE)
|
||||
|
||||
# Now add a dependency chain between the serial versions.
|
||||
# This ensures they run in order.
|
||||
add_dependencies(serial_test_low_level test_prep)
|
||||
add_dependencies(serial_test_fishscript serial_test_low_level)
|
||||
add_dependencies(serial_test_interactive serial_test_fishscript)
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
.sphinxsidebar ul.current > li.current { font-weight: bold }
|
||||
|
||||
.gray { color: #555555 }
|
||||
.purple { color: #551a8b }
|
||||
.red { color: #FF0000 }
|
||||
|
||||
/* Color based on the Name.Function (.nf) class from pygments.css. */
|
||||
.command { color: #005fd7 }
|
||||
|
||||
/* Color based on the Name.Constant (.no) class from pygments.css. */
|
||||
.param { color: #00afff }
|
||||
|
||||
/* Color based on the Name.Constant (.no) class from pygments.css. */
|
||||
/* Used for underlining file paths in interactive code examples. */
|
||||
.param-valid-path { color: #00afff; text-decoration: underline }
|
||||
|
||||
/* Color based on the Generic.Prompt (.gp) class from pygments.css. */
|
||||
.prompt { color: #8f5902 }
|
||||
|
||||
kbd {
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: .2em;
|
||||
box-shadow: 0.1em 0.1em 0.2em rgba(0,0,0,0.1);
|
||||
color: #000;
|
||||
padding: 0.1em 0.3em;
|
||||
}
|
||||
@@ -73,31 +73,31 @@ Functions
|
||||
|
||||
``math`` supports the following functions:
|
||||
|
||||
- ``abs``
|
||||
- ``acos``
|
||||
- ``asin``
|
||||
- ``atan``
|
||||
- ``atan2``
|
||||
- ``abs`` - the absolute value, with positive sign
|
||||
- ``acos`` - arc cosine
|
||||
- ``asin`` - arc sine
|
||||
- ``atan`` - arc tangent
|
||||
- ``atan2`` - arc tangent of two variables
|
||||
- ``bitand``, ``bitor`` and ``bitxor`` to perform bitwise operations. These will throw away any non-integer parts and interpret the rest as an int.
|
||||
- ``ceil``
|
||||
- ``cos``
|
||||
- ``cosh``
|
||||
- ``ceil`` - round number up to nearest integer
|
||||
- ``cos`` - the cosine
|
||||
- ``cosh`` - hyperbolic cosine
|
||||
- ``exp`` - the base-e exponential function
|
||||
- ``fac`` - factorial
|
||||
- ``floor``
|
||||
- ``fac`` - factorial - also known as ``x!`` (``x * (x - 1) * (x - 2) * ... * 1``)
|
||||
- ``floor`` - round number down to nearest integer
|
||||
- ``ln`` - the base-e logarithm
|
||||
- ``log`` or ``log10`` - the base-10 logarithm
|
||||
- ``ncr``
|
||||
- ``npr``
|
||||
- ``ncr`` - "from n choose r" combination function - how many subsets of size r can be taken from n (order doesn't matter)
|
||||
- ``npr`` - the number of subsets of size r that can be taken from a set of n elements (including different order)
|
||||
- ``pow(x,y)`` returns x to the y (and can be written as ``x ^ y``)
|
||||
- ``round`` - rounds to the nearest integer, away from 0
|
||||
- ``sin``
|
||||
- ``sinh``
|
||||
- ``sqrt``
|
||||
- ``tan``
|
||||
- ``tanh``
|
||||
- ``sin`` - the sine function
|
||||
- ``sinh`` - the hyperbolic sine
|
||||
- ``sqrt`` - the square root - (can also be written as ``x ^ 0.5``)
|
||||
- ``tan`` - the tangent
|
||||
- ``tanh`` - the hyperbolic tangent
|
||||
|
||||
All of the trigonometric functions use radians.
|
||||
All of the trigonometric functions use radians (the pi-based scale, not 360°).
|
||||
|
||||
Examples
|
||||
--------
|
||||
@@ -124,6 +124,8 @@ Examples
|
||||
|
||||
``math --base=hex 192`` prints ``0xc0``.
|
||||
|
||||
``math 'ncr(49,6)'`` prints 13983816 - that's the number of possible picks in 6-from-49 lotto.
|
||||
|
||||
Compatibility notes
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -52,12 +52,6 @@ def setup(app):
|
||||
)
|
||||
lexers["fish-docs-samples"] = fish_indent_lexer
|
||||
|
||||
# add_css_file only appears in Sphinx 1.8.0
|
||||
if hasattr(app, "add_css_file"):
|
||||
app.add_css_file("custom.css")
|
||||
else:
|
||||
app.add_stylesheet("custom.css")
|
||||
|
||||
app.add_config_value("issue_url", default=None, rebuild="html")
|
||||
app.add_role("issue", issue_role)
|
||||
|
||||
@@ -154,7 +148,7 @@ html_copy_source = False
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ["_static"]
|
||||
# html_static_path = ["_static"]
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
|
||||
@@ -301,20 +301,24 @@ The ``open`` command uses the MIME type database and the ``.desktop`` files used
|
||||
Why won't SSH/SCP/rsync connect properly when fish is my login shell?
|
||||
---------------------------------------------------------------------
|
||||
|
||||
This problem may manifest as messages such as "``Received message too long``", "``open terminal
|
||||
This problem may show up as messages like "``Received message too long``", "``open terminal
|
||||
failed: not a terminal``", "``Bad packet length``", or "``Connection refused``" with strange output
|
||||
in ``ssh_exchange_identification`` messages in the debug log.
|
||||
|
||||
These problems are generally caused by the :ref:`user initialization file <initialization>` (usually
|
||||
``~/.config/fish/config.fish``) producing output when started in non-interactive mode.
|
||||
This usually happens because fish reads the :ref:`user configuration file <initialization>` (``~/.config/fish/config.fish``) *always*,
|
||||
whether it's in an interactive or login or non-interactive or non-login shell.
|
||||
|
||||
This simplifies matters, but it also means when config.fish generates output, it will do that even in non-interactive shells like the one ssh/scp/rsync start when they connect.
|
||||
|
||||
Anything in config.fish that produces output should be guarded with ``status is-interactive`` (or ``status is-login`` if you prefer)::
|
||||
|
||||
All statements in initialization files that output to the terminal should be guarded with something
|
||||
like the following::
|
||||
|
||||
if status is-interactive
|
||||
...
|
||||
end
|
||||
|
||||
The same applies for example when you start ``tmux`` in config.fish without guards, which will cause a message like ``sessions should be nested with care, unset $TMUX to force``.
|
||||
|
||||
.. _faq-unicode:
|
||||
|
||||
I'm getting weird graphical glitches (a staircase effect, ghost characters,...)?
|
||||
|
||||
@@ -269,8 +269,6 @@ Any arbitrary file descriptor can used in a redirection by prefixing the redirec
|
||||
|
||||
For example, ``echo hello 2> output.stderr`` writes the standard error (file descriptor 2) to ``output.stderr``.
|
||||
|
||||
It is an error to redirect a builtin, function, or block to a file descriptor above 2. However this is supported for external commands.
|
||||
|
||||
.. [#] Previous versions of fish also allowed specifying this as ``^DESTINATION``, but that made another character special so it was deprecated and will be removed in the future. See :ref:`feature flags<featureflags>`.
|
||||
|
||||
.. _pipes:
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{% extends "classic/layout.html" %}
|
||||
{% extends "basic/layout.html" %}
|
||||
{# Remove broken "genindex" link - unfortunately this takes with it the acceptable "next" and "previous" links, but they're not super necessary. #}
|
||||
{% set rellinks = [] %}
|
||||
|
||||
{% block rootrellink %}
|
||||
<li><img src="{{ pathto('_static/' + theme_root_icon, 1) }}" alt=""
|
||||
style="max-width: 80px; vertical-align: middle; margin-top: -1px"/></li>
|
||||
style="width: 80px; vertical-align: middle; margin-top: -1px"/></li>
|
||||
<li><a href="{{theme_root_url}}">{{theme_root_name}}</a>{{ reldelim1 }}</li>
|
||||
{% if theme_root_include_title %}
|
||||
<a href="{{ pathto('index') }}">{{ shorttitle }}</a>{{ reldelim1 }}
|
||||
@@ -41,9 +41,6 @@
|
||||
{% block sidebar2 %} {% endblock %}
|
||||
{% block extrahead %}
|
||||
<link rel="shortcut icon" type="image/png" href="{{ pathto('_static/' + theme_root_icon, 1) }}" />
|
||||
{% if builder != "htmlhelp" %}
|
||||
{% if not embedded %}<script type="text/javascript" src="{{ pathto('_static/copybutton.js', 1) }}"></script>{% endif %}
|
||||
{% endif %}
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
/* Add a [>>>] button on the top-right corner of code samples to hide
|
||||
* the >>> and ... prompts and the output and thus make the code
|
||||
* copyable. */
|
||||
var div = $('.highlight-python .highlight,' +
|
||||
'.highlight-python3 .highlight,' +
|
||||
'.highlight-pycon .highlight,' +
|
||||
'.highlight-default .highlight');
|
||||
var pre = div.find('pre');
|
||||
|
||||
// get the styles from the current theme
|
||||
pre.parent().parent().css('position', 'relative');
|
||||
var hide_text = 'Hide the prompts and output';
|
||||
var show_text = 'Show the prompts and output';
|
||||
var border_width = pre.css('border-top-width');
|
||||
var border_style = pre.css('border-top-style');
|
||||
var border_color = pre.css('border-top-color');
|
||||
var button_styles = {
|
||||
'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0',
|
||||
'border-color': border_color, 'border-style': border_style,
|
||||
'border-width': border_width, 'color': border_color, 'text-size': '75%',
|
||||
'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em',
|
||||
'border-radius': '0 3px 0 0'
|
||||
}
|
||||
|
||||
// create and add the button to all the code blocks that contain >>>
|
||||
div.each(function(index) {
|
||||
var jthis = $(this);
|
||||
if (jthis.find('.gp').length > 0) {
|
||||
var button = $('<span class="copybutton">>>></span>');
|
||||
button.css(button_styles)
|
||||
button.attr('title', hide_text);
|
||||
button.data('hidden', 'false');
|
||||
jthis.prepend(button);
|
||||
}
|
||||
// tracebacks (.gt) contain bare text elements that need to be
|
||||
// wrapped in a span to work with .nextUntil() (see later)
|
||||
jthis.find('pre:has(.gt)').contents().filter(function() {
|
||||
return ((this.nodeType == 3) && (this.data.trim().length > 0));
|
||||
}).wrap('<span>');
|
||||
});
|
||||
|
||||
// define the behavior of the button when it's clicked
|
||||
$('.copybutton').click(function(e){
|
||||
e.preventDefault();
|
||||
var button = $(this);
|
||||
if (button.data('hidden') === 'false') {
|
||||
// hide the code output
|
||||
button.parent().find('.go, .gp, .gt').hide();
|
||||
button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden');
|
||||
button.css('text-decoration', 'line-through');
|
||||
button.attr('title', show_text);
|
||||
button.data('hidden', 'true');
|
||||
} else {
|
||||
// show the code output
|
||||
button.parent().find('.go, .gp, .gt').show();
|
||||
button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible');
|
||||
button.css('text-decoration', 'none');
|
||||
button.attr('title', hide_text);
|
||||
button.data('hidden', 'false');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import url("default.css");
|
||||
@import url("classic.css");
|
||||
|
||||
html {
|
||||
background: none;
|
||||
@@ -276,3 +276,31 @@ dl > dt span ~ em {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sphinxsidebar ul.current > li.current { font-weight: bold }
|
||||
|
||||
.gray { color: #555555 }
|
||||
.purple { color: #551a8b }
|
||||
.red { color: #FF0000 }
|
||||
|
||||
/* Color based on the Name.Function (.nf) class from pygments.css. */
|
||||
.command { color: #005fd7 }
|
||||
|
||||
/* Color based on the Name.Constant (.no) class from pygments.css. */
|
||||
.param { color: #00afff }
|
||||
|
||||
/* Color based on the Name.Constant (.no) class from pygments.css. */
|
||||
/* Used for underlining file paths in interactive code examples. */
|
||||
.param-valid-path { color: #00afff; text-decoration: underline }
|
||||
|
||||
/* Color based on the Generic.Prompt (.gp) class from pygments.css. */
|
||||
.prompt { color: #8f5902 }
|
||||
|
||||
kbd {
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: .2em;
|
||||
box-shadow: 0.1em 0.1em 0.2em rgba(0,0,0,0.1);
|
||||
color: #000;
|
||||
padding: 0.1em 0.3em;
|
||||
}
|
||||
|
||||
539
doc_src/python_docs_theme/static/searchtools.js
Normal file
539
doc_src/python_docs_theme/static/searchtools.js
Normal file
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* searchtools.js
|
||||
* ~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Sphinx JavaScript utilities for the full-text search.
|
||||
*
|
||||
* :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
* This file taken for fish from sphinx 3.5.1 to add a special error message
|
||||
* that lists short builtins.
|
||||
*
|
||||
*/
|
||||
|
||||
if (!Scorer) {
|
||||
/**
|
||||
* Simple result scoring code.
|
||||
*/
|
||||
var Scorer = {
|
||||
// Implement the following function to further tweak the score for each result
|
||||
// The function takes a result array [filename, title, anchor, descr, score]
|
||||
// and returns the new score.
|
||||
/*
|
||||
score: function(result) {
|
||||
return result[4];
|
||||
},
|
||||
*/
|
||||
|
||||
// query matches the full name of an object
|
||||
objNameMatch: 11,
|
||||
// or matches in the last dotted part of the object name
|
||||
objPartialMatch: 6,
|
||||
// Additive scores depending on the priority of the object
|
||||
objPrio: {0: 15, // used to be importantResults
|
||||
1: 5, // used to be objectResults
|
||||
2: -5}, // used to be unimportantResults
|
||||
// Used when the priority is not in the mapping.
|
||||
objPrioDefault: 0,
|
||||
|
||||
// query found in title
|
||||
title: 15,
|
||||
partialTitle: 7,
|
||||
// query found in terms
|
||||
term: 5,
|
||||
partialTerm: 2
|
||||
};
|
||||
}
|
||||
|
||||
if (!splitQuery) {
|
||||
function splitQuery(query) {
|
||||
return query.split(/\s+/);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search Module
|
||||
*/
|
||||
var Search = {
|
||||
|
||||
_index : null,
|
||||
_queued_query : null,
|
||||
_pulse_status : -1,
|
||||
|
||||
htmlToText : function(htmlString) {
|
||||
var virtualDocument = document.implementation.createHTMLDocument('virtual');
|
||||
var htmlElement = $(htmlString, virtualDocument);
|
||||
htmlElement.find('.headerlink').remove();
|
||||
docContent = htmlElement.find('[role=main]')[0];
|
||||
if(docContent === undefined) {
|
||||
console.warn("Content block not found. Sphinx search tries to obtain it " +
|
||||
"via '[role=main]'. Could you check your theme or template.");
|
||||
return "";
|
||||
}
|
||||
return docContent.textContent || docContent.innerText;
|
||||
},
|
||||
|
||||
init : function() {
|
||||
var params = $.getQueryParameters();
|
||||
if (params.q) {
|
||||
var query = params.q[0];
|
||||
$('input[name="q"]')[0].value = query;
|
||||
this.performSearch(query);
|
||||
}
|
||||
},
|
||||
|
||||
loadIndex : function(url) {
|
||||
$.ajax({type: "GET", url: url, data: null,
|
||||
dataType: "script", cache: true,
|
||||
complete: function(jqxhr, textstatus) {
|
||||
if (textstatus != "success") {
|
||||
document.getElementById("searchindexloader").src = url;
|
||||
}
|
||||
}});
|
||||
},
|
||||
|
||||
setIndex : function(index) {
|
||||
var q;
|
||||
this._index = index;
|
||||
if ((q = this._queued_query) !== null) {
|
||||
this._queued_query = null;
|
||||
Search.query(q);
|
||||
}
|
||||
},
|
||||
|
||||
hasIndex : function() {
|
||||
return this._index !== null;
|
||||
},
|
||||
|
||||
deferQuery : function(query) {
|
||||
this._queued_query = query;
|
||||
},
|
||||
|
||||
stopPulse : function() {
|
||||
this._pulse_status = 0;
|
||||
},
|
||||
|
||||
startPulse : function() {
|
||||
if (this._pulse_status >= 0)
|
||||
return;
|
||||
function pulse() {
|
||||
var i;
|
||||
Search._pulse_status = (Search._pulse_status + 1) % 4;
|
||||
var dotString = '';
|
||||
for (i = 0; i < Search._pulse_status; i++)
|
||||
dotString += '.';
|
||||
Search.dots.text(dotString);
|
||||
if (Search._pulse_status > -1)
|
||||
window.setTimeout(pulse, 500);
|
||||
}
|
||||
pulse();
|
||||
},
|
||||
|
||||
/**
|
||||
* perform a search for something (or wait until index is loaded)
|
||||
*/
|
||||
performSearch : function(query) {
|
||||
// create the required interface elements
|
||||
this.out = $('#search-results');
|
||||
this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
|
||||
this.dots = $('<span></span>').appendTo(this.title);
|
||||
this.status = $('<p class="search-summary"> </p>').appendTo(this.out);
|
||||
this.output = $('<ul class="search"/>').appendTo(this.out);
|
||||
|
||||
$('#search-progress').text(_('Preparing search...'));
|
||||
this.startPulse();
|
||||
|
||||
// index already loaded, the browser was quick!
|
||||
if (this.hasIndex())
|
||||
this.query(query);
|
||||
else
|
||||
this.deferQuery(query);
|
||||
},
|
||||
|
||||
/**
|
||||
* execute search (requires search index to be loaded)
|
||||
*/
|
||||
query : function(query) {
|
||||
var i;
|
||||
|
||||
// stem the searchterms and add them to the correct list
|
||||
var stemmer = new Stemmer();
|
||||
var searchterms = [];
|
||||
var excluded = [];
|
||||
var hlterms = [];
|
||||
var tmp = splitQuery(query);
|
||||
var objectterms = [];
|
||||
for (i = 0; i < tmp.length; i++) {
|
||||
if (tmp[i] !== "") {
|
||||
objectterms.push(tmp[i].toLowerCase());
|
||||
}
|
||||
|
||||
if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i] === "") {
|
||||
// skip this "word"
|
||||
continue;
|
||||
}
|
||||
// stem the word
|
||||
var word = stemmer.stemWord(tmp[i].toLowerCase());
|
||||
// prevent stemmer from cutting word smaller than two chars
|
||||
if(word.length < 3 && tmp[i].length >= 3) {
|
||||
word = tmp[i];
|
||||
}
|
||||
var toAppend;
|
||||
// select the correct list
|
||||
if (word[0] == '-') {
|
||||
toAppend = excluded;
|
||||
word = word.substr(1);
|
||||
}
|
||||
else {
|
||||
toAppend = searchterms;
|
||||
hlterms.push(tmp[i].toLowerCase());
|
||||
}
|
||||
// only add if not already in the list
|
||||
if (!$u.contains(toAppend, word))
|
||||
toAppend.push(word);
|
||||
}
|
||||
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
|
||||
|
||||
// console.debug('SEARCH: searching for:');
|
||||
// console.info('required: ', searchterms);
|
||||
// console.info('excluded: ', excluded);
|
||||
|
||||
// prepare search
|
||||
var terms = this._index.terms;
|
||||
var titleterms = this._index.titleterms;
|
||||
|
||||
// array of [filename, title, anchor, descr, score]
|
||||
var results = [];
|
||||
$('#search-progress').empty();
|
||||
|
||||
// lookup as object
|
||||
for (i = 0; i < objectterms.length; i++) {
|
||||
var others = [].concat(objectterms.slice(0, i),
|
||||
objectterms.slice(i+1, objectterms.length));
|
||||
results = results.concat(this.performObjectSearch(objectterms[i], others));
|
||||
}
|
||||
|
||||
// lookup as search terms in fulltext
|
||||
results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms));
|
||||
|
||||
// let the scorer override scores with a custom scoring function
|
||||
if (Scorer.score) {
|
||||
for (i = 0; i < results.length; i++)
|
||||
results[i][4] = Scorer.score(results[i]);
|
||||
}
|
||||
|
||||
// now sort the results by score (in opposite order of appearance, since the
|
||||
// display function below uses pop() to retrieve items) and then
|
||||
// alphabetically
|
||||
results.sort(function(a, b) {
|
||||
var left = a[4];
|
||||
var right = b[4];
|
||||
if (left > right) {
|
||||
return 1;
|
||||
} else if (left < right) {
|
||||
return -1;
|
||||
} else {
|
||||
// same score: sort alphabetically
|
||||
left = a[1].toLowerCase();
|
||||
right = b[1].toLowerCase();
|
||||
return (left > right) ? -1 : ((left < right) ? 1 : 0);
|
||||
}
|
||||
});
|
||||
|
||||
// for debugging
|
||||
//Search.lastresults = results.slice(); // a copy
|
||||
//console.info('search results:', Search.lastresults);
|
||||
|
||||
// print the results
|
||||
var resultCount = results.length;
|
||||
function displayNextItem() {
|
||||
// results left, load the summary and display it
|
||||
var listItem = $('<li></li>');
|
||||
if (results.length) {
|
||||
var item = results.pop();
|
||||
var requestUrl = "";
|
||||
var linkUrl = "";
|
||||
if (DOCUMENTATION_OPTIONS.BUILDER === 'dirhtml') {
|
||||
// dirhtml builder
|
||||
var dirname = item[0] + '/';
|
||||
if (dirname.match(/\/index\/$/)) {
|
||||
dirname = dirname.substring(0, dirname.length-6);
|
||||
} else if (dirname == 'index/') {
|
||||
dirname = '';
|
||||
}
|
||||
requestUrl = DOCUMENTATION_OPTIONS.URL_ROOT + dirname;
|
||||
linkUrl = requestUrl;
|
||||
|
||||
} else {
|
||||
// normal html builders
|
||||
requestUrl = DOCUMENTATION_OPTIONS.URL_ROOT + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX;
|
||||
linkUrl = item[0] + DOCUMENTATION_OPTIONS.LINK_SUFFIX;
|
||||
}
|
||||
listItem.append($('<a/>').attr('href',
|
||||
linkUrl +
|
||||
highlightstring + item[2]).html(item[1]));
|
||||
if (item[3]) {
|
||||
listItem.append($('<span> (' + item[3] + ')</span>'));
|
||||
Search.output.append(listItem);
|
||||
setTimeout(function() {
|
||||
displayNextItem();
|
||||
}, 5);
|
||||
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
|
||||
$.ajax({url: requestUrl,
|
||||
dataType: "text",
|
||||
complete: function(jqxhr, textstatus) {
|
||||
var data = jqxhr.responseText;
|
||||
if (data !== '' && data !== undefined) {
|
||||
listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
|
||||
}
|
||||
Search.output.append(listItem);
|
||||
setTimeout(function() {
|
||||
displayNextItem();
|
||||
}, 5);
|
||||
}});
|
||||
} else {
|
||||
// no source available, just display title
|
||||
Search.output.append(listItem);
|
||||
setTimeout(function() {
|
||||
displayNextItem();
|
||||
}, 5);
|
||||
}
|
||||
}
|
||||
// search finished, update title and status message
|
||||
else {
|
||||
Search.stopPulse();
|
||||
Search.title.text(_('Search Results'));
|
||||
if (!resultCount) {
|
||||
Search.status.text(_('Your search did not match any documents. Unfortunately search does not work with short terms, so here are some commonly used short builtins:'));
|
||||
var shortbuiltins = {
|
||||
"and": "conditionally execute a command",
|
||||
"cd": "change directory",
|
||||
"end": "end a block of commands",
|
||||
"for": "perform a set of commands multiple times",
|
||||
"if": "conditionally execute a command",
|
||||
"or": "condtionally execute a command",
|
||||
"set": "display and change shell variables",
|
||||
};
|
||||
for (var sb in shortbuiltins) {
|
||||
var li = $('<li><a href="cmds/' + sb + '.html">' + sb + " - " + shortbuiltins[sb] + '</a></li>');
|
||||
Search.output.append(li);
|
||||
}
|
||||
} else {
|
||||
Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
|
||||
}
|
||||
Search.status.fadeIn(500);
|
||||
}
|
||||
}
|
||||
displayNextItem();
|
||||
},
|
||||
|
||||
/**
|
||||
* search for object names
|
||||
*/
|
||||
performObjectSearch : function(object, otherterms) {
|
||||
var filenames = this._index.filenames;
|
||||
var docnames = this._index.docnames;
|
||||
var objects = this._index.objects;
|
||||
var objnames = this._index.objnames;
|
||||
var titles = this._index.titles;
|
||||
|
||||
var i;
|
||||
var results = [];
|
||||
|
||||
for (var prefix in objects) {
|
||||
for (var name in objects[prefix]) {
|
||||
var fullname = (prefix ? prefix + '.' : '') + name;
|
||||
var fullnameLower = fullname.toLowerCase()
|
||||
if (fullnameLower.indexOf(object) > -1) {
|
||||
var score = 0;
|
||||
var parts = fullnameLower.split('.');
|
||||
// check for different match types: exact matches of full name or
|
||||
// "last name" (i.e. last dotted part)
|
||||
if (fullnameLower == object || parts[parts.length - 1] == object) {
|
||||
score += Scorer.objNameMatch;
|
||||
// matches in last name
|
||||
} else if (parts[parts.length - 1].indexOf(object) > -1) {
|
||||
score += Scorer.objPartialMatch;
|
||||
}
|
||||
var match = objects[prefix][name];
|
||||
var objname = objnames[match[1]][2];
|
||||
var title = titles[match[0]];
|
||||
// If more than one term searched for, we require other words to be
|
||||
// found in the name/title/description
|
||||
if (otherterms.length > 0) {
|
||||
var haystack = (prefix + ' ' + name + ' ' +
|
||||
objname + ' ' + title).toLowerCase();
|
||||
var allfound = true;
|
||||
for (i = 0; i < otherterms.length; i++) {
|
||||
if (haystack.indexOf(otherterms[i]) == -1) {
|
||||
allfound = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!allfound) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
var descr = objname + _(', in ') + title;
|
||||
|
||||
var anchor = match[3];
|
||||
if (anchor === '')
|
||||
anchor = fullname;
|
||||
else if (anchor == '-')
|
||||
anchor = objnames[match[1]][1] + '-' + fullname;
|
||||
// add custom score for some objects according to scorer
|
||||
if (Scorer.objPrio.hasOwnProperty(match[2])) {
|
||||
score += Scorer.objPrio[match[2]];
|
||||
} else {
|
||||
score += Scorer.objPrioDefault;
|
||||
}
|
||||
results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
|
||||
*/
|
||||
escapeRegExp : function(string) {
|
||||
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||
},
|
||||
|
||||
/**
|
||||
* search for full-text terms in the index
|
||||
*/
|
||||
performTermsSearch : function(searchterms, excluded, terms, titleterms) {
|
||||
var docnames = this._index.docnames;
|
||||
var filenames = this._index.filenames;
|
||||
var titles = this._index.titles;
|
||||
|
||||
var i, j, file;
|
||||
var fileMap = {};
|
||||
var scoreMap = {};
|
||||
var results = [];
|
||||
|
||||
// perform the search on the required terms
|
||||
for (i = 0; i < searchterms.length; i++) {
|
||||
var word = searchterms[i];
|
||||
var files = [];
|
||||
var _o = [
|
||||
{files: terms[word], score: Scorer.term},
|
||||
{files: titleterms[word], score: Scorer.title}
|
||||
];
|
||||
// add support for partial matches
|
||||
if (word.length > 2) {
|
||||
var word_regex = this.escapeRegExp(word);
|
||||
for (var w in terms) {
|
||||
if (w.match(word_regex) && !terms[word]) {
|
||||
_o.push({files: terms[w], score: Scorer.partialTerm})
|
||||
}
|
||||
}
|
||||
for (var w in titleterms) {
|
||||
if (w.match(word_regex) && !titleterms[word]) {
|
||||
_o.push({files: titleterms[w], score: Scorer.partialTitle})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no match but word was a required one
|
||||
if ($u.every(_o, function(o){return o.files === undefined;})) {
|
||||
break;
|
||||
}
|
||||
// found search word in contents
|
||||
$u.each(_o, function(o) {
|
||||
var _files = o.files;
|
||||
if (_files === undefined)
|
||||
return
|
||||
|
||||
if (_files.length === undefined)
|
||||
_files = [_files];
|
||||
files = files.concat(_files);
|
||||
|
||||
// set score for the word in each file to Scorer.term
|
||||
for (j = 0; j < _files.length; j++) {
|
||||
file = _files[j];
|
||||
if (!(file in scoreMap))
|
||||
scoreMap[file] = {};
|
||||
scoreMap[file][word] = o.score;
|
||||
}
|
||||
});
|
||||
|
||||
// create the mapping
|
||||
for (j = 0; j < files.length; j++) {
|
||||
file = files[j];
|
||||
if (file in fileMap && fileMap[file].indexOf(word) === -1)
|
||||
fileMap[file].push(word);
|
||||
else
|
||||
fileMap[file] = [word];
|
||||
}
|
||||
}
|
||||
|
||||
// now check if the files don't contain excluded terms
|
||||
for (file in fileMap) {
|
||||
var valid = true;
|
||||
|
||||
// check if all requirements are matched
|
||||
var filteredTermCount = // as search terms with length < 3 are discarded: ignore
|
||||
searchterms.filter(function(term){return term.length > 2}).length
|
||||
if (
|
||||
fileMap[file].length != searchterms.length &&
|
||||
fileMap[file].length != filteredTermCount
|
||||
) continue;
|
||||
|
||||
// ensure that none of the excluded terms is in the search result
|
||||
for (i = 0; i < excluded.length; i++) {
|
||||
if (terms[excluded[i]] == file ||
|
||||
titleterms[excluded[i]] == file ||
|
||||
$u.contains(terms[excluded[i]] || [], file) ||
|
||||
$u.contains(titleterms[excluded[i]] || [], file)) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have still a valid result we can add it to the result list
|
||||
if (valid) {
|
||||
// select one (max) score for the file.
|
||||
// for better ranking, we should calculate ranking by using words statistics like basic tf-idf...
|
||||
var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]}));
|
||||
results.push([docnames[file], titles[file], '', null, score, filenames[file]]);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* helper function to return a node containing the
|
||||
* search summary for a given text. keywords is a list
|
||||
* of stemmed words, hlwords is the list of normal, unstemmed
|
||||
* words. the first one is used to find the occurrence, the
|
||||
* latter for highlighting it.
|
||||
*/
|
||||
makeSearchSummary : function(htmlText, keywords, hlwords) {
|
||||
var text = Search.htmlToText(htmlText);
|
||||
var textLower = text.toLowerCase();
|
||||
var start = 0;
|
||||
$.each(keywords, function() {
|
||||
var i = textLower.indexOf(this.toLowerCase());
|
||||
if (i > -1)
|
||||
start = i;
|
||||
});
|
||||
start = Math.max(start - 120, 0);
|
||||
var excerpt = ((start > 0) ? '...' : '') +
|
||||
$.trim(text.substr(start, 240)) +
|
||||
((start + 240 - text.length) ? '...' : '');
|
||||
var rv = $('<div class="context"></div>').text(excerpt);
|
||||
$.each(hlwords, function() {
|
||||
rv = rv.highlightText(this, 'highlighted');
|
||||
});
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
Search.init();
|
||||
});
|
||||
@@ -1,194 +0,0 @@
|
||||
/*
|
||||
* sidebar.js
|
||||
* ~~~~~~~~~~
|
||||
*
|
||||
* This script makes the Sphinx sidebar collapsible and implements intelligent
|
||||
* scrolling. This is a slightly modified version of Sphinx's own sidebar.js.
|
||||
*
|
||||
* .sphinxsidebar contains .sphinxsidebarwrapper. This script adds in
|
||||
* .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton used to
|
||||
* collapse and expand the sidebar.
|
||||
*
|
||||
* When the sidebar is collapsed the .sphinxsidebarwrapper is hidden and the
|
||||
* width of the sidebar and the margin-left of the document are decreased.
|
||||
* When the sidebar is expanded the opposite happens. This script saves a
|
||||
* per-browser/per-session cookie used to remember the position of the sidebar
|
||||
* among the pages. Once the browser is closed the cookie is deleted and the
|
||||
* position reset to the default (expanded).
|
||||
*
|
||||
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
// global elements used by the functions.
|
||||
// the 'sidebarbutton' element is defined as global after its
|
||||
// creation, in the add_sidebar_button function
|
||||
var jwindow = $(window);
|
||||
var jdocument = $(document);
|
||||
var bodywrapper = $('.bodywrapper');
|
||||
var documentwrapper = $('.documentwrapper');
|
||||
var sidebar = $('.sphinxsidebar');
|
||||
var sidebarwrapper = $('.sphinxsidebarwrapper');
|
||||
|
||||
// original margin-left of the bodywrapper and width of the sidebar
|
||||
// with the sidebar expanded
|
||||
var bw_margin_expanded = bodywrapper.css('margin-left');
|
||||
var ssb_width_expanded = sidebar.width();
|
||||
|
||||
// margin-left of the bodywrapper and width of the sidebar
|
||||
// with the sidebar collapsed
|
||||
var bw_margin_collapsed = '.8em';
|
||||
var ssb_width_collapsed = '.8em';
|
||||
|
||||
// colors used by the current theme
|
||||
var dark_color = '#AAAAAA';
|
||||
var light_color = '#CCCCCC';
|
||||
|
||||
function get_viewport_height() {
|
||||
if (window.innerHeight)
|
||||
return window.innerHeight;
|
||||
else
|
||||
return jwindow.height();
|
||||
}
|
||||
|
||||
function sidebar_is_collapsed() {
|
||||
return sidebarwrapper.is(':not(:visible)');
|
||||
}
|
||||
|
||||
function toggle_sidebar() {
|
||||
if (sidebar_is_collapsed())
|
||||
expand_sidebar();
|
||||
else
|
||||
collapse_sidebar();
|
||||
// adjust the scrolling of the sidebar
|
||||
scroll_sidebar();
|
||||
}
|
||||
|
||||
function collapse_sidebar() {
|
||||
sidebarwrapper.hide();
|
||||
sidebar.css('width', ssb_width_collapsed);
|
||||
bodywrapper.css('margin-left', bw_margin_collapsed);
|
||||
sidebarbutton.css({
|
||||
'margin-left': '0',
|
||||
'height': documentwrapper.height(),
|
||||
'border-radius': '5px'
|
||||
});
|
||||
sidebarbutton.find('span').text('»');
|
||||
sidebarbutton.attr('title', _('Expand sidebar'));
|
||||
document.cookie = 'sidebar=collapsed';
|
||||
}
|
||||
|
||||
function expand_sidebar() {
|
||||
bodywrapper.css('margin-left', bw_margin_expanded);
|
||||
sidebar.css('width', ssb_width_expanded);
|
||||
sidebarwrapper.show();
|
||||
sidebarbutton.css({
|
||||
'margin-left': ssb_width_expanded-12,
|
||||
'height': Math.max(sidebarwrapper.height(), documentwrapper.height()),
|
||||
'border-radius': '0 5px 5px 0'
|
||||
});
|
||||
sidebarbutton.find('span').text('«');
|
||||
sidebarbutton.attr('title', _('Collapse sidebar'));
|
||||
//sidebarwrapper.css({'padding-top':
|
||||
// Math.max(window.pageYOffset - sidebarwrapper.offset().top, 10)});
|
||||
document.cookie = 'sidebar=expanded';
|
||||
}
|
||||
|
||||
function add_sidebar_button() {
|
||||
sidebarwrapper.css({
|
||||
'float': 'left',
|
||||
'margin-right': '0',
|
||||
'width': ssb_width_expanded - 28
|
||||
});
|
||||
// create the button
|
||||
sidebar.append(
|
||||
'<div id="sidebarbutton"><span>«</span></div>'
|
||||
);
|
||||
var sidebarbutton = $('#sidebarbutton');
|
||||
// find the height of the viewport to center the '<<' in the page
|
||||
var viewport_height = get_viewport_height();
|
||||
var sidebar_offset = sidebar.offset().top;
|
||||
var sidebar_height = Math.max(documentwrapper.height(), sidebar.height());
|
||||
sidebarbutton.find('span').css({
|
||||
'display': 'block',
|
||||
'position': 'fixed',
|
||||
'top': Math.min(viewport_height/2, sidebar_height/2 + sidebar_offset) - 10
|
||||
});
|
||||
|
||||
sidebarbutton.click(toggle_sidebar);
|
||||
sidebarbutton.attr('title', _('Collapse sidebar'));
|
||||
sidebarbutton.css({
|
||||
'border-radius': '0 5px 5px 0',
|
||||
'color': '#444444',
|
||||
'background-color': '#CCCCCC',
|
||||
'font-size': '1.2em',
|
||||
'cursor': 'pointer',
|
||||
'height': sidebar_height,
|
||||
'padding-top': '1px',
|
||||
'padding-left': '1px',
|
||||
'margin-left': ssb_width_expanded - 12
|
||||
});
|
||||
|
||||
sidebarbutton.hover(
|
||||
function () {
|
||||
$(this).css('background-color', dark_color);
|
||||
},
|
||||
function () {
|
||||
$(this).css('background-color', light_color);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function set_position_from_cookie() {
|
||||
if (!document.cookie)
|
||||
return;
|
||||
var items = document.cookie.split(';');
|
||||
for(var k=0; k<items.length; k++) {
|
||||
var key_val = items[k].split('=');
|
||||
var key = key_val[0];
|
||||
if (key == 'sidebar') {
|
||||
var value = key_val[1];
|
||||
if ((value == 'collapsed') && (!sidebar_is_collapsed()))
|
||||
collapse_sidebar();
|
||||
else if ((value == 'expanded') && (sidebar_is_collapsed()))
|
||||
expand_sidebar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_sidebar_button();
|
||||
var sidebarbutton = $('#sidebarbutton');
|
||||
set_position_from_cookie();
|
||||
|
||||
|
||||
/* intelligent scrolling */
|
||||
function scroll_sidebar() {
|
||||
var sidebar_height = sidebarwrapper.height();
|
||||
var viewport_height = get_viewport_height();
|
||||
var offset = sidebar.position()['top'];
|
||||
var wintop = jwindow.scrollTop();
|
||||
var winbot = wintop + viewport_height;
|
||||
var curtop = sidebarwrapper.position()['top'];
|
||||
var curbot = curtop + sidebar_height;
|
||||
// does sidebar fit in window?
|
||||
if (sidebar_height < viewport_height) {
|
||||
// yes: easy case -- always keep at the top
|
||||
sidebarwrapper.css('top', $u.min([$u.max([0, wintop - offset - 10]),
|
||||
jdocument.height() - sidebar_height - 200]));
|
||||
}
|
||||
else {
|
||||
// no: only scroll if top/bottom edge of sidebar is at
|
||||
// top/bottom edge of window
|
||||
if (curtop > wintop && curbot > winbot) {
|
||||
sidebarwrapper.css('top', $u.max([wintop - offset - 10, 0]));
|
||||
}
|
||||
else if (curtop < wintop && curbot < winbot) {
|
||||
sidebarwrapper.css('top', $u.min([winbot - sidebar_height - offset - 20,
|
||||
jdocument.height() - sidebar_height - 200]));
|
||||
}
|
||||
}
|
||||
}
|
||||
jwindow.scroll(scroll_sidebar);
|
||||
});
|
||||
2
po/fr.po
2
po/fr.po
@@ -3556,7 +3556,7 @@ msgstr ""
|
||||
|
||||
#: /tmp/fish/explicit/share/functions/cdh.fish:5
|
||||
msgid "Select directory by letter or number: "
|
||||
msgstr "Sélectionner un dossier par lettre ou chiffre"
|
||||
msgstr "Sélectionner un dossier par lettre ou chiffre : "
|
||||
|
||||
#: /tmp/fish/explicit/share/functions/cdh.fish:6
|
||||
msgid ""
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
|
||||
complete -c badblocks -s b -d 'Block-size Specify the size of blocks in bytes'
|
||||
complete -c badblocks -s c -d 'Number of blocks is the number of blocks which are tested at a time'
|
||||
complete -c badblocks -s f -d 'Normally, badblocks will refuse to do a read/write or a nondestructive test on a device which is mounted, since either can cause the system to potentially crash and/or damage the filesystem even if it is mounted read-only'
|
||||
complete -c badblocks -s f -d 'Execute test even when device is mounted (dangerous!)'
|
||||
complete -c badblocks -s i -d 'Input_file Read a list of already existing known bad blocks'
|
||||
complete -c badblocks -s o -d 'Output_file Write the list of bad blocks to the specified file'
|
||||
complete -c badblocks -s p -d 'Repeat scanning the disk until there are no new blocks discovered in specified number of consecutive scans of the disk'
|
||||
complete -c badblocks -s p -d 'Repeat until no new blocks are found in provided number of scans'
|
||||
complete -c badblocks -s t -d 'Test_pattern Specify a test pattern to be read (and written) to disk blocks'
|
||||
complete -c badblocks -s n -d 'Use non-destructive read-write mode'
|
||||
complete -c badblocks -s s -d 'Show the progress of the scan by writing out the block numbers as they are checked'
|
||||
complete -c badblocks -s s -d 'Show scan progress'
|
||||
complete -c badblocks -s v -d 'Verbose mode'
|
||||
complete -c badblocks -s w -d 'Use write-mode test'
|
||||
complete -c badblocks -s X -d 'Internal flag only to be used by e2fsck(8) and mke2fs(8)'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
complete -c curl -n 'string match -qr "^@" -- (commandline -ct)' -k -xa "(printf '%s\n' -- @(__fish_complete_suffix (commandline -ct | string replace -r '^@' '') ''))"
|
||||
|
||||
# These based on the autogenerated completions.
|
||||
complete -c curl -l abstract-unix-socket -d '(HTTP) Connect through an abstract Unix domain socket, instead of using the n…'
|
||||
complete -c curl -l abstract-unix-socket -d '(HTTP) Connect through an abstract Unix domain socket'
|
||||
complete -c curl -l anyauth -d '(HTTP) Use most secure authentication method automatically'
|
||||
complete -c curl -s a -l append -d '(FTP SFTP) Upload: append to the target file'
|
||||
complete -c curl -l basic -d '(HTTP) Use HTTP Basic authentication'
|
||||
@@ -65,12 +65,12 @@ complete -c curl -l ftp-ssl-control -d '(FTP) Require SSL/TLS for the FTP login,
|
||||
complete -c curl -s G -l get -d 'Use GET instead of POST'
|
||||
complete -c curl -s g -l globoff -d 'This option switches off the "URL globbing parser"'
|
||||
complete -c curl -l happy-eyeballs-timeout-ms -d 'Attempt to connect to both IPv4 and IPv6 in parallel'
|
||||
complete -c curl -l haproxy-protocol -d '(HTTP) Send a HAProxy PROXY protocol v1 header at the beginning of the connection'
|
||||
complete -c curl -l haproxy-protocol -d '(HTTP) Use HAProxy PROXY protocol'
|
||||
complete -c curl -s I -l head -d '(HTTP FTP FILE) Fetch the headers only'
|
||||
complete -c curl -s H -l header -d '(HTTP) Extra header to include in the request when sending HTTP to a server'
|
||||
complete -c curl -s h -l help -d 'Usage help'
|
||||
complete -c curl -l hostpubmd5 -d '(SFTP SCP) Pass a string containing 32 hexadecimal digits'
|
||||
complete -c curl -l 'http0.9' -d '(HTTP) Tells curl to be fine with HTTP version 0. 9 response. HTTP/0'
|
||||
complete -c curl -l 'http0.9' -d '(HTTP) Accept HTTP version 0.9 response'
|
||||
complete -c curl -s 0 -l 'http1.0' -d '(HTTP) Use HTTP version 1'
|
||||
complete -c curl -l 'http1.1' -d '(HTTP) Use HTTP version 1.1'
|
||||
complete -c curl -l http2-prior-knowledge -d '(HTTP) Use HTTP/2 immediately (without trying HTTP1)'
|
||||
@@ -129,83 +129,83 @@ complete -c curl -l proto-redir -d 'Limit what protocols it may use on redirect'
|
||||
# TODO: args
|
||||
complete -c curl -l proto -d 'Limit what protocols it may use in the transfer'
|
||||
complete -c curl -l proxy-anyauth -d 'Like --anyauth but for the proxy'
|
||||
complete -c curl -l proxy-basic -d 'Tells curl to use HTTP Basic authentication when communicating with the given…'
|
||||
complete -c curl -l proxy-basic -d 'Use HTTP Basic authentication to communicate with proxy'
|
||||
complete -c curl -l proxy-cacert -d 'Same as --cacert but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-capath -d 'Same as --capath but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-cert-type -d 'Same as --cert-type but used in HTTPS proxy context. Added in 7. 52. 0'
|
||||
complete -c curl -l proxy-cert -d 'Same as -E, --cert but used in HTTPS proxy context. Added in 7. 52. 0'
|
||||
complete -c curl -l proxy-ciphers -d 'Same as --ciphers but used in HTTPS proxy context. Added in 7. 52. 0'
|
||||
complete -c curl -l proxy-crlfile -d 'Same as --crlfile but used in HTTPS proxy context. Added in 7. 52. 0'
|
||||
complete -c curl -l proxy-digest -d 'Tells curl to use HTTP Digest authentication when communicating with the give…'
|
||||
complete -c curl -l proxy-cert-type -d 'Same as --cert-type but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-cert -d 'Same as -E, --cert but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-ciphers -d 'Same as --ciphers but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-crlfile -d 'Same as --crlfile but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-digest -d 'Use HTTP Digest authentication to communicate with proxy'
|
||||
complete -c curl -l proxy-header -d '(HTTP) Extra header to include in the request when sending HTTP to a proxy'
|
||||
complete -c curl -l proxy-insecure -d 'Same as -k, --insecure but used in HTTPS proxy context. Added in 7. 52. 0'
|
||||
complete -c curl -l proxy-key-type -d 'Same as --key-type but used in HTTPS proxy context. Added in 7. 52. 0'
|
||||
complete -c curl -l proxy-insecure -d 'Same as -k, --insecure but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-key-type -d 'Same as --key-type but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-key -d 'Same as --key but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-negotiate -d 'Tells curl to use HTTP Negotiate (SPNEGO) authentication when communicating w…'
|
||||
complete -c curl -l proxy-ntlm -d 'Tells curl to use HTTP NTLM authentication when communicating with the given …'
|
||||
complete -c curl -l proxy-pass -d 'Same as --pass but used in HTTPS proxy context. Added in 7. 52. 0'
|
||||
complete -c curl -l proxy-pinnedpubkey -d '(TLS) Tells curl to use the specified public key file (or hashes) to verify t…'
|
||||
complete -c curl -l proxy-negotiate -d 'Use HTTP Negotiate authentication to communicate with proxy'
|
||||
complete -c curl -l proxy-ntlm -d 'Use HTTP NTLM authentication when to communicate with proxy'
|
||||
complete -c curl -l proxy-pass -d 'Same as --pass but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-pinnedpubkey -d '(TLS) Use specified public key file or hashes to verify proxy'
|
||||
complete -c curl -l proxy-service-name -d 'This option allows you to change the service name for proxy negotiation'
|
||||
complete -c curl -l proxy-ssl-allow-beast -d 'Same as --ssl-allow-beast but used in HTTPS proxy context. Added in 7. 52'
|
||||
complete -c curl -l proxy-tls13-ciphers -d '(TLS) Specifies which cipher suites to use in the connection to your HTTPS pr…'
|
||||
complete -c curl -l proxy-tlsauthtype -d 'Same as --tlsauthtype but used in HTTPS proxy context. Added in 7. 52. 0'
|
||||
complete -c curl -l proxy-tlspassword -d 'Same as --tlspassword but used in HTTPS proxy context. Added in 7. 52. 0'
|
||||
complete -c curl -l proxy-tlsuser -d 'Same as --tlsuser but used in HTTPS proxy context. Added in 7. 52. 0'
|
||||
complete -c curl -l proxy-tlsv1 -d 'Same as -1, --tlsv1 but used in HTTPS proxy context. Added in 7. 52. 0'
|
||||
complete -c curl -l proxy-ssl-allow-beast -d 'Same as --ssl-allow-beast but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-tls13-ciphers -d '(TLS) Specify cipher suites for TLS 1.3 proxy connection'
|
||||
complete -c curl -l proxy-tlsauthtype -d 'Same as --tlsauthtype but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-tlspassword -d 'Same as --tlspassword but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-tlsuser -d 'Same as --tlsuser but used in HTTPS proxy context'
|
||||
complete -c curl -l proxy-tlsv1 -d 'Same as -1, --tlsv1 but used in HTTPS proxy context'
|
||||
complete -c curl -s U -l proxy-user -d 'Specify the user name and password to use for proxy authentication'
|
||||
complete -c curl -s x -l proxy -d 'Use the specified proxy'
|
||||
complete -c curl -l 'proxy1.0' -d 'Use the specified HTTP 1.0 proxy'
|
||||
complete -c curl -s p -l proxytunnel -d 'When an HTTP proxy is used -x, --proxy, this option will cause non-HTTP proto…'
|
||||
complete -c curl -s p -l proxytunnel -d 'If HTTP proxy is used, make curl tunnel through it'
|
||||
complete -c curl -l pubkey -d '(SFTP SCP) Public key file name'
|
||||
complete -c curl -s Q -l quote -d '(FTP SFTP) Send an arbitrary command to the remote FTP or SFTP server'
|
||||
complete -c curl -l random-file -d 'Specify the path name to file containing what will be considered as random da…'
|
||||
complete -c curl -s r -l range -d '(HTTP FTP SFTP FILE) Retrieve a byte range (i. e'
|
||||
complete -c curl -l random-file -d 'Specify file containing random data'
|
||||
complete -c curl -s r -l range -d '(HTTP FTP SFTP FILE) Retrieve a byte range'
|
||||
complete -c curl -o 500 -d 'specifies the last 500 bytes'
|
||||
complete -c curl -s 1 -d 'specifies the first and last byte only(*)(HTTP)'
|
||||
complete -c curl -l raw -d '(HTTP) When used, it disables all internal HTTP decoding of content or transf…'
|
||||
complete -c curl -l raw -d '(HTTP) Pass raw data (no HTTP decoding or transfer encoding)'
|
||||
complete -c curl -s e -l referer -d '(HTTP) Sends the "Referrer Page" information to the HTTP server'
|
||||
complete -c curl -s J -l remote-header-name -d '(HTTP) This option tells the -O, --remote-name option to use the server-speci…'
|
||||
complete -c curl -l remote-name-all -d 'This option changes the default action for all given URLs to be dealt with as…'
|
||||
complete -c curl -s J -l remote-header-name -d '(HTTP) Save output to filename from Content-Disposition'
|
||||
complete -c curl -l remote-name-all -d 'For every URL write output to local file by default'
|
||||
complete -c curl -s O -l remote-name -d 'Write output to a local file named like the remote file we get'
|
||||
complete -c curl -s R -l remote-time -d 'When used, this will make curl attempt to figure out the timestamp of the rem…'
|
||||
complete -c curl -l request-target -d '(HTTP) Tells curl to use an alternative "target" (path) instead of using the …'
|
||||
complete -c curl -s X -l request -d '(HTTP) Specifies a custom request method to use when communicating with the H…'
|
||||
complete -c curl -s R -l remote-time -d 'Use timestamp of remote file on output'
|
||||
complete -c curl -l request-target -d '(HTTP) Use an alternative request target'
|
||||
complete -c curl -s X -l request -d '(HTTP) Specifies a custom HTTP method'
|
||||
complete -c curl -l resolve -d 'Provide a custom address for a specific host and port pair'
|
||||
complete -c curl -l retry-connrefused -d 'In addition to the other conditions, consider ECONNREFUSED as a transient err…'
|
||||
complete -c curl -l retry-delay -d 'Make curl sleep this amount of time before each retry when a transfer has fai…'
|
||||
complete -c curl -l retry-connrefused -d 'Consider ECONNREFUSED a transient error'
|
||||
complete -c curl -l retry-delay -d 'Time to wait between transfer retries'
|
||||
complete -c curl -l retry-max-time -d 'The retry timer is reset before the first transfer attempt'
|
||||
complete -c curl -l retry -d 'If a transient error is returned when curl tries to perform a transfer, it wi…'
|
||||
complete -c curl -l sasl-ir -d 'Enable initial response in SASL authentication. Added in 7. 31. 0'
|
||||
complete -c curl -l retry -d 'Number of retries when transient error occurs'
|
||||
complete -c curl -l sasl-ir -d 'Enable initial response in SASL authentication'
|
||||
complete -c curl -l service-name -d 'This option allows you to change the service name for SPNEGO'
|
||||
complete -c curl -s S -l show-error -d 'When used with -s, --silent, it makes curl show an error message if it fails'
|
||||
complete -c curl -s s -l silent -d 'Silent or quiet mode. Don\'t show progress meter or error messages'
|
||||
complete -c curl -l socks4 -d 'Use the specified SOCKS4 proxy'
|
||||
complete -c curl -l socks4a -d 'Use the specified SOCKS4a proxy'
|
||||
complete -c curl -l socks5-basic -d 'Tells curl to use username/password authentication when connecting to a SOCKS…'
|
||||
complete -c curl -l socks5-basic -d 'Use username/password authentication to connect to SOCKS5 proxy'
|
||||
complete -c curl -l socks5-gssapi-nec -d 'As part of the GSS-API negotiation a protection mode is negotiated'
|
||||
complete -c curl -l socks5-gssapi-service -d 'The default service name for a socks server is rcmd/server-fqdn'
|
||||
complete -c curl -l socks5-gssapi -d 'Tells curl to use GSS-API authentication when connecting to a SOCKS5 proxy'
|
||||
complete -c curl -l socks5-hostname -d 'Use the specified SOCKS5 proxy (and let the proxy resolve the host name)'
|
||||
complete -c curl -l socks5 -d 'Use the specified SOCKS5 proxy - but resolve the host name locally'
|
||||
complete -c curl -s Y -l speed-limit -d 'If a download is slower than this given speed (in bytes per second) for speed…'
|
||||
complete -c curl -s y -l speed-time -d 'If a download is slower than speed-limit bytes per second during a speed-time…'
|
||||
complete -c curl -l ssl-allow-beast -d 'This option tells curl to not work around a security flaw in the SSL3 and TLS…'
|
||||
complete -c curl -s Y -l speed-limit -d 'Abort download if it\'s slower than given speed (Bps) for speed-time'
|
||||
complete -c curl -s y -l speed-time -d 'Abort download if it\'s slower than speed for given speed-time (s)'
|
||||
complete -c curl -l ssl-allow-beast -d 'Don\'t work around BEAST security flaw in SSL3 and TLS1.0'
|
||||
complete -c curl -l ssl-no-revoke -d '(Schannel) This option tells curl to disable certificate revocation checks'
|
||||
complete -c curl -l ssl-reqd -d '(FTP IMAP POP3 SMTP) Require SSL/TLS for the connection'
|
||||
complete -c curl -l ssl -d '(FTP IMAP POP3 SMTP) Try to use SSL/TLS for the connection'
|
||||
complete -c curl -s 2 -l sslv2 -d '(SSL) Forces curl to use SSL version 2 when negotiating with a remote SSL ser…'
|
||||
complete -c curl -s 3 -l sslv3 -d '(SSL) Forces curl to use SSL version 3 when negotiating with a remote SSL ser…'
|
||||
complete -c curl -s 2 -l sslv2 -d '(SSL) Use SSL version 2'
|
||||
complete -c curl -s 3 -l sslv3 -d '(SSL) Use SSL version 3'
|
||||
complete -c curl -l stderr -d 'Redirect all writes to stderr to the specified file instead'
|
||||
complete -c curl -l styled-output -d 'Enables the automatic use of bold font styles when writing HTTP headers to th…'
|
||||
complete -c curl -l suppress-connect-headers -d 'When -p, --proxytunnel is used and a CONNECT request is made don\'t output pro…'
|
||||
complete -c curl -l tcp-fastopen -d 'Enable use of TCP Fast Open (RFC7413). Added in 7. 49. 0'
|
||||
complete -c curl -l styled-output -d 'Use bold font styles when writing HTTP headers to terminal'
|
||||
complete -c curl -l suppress-connect-headers -d 'Don\'t print response headers for CONNECT request if -p is set'
|
||||
complete -c curl -l tcp-fastopen -d 'Enable use of TCP Fast Open'
|
||||
complete -c curl -l tcp-nodelay -d 'Turn on the TCP_NODELAY option'
|
||||
complete -c curl -s t -l telnet-option -d 'Pass options to the telnet protocol'
|
||||
complete -c curl -l tftp-blksize -d '(TFTP) Set TFTP BLKSIZE option (must be >512)'
|
||||
complete -c curl -l tftp-no-options -d '(TFTP) Tells curl not to send TFTP options requests'
|
||||
complete -c curl -s z -l time-cond -d '(HTTP FTP) Request a file that has been modified later than the given time an…'
|
||||
complete -c curl -s z -l time-cond -d '(HTTP FTP) Request file modified before or later than given time'
|
||||
complete -c curl -l tls-max -d '(SSL) VERSION defines maximum supported TLS version'
|
||||
complete -c curl -l tls13-ciphers -d '(TLS) Specifies which cipher suites to use in the connection if it negotiates…'
|
||||
complete -c curl -l tls13-ciphers -d '(TLS) Specifies cipher suites to use for TLS 1.3'
|
||||
complete -c curl -l tlsauthtype -d 'Set TLS authentication type'
|
||||
complete -c curl -l tlspassword -d 'Set password for use with the TLS authentication method'
|
||||
complete -c curl -l tlsuser -d 'Set username for use with the TLS authentication method'
|
||||
@@ -214,7 +214,7 @@ complete -c curl -l 'tlsv1.1' -d '(TLS) Forces curl to use TLS version 1.1'
|
||||
complete -c curl -l 'tlsv1.2' -d '(TLS) Forces curl to use TLS version 1.2'
|
||||
complete -c curl -l 'tlsv1.3' -d '(TLS) Forces curl to use TLS version 1.3'
|
||||
complete -c curl -l tlsv1 -d '(SSL) Tells curl to use at least TLS version 1'
|
||||
complete -c curl -l tr-encoding -d '(HTTP) Request a compressed Transfer-Encoding response using one of the algor…'
|
||||
complete -c curl -l tr-encoding -d '(HTTP) Request compressed Transfer-Encoding, uncompress on receive'
|
||||
complete -c curl -l trace-ascii -d 'Enables a full trace dump of all incoming and outgoing data'
|
||||
complete -c curl -l trace-time -d 'Prepends a time stamp to each trace or verbose line that curl displays'
|
||||
complete -c curl -l trace -d 'Enables a full trace dump of all incoming and outgoing data'
|
||||
|
||||
@@ -47,7 +47,7 @@ function __fish_git_recent_commits
|
||||
# Like __fish_git_commits, but not on all branches and limited to
|
||||
# the last 50 commits. Used for fixup, where only the current branch
|
||||
# and the latest commits make sense.
|
||||
__fish_git log --pretty=tformat:"%h"\t"%<(64,trunc)%s" --max-count=50 2>/dev/null
|
||||
__fish_git log --pretty=tformat:"%h"\t"%<(64,trunc)%s" --max-count=50 $argv 2>/dev/null
|
||||
end
|
||||
|
||||
function __fish_git_branches
|
||||
@@ -972,7 +972,7 @@ complete -k -f -c git -n '__fish_git_using_command checkout; and not contains --
|
||||
complete -k -f -c git -n '__fish_git_using_command checkout; and not contains -- -- (commandline -opc)' -a '(__fish_git_heads)' -d Head
|
||||
complete -k -f -c git -n '__fish_git_using_command checkout; and not contains -- -- (commandline -opc)' -a '(__fish_git_branches)'
|
||||
complete -k -f -c git -n '__fish_git_using_command checkout; and not contains -- -- (commandline -opc)' -a '(__fish_git_unique_remote_branches)' -d 'Unique Remote Branch'
|
||||
complete -k -f -c git -n '__fish_git_using_command checkout; and not contains -- -- (commandline -opc)' -a '(__fish_git_recent_commits)'
|
||||
complete -k -f -c git -n '__fish_git_using_command checkout; and not contains -- -- (commandline -opc)' -a '(__fish_git_recent_commits --all)'
|
||||
complete -k -f -c git -n '__fish_git_using_command checkout' -a '(__fish_git_files modified deleted)'
|
||||
complete -f -c git -n '__fish_git_using_command checkout' -s b -d 'Create a new branch'
|
||||
complete -f -c git -n '__fish_git_using_command checkout' -s t -l track -d 'Track a new branch'
|
||||
@@ -1505,6 +1505,7 @@ complete -f -c git -n __fish_git_needs_command -a rebase -d 'Forward-port local
|
||||
complete -f -c git -n '__fish_git_using_command rebase' -a '(__fish_git_remotes)' -d 'Remote alias'
|
||||
complete -f -c git -n '__fish_git_using_command rebase' -a '(__fish_git_branches)'
|
||||
complete -f -c git -n '__fish_git_using_command rebase' -a '(__fish_git_heads)' -d Head
|
||||
complete -f -c git -n '__fish_git_using_command rebase' -a '(__fish_git_recent_commits)'
|
||||
complete -f -c git -n '__fish_git_using_command rebase' -a '(__fish_git_tags)' -d Tag
|
||||
complete -f -c git -n '__fish_git_using_command rebase' -l continue -d 'Restart the rebasing process'
|
||||
complete -f -c git -n '__fish_git_using_command rebase' -l abort -d 'Abort the rebase operation'
|
||||
@@ -1922,8 +1923,8 @@ for file in $PATH/git-*
|
||||
and continue
|
||||
|
||||
complete -C "git-$subcommand " >/dev/null
|
||||
if [ (complete git-$subcommand | count) -gt 0 ]
|
||||
complete git -f -n "__fish_git_using_command $subcommand" -a "(__fish_git_complete_custom_command $subcommand)"
|
||||
if [ (complete -c git-$subcommand | count) -gt 0 ]
|
||||
complete -c git -f -n "__fish_git_using_command $subcommand" -a "(__fish_git_complete_custom_command $subcommand)"
|
||||
end
|
||||
set -a __fish_git_custom_commands_completion $subcommand
|
||||
end
|
||||
|
||||
12
share/completions/mkpasswd.fish
Normal file
12
share/completions/mkpasswd.fish
Normal file
@@ -0,0 +1,12 @@
|
||||
function __fish_mkpasswd_methods --description "Complete hashing methods for mkpasswd"
|
||||
mkpasswd -m help | tail -n +2 | string replace -r '^(\S+)\s+(\S.*)' '$1\t$2'
|
||||
echo -e "help\tList available methods"
|
||||
end
|
||||
|
||||
complete -c mkpasswd -f
|
||||
complete -c mkpasswd -s S -l salt -x -d 'Use given string as salt'
|
||||
complete -c mkpasswd -s R -l rounds -x -d 'Use given number of rounds'
|
||||
complete -c mkpasswd -s m -l method -xa "(__fish_mkpasswd_methods)" -d 'Compute the password using the given method'
|
||||
complete -c mkpasswd -s 5 -d 'Like --method=md5crypt'
|
||||
complete -c mkpasswd -s P -l password-fd -x -d 'Read the password from the given file descriptor'
|
||||
complete -c mkpasswd -s s -l stdin -d 'Read the password from stdin'
|
||||
@@ -24,7 +24,7 @@ complete -c msfdb -l db-port -x -d 'Database port'
|
||||
complete -c msfdb -l db-pool -x -d 'Database connection pool size'
|
||||
|
||||
# Web Service Options
|
||||
complete -c msfdb -s a -l address -x -a "(__fish_print_addresses)" -d 'Bind to host address'
|
||||
complete -c msfdb -s a -l address -x -a "(__fish_print_addresses --all)" -d 'Bind to host address'
|
||||
complete -c msfdb -s p -l port -x -d 'Web service port'
|
||||
complete -c msfdb -l ssl -d 'Enable SSL'
|
||||
complete -c msfdb -l no-ssl -d 'Disable SSL'
|
||||
|
||||
@@ -5,12 +5,12 @@ complete -c read -s P -l prompt-str -d "Set prompt using provided string" -x
|
||||
complete -c read -s x -l export -d "Export variable to subprocess"
|
||||
complete -c read -s g -l global -d "Make variable scope global"
|
||||
complete -c read -s l -l local -d "Make variable scope local"
|
||||
complete -c read -s U -l universal -d "Make variable scope universal, i.e. share variable with all the users fish processes on this computer"
|
||||
complete -c read -s U -l universal -d "Share variable with all the users fish processes on the computer"
|
||||
complete -c read -s u -l unexport -d "Do not export variable to subprocess"
|
||||
complete -c read -s m -l mode-name -d "Name to load/save history under" -r -a "read fish"
|
||||
complete -c read -s c -l command -d "Initial contents of read buffer when reading interactively" -r
|
||||
complete -c read -s S -l shell -d "Use syntax highlighting, tab completions and command termination suitable for entering shellscript code"
|
||||
complete -c read -s s -l silent -d "Secure mode: mask characters at the command line (suitable for passwords)"
|
||||
complete -c read -s S -l shell -d "Read like the shell would"
|
||||
complete -c read -s s -l silent -d "Mask input with ●"
|
||||
complete -c read -s n -l nchars -d "Read the specified number of characters" -x
|
||||
complete -c read -s a -l list -l array -d "Store the results as an array"
|
||||
complete -c read -s R -l right-prompt -d "Set right-hand prompt command" -x
|
||||
|
||||
@@ -2,8 +2,24 @@ function __rsync_remote_target
|
||||
commandline -ct | string match -r '.*::?(?:.*/)?' | string unescape
|
||||
end
|
||||
|
||||
function __rsync_parse_flags -d "Print info|help FLAGS from help output"
|
||||
set -l helptext $argv[2..-1] # Skips header line
|
||||
for line in $helptext
|
||||
set -l tokens (string match -r "([A-Z]+)(?: {2,})(.+)" $line)
|
||||
if test (count $tokens) -ge 3
|
||||
echo $tokens[2]\t$tokens[3]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
complete -c rsync -s v -l verbose -d "Increase verbosity"
|
||||
complete -c rsync -l info -d "Fine-grained informational verbosity" -xa "
|
||||
(__rsync_parse_flags (rsync --info=help))"
|
||||
complete -c rsync -l debug -d "Fine-grained debug verbosity" -xa "
|
||||
(__rsync_parse_flags (rsync --debug=help))"
|
||||
complete -c rsync -l stderr -xa 'errors all client' -d "change stderr output mode, default: errors"
|
||||
complete -c rsync -s q -l quiet -d "Suppress non-error messages"
|
||||
complete -c rsync -l no-motd -d "Suppress daemon-mode MOTD"
|
||||
complete -c rsync -s c -l checksum -d "Skip based on checksum, not mod-time & size"
|
||||
complete -c rsync -s a -l archive -d "Archive mode; same as -rlptgoD (no -H)"
|
||||
complete -c rsync -l no-OPTION -d "Turn off an implied OPTION (e.g. --no-D)"
|
||||
@@ -15,31 +31,42 @@ complete -c rsync -l backup-dir -xa '(__fish_complete_directories)' -d "Make bac
|
||||
complete -c rsync -l suffix -d "Backup suffix (default ~ w/o --backup-dir)"
|
||||
complete -c rsync -s u -l update -d "Skip files that are newer on the receiver"
|
||||
complete -c rsync -l inplace -d "Update destination files in-place"
|
||||
complete -c rsync -l append -d "Append data onto shorter files"
|
||||
complete -c rsync -l append -d "Append data onto shorter files without verifing old content"
|
||||
complete -c rsync -l append-verify -d "Append with full file checksum, including old data"
|
||||
complete -c rsync -s d -l dirs -d "Transfer directories without recursing"
|
||||
complete -c rsync -l mkpath -d "Create the destination's path component"
|
||||
complete -c rsync -s l -l links -d "Copy symlinks as symlinks"
|
||||
complete -c rsync -s L -l copy-links -d "Transform symlink into referent file/dir"
|
||||
complete -c rsync -l copy-unsafe-links -d "Only \"unsafe\" symlinks are transformed"
|
||||
complete -c rsync -l safe-links -d "Ignore symlinks that point outside the tree"
|
||||
complete -c rsync -l munge-links -d "Munge symlinks to make them safe & unusable"
|
||||
complete -c rsync -s k -l copy-dirlinks -d "Transform symlink to dir into referent dir"
|
||||
complete -c rsync -s K -l keep-dirlinks -d "Treat symlinked dir on receiver as dir"
|
||||
complete -c rsync -s H -l hard-links -d "Preserve hard links"
|
||||
complete -c rsync -s p -l perms -d "Preserve permissions"
|
||||
complete -c rsync -s E -l executability -d "Preserve executability"
|
||||
complete -c rsync -l chmod -d "Change destination permissions"
|
||||
complete -c rsync -s A -l acls -d "Preserve ACLs (implies -p) [non-standard]"
|
||||
complete -c rsync -s X -l xattrs -d "Preserve extended attrs (implies -p) [n.s.]"
|
||||
complete -c rsync -l chmod -d "Change destination permissions"
|
||||
complete -c rsync -s o -l owner -d "Preserve owner (super-user only)"
|
||||
complete -c rsync -s g -l group -d "Preserve group"
|
||||
complete -c rsync -l devices -d "Preserve device files (super-user only)"
|
||||
complete -c rsync -l specials -d "Preserve special files"
|
||||
complete -c rsync -s D -d "Same as --devices --specials"
|
||||
complete -c rsync -s t -l times -d "Preserve times"
|
||||
complete -c rsync -s t -l times -d "Preserve modification times"
|
||||
complete -c rsync -s U -l atimes -d "Preserve access (use) times"
|
||||
complete -c rsync -l open-noatime -d "Avoid changing the atime on opened files"
|
||||
complete -c rsync -l crtimes -d "Preserve creation (birth) times"
|
||||
complete -c rsync -s O -l omit-dir-times -d "Omit directories when preserving times"
|
||||
complete -c rsync -s J -l omit-link-times -d "Omit symlinks when preserving times"
|
||||
complete -c rsync -l super -d "Receiver attempts super-user activities"
|
||||
complete -c rsync -l fake-super -d "Store/recover privileged attrs using xattrs"
|
||||
complete -c rsync -s S -l sparse -d "Handle sparse files efficiently"
|
||||
complete -c rsync -l preallocate -d "Allocate dest files before writing them"
|
||||
complete -c rsync -l write-devices -d "Write to devices as files (implies --inplace)"
|
||||
complete -c rsync -s n -l dry-run -d "Show what would have been transferred"
|
||||
complete -c rsync -s W -l whole-file -d "Copy files whole (without rsync algorithm)"
|
||||
complete -c rsync -l cc -l checksum-choice -xa 'xxh128 xxh3 xxh64 md5 md4 none' -d "Choose the checksum algorithm"
|
||||
complete -c rsync -s x -l one-file-system -d "Don’t cross filesystem boundaries"
|
||||
complete -c rsync -s B -l block-size -x -d "Force a fixed checksum block-size"
|
||||
complete -c rsync -s e -l rsh -x -d "Specify the remote shell to use"
|
||||
@@ -52,19 +79,27 @@ complete -c rsync -l del -d "An alias for --delete-during"
|
||||
complete -c rsync -l delete -d "Delete files that don’t exist on sender"
|
||||
complete -c rsync -l delete-before -d "Receiver deletes before transfer (default)"
|
||||
complete -c rsync -l delete-during -d "Receiver deletes during xfer, not before"
|
||||
complete -c rsync -l delete-delay -d "Find deletions during, delete after"
|
||||
complete -c rsync -l delete-after -d "Receiver deletes after transfer, not before"
|
||||
complete -c rsync -l delete-excluded -d "Also delete excluded files on receiver"
|
||||
complete -c rsync -l ignore-missing-args -d "Ignore missing source args without error"
|
||||
complete -c rsync -l delete-missing-args -d "Delete missing source args from destination"
|
||||
complete -c rsync -l ignore-errors -d "Delete even if there are I/O errors"
|
||||
complete -c rsync -l force -d "Force deletion of dirs even if not empty"
|
||||
complete -c rsync -l max-delete -xa '(seq 0 10)' -d "Don’t delete more than NUM files"
|
||||
complete -c rsync -l max-size -xa '(seq 0 10){K,M,G}' -d "Don’t transfer any file larger than SIZE"
|
||||
complete -c rsync -l min-size -xa '(seq 0 10){K,M,G}' -d "Don’t transfer any file smaller than SIZE"
|
||||
complete -c rsync -l max-alloc -xa '(seq 0 10){K,M,G}' -d "Change process memory allocation limit"
|
||||
complete -c rsync -l partial -d "Keep partially transferred files"
|
||||
complete -c rsync -l partial-dir -xa '(__fish_complete_directories)' -d "Put a partially transferred file into DIR"
|
||||
complete -c rsync -l delay-updates -d "Put all updated files into place at end"
|
||||
complete -c rsync -s m -l prune-empty-dirs -d "Prune empty directory chains from file-list"
|
||||
complete -c rsync -l numeric-ids -d "Don’t map uid/gid values by user/group name"
|
||||
complete -c rsync -l usermap -xa '(__fish_complete_users)' -d "Custom username mapping"
|
||||
complete -c rsync -l groupmap -xa '(__fish_complete_groups)' -d "Custom username mapping"
|
||||
complete -c rsync -l chown -xa '(__fish_complete_users;__fish_complete_groups)' -d "Combined username/groupname mapping"
|
||||
complete -c rsync -l timeout -d "Set I/O timeout in seconds"
|
||||
complete -c rsync -l cotimeout -d "Set daemon connection timeout in seconds"
|
||||
complete -c rsync -s I -l ignore-times -d "Don’t skip files that match size and time"
|
||||
complete -c rsync -l size-only -d "Skip files that match in size"
|
||||
complete -c rsync -l modify-window -xa '(seq 0 10)' -d "Compare NUM mod-times with reduced accuracy"
|
||||
@@ -74,7 +109,9 @@ complete -c rsync -l compare-dest -xa '(__fish_complete_directories)' -d "Also c
|
||||
complete -c rsync -l copy-dest -xa '(__fish_complete_directories)' -d "Also compare received files relative to DIR and include copies of unchanged files"
|
||||
complete -c rsync -l link-dest -xa '(__fish_complete_directories)' -d "Hardlink to files in DIR when unchanged"
|
||||
complete -c rsync -s z -l compress -d "Compress file data during the transfer"
|
||||
complete -c rsync -l compress-level -d "Explicitly set compression level"
|
||||
complete -c rsync -l zc -l compress-choice -xa 'zstd lz4 zlibx zlib none' -d "Choose the compression algorithm"
|
||||
complete -c rsync -l compress-level -x -d "Explicitly set compression level (aka --zl)"
|
||||
complete -c rsync -l skip-compress -x -d "Skip compressing files with suffix in LIST"
|
||||
complete -c rsync -s C -l cvs-exclude -d "Auto-ignore files in the same way CVS does"
|
||||
complete -c rsync -s f -l filter -d "Add a file-filtering RULE"
|
||||
complete -c rsync -s F -d "Same as --filter=’dir-merge /.rsync-filter’ repeated: --filter='- .rsync-filter'"
|
||||
@@ -84,29 +121,43 @@ complete -c rsync -l include -d "Don’t exclude files matching PATTERN"
|
||||
complete -c rsync -l include-from -r -d "Read include patterns from FILE"
|
||||
complete -c rsync -l files-from -r -d "Read list of source-file names from FILE"
|
||||
complete -c rsync -s 0 -l from0 -d "All *from/filter files are delimited by 0s"
|
||||
complete -c rsync -s s -l protect-args -d "No space-splitting; wildcard chars only"
|
||||
complete -c rsync -l copy-as -xa '(__fish_complete_users;__fish_complete_groups)' -d "Specify user & optional group for the copy"
|
||||
complete -c rsync -l address -d "Bind address for outgoing socket to daemon"
|
||||
complete -c rsync -l port -d "Specify double-colon alternate port number"
|
||||
complete -c rsync -l sockopts -d "Specify custom TCP options"
|
||||
complete -c rsync -l blocking-io -d "Use blocking I/O for the remote shell"
|
||||
complete -c rsync -l outbuf -xa 'N L B' -d "Set out buffering to None, Line, or Block"
|
||||
complete -c rsync -l stats -d "Give some file-transfer stats"
|
||||
complete -c rsync -s 8 -l 8-bit-output -d "Leave high-bit chars unescaped in output"
|
||||
complete -c rsync -s h -l human-readable -d "Output numbers in a human-readable format"
|
||||
complete -c rsync -l progress -d "Show progress during transfer"
|
||||
complete -c rsync -s P -d "Same as --partial --progress"
|
||||
complete -c rsync -s i -l itemize-changes -d "Output a change-summary for all updates"
|
||||
complete -c rsync -l log-format -x -d "Output filenames using the specified format"
|
||||
complete -c rsync -l password-file -x -d "Read password from FILE"
|
||||
complete -c rsync -s M -l remote-option -d "Send OPTION to the remote side only"
|
||||
complete -c rsync -l out-format -x -d "Output updates using the specified FORMAT"
|
||||
complete -c rsync -l log-file -d "log what we're doing to the specified FILE"
|
||||
complete -c rsync -l log-file-format -x -d "log updates using the specified FMT"
|
||||
complete -c rsync -l password-file -r -d "Read password from FILE"
|
||||
complete -c rsync -l early-input -d "Use FILE for daemon's early exec input"
|
||||
complete -c rsync -l list-only -d "List the files instead of copying them"
|
||||
complete -c rsync -l bwlimit -x -d "Limit I/O bandwidth; KBytes per second"
|
||||
complete -c rsync -l write-batch -x -d "Write a batched update to FILE"
|
||||
complete -c rsync -l bwlimit -xa '(seq 0 10){K,M,G}' -d "Limit I/O bandwidth; optional unit (KB/s default)"
|
||||
complete -c rsync -l stop-after -x -d "Stop rsync after MINS minutes have elapsed"
|
||||
complete -c rsync -l stop-at -x -d "Stop rsync at the specified point in time"
|
||||
complete -c rsync -l write-batch -r -d "Write a batched update to FILE"
|
||||
complete -c rsync -l only-write-batch -d "Like --write-batch but w/o updating dest"
|
||||
complete -c rsync -l read-batch -x -d "Read a batched update from FILE"
|
||||
complete -c rsync -l read-batch -r -d "Read a batched update from FILE"
|
||||
complete -c rsync -l protocol -x -d "Force an older protocol version to be used"
|
||||
complete -c rsync -l iconv -x -d "Request charset conversion of filenames"
|
||||
complete -c rsync -l checksum-seed -x -d "Set block/file checksum seed (advanced)"
|
||||
complete -c rsync -s 4 -l ipv4 -d "Prefer IPv4"
|
||||
complete -c rsync -s 6 -l ipv6 -d "Prefer IPv6"
|
||||
complete -c rsync -l version -d "Display version and exit"
|
||||
complete -c rsync -l help -d "Display help and exit"
|
||||
complete -c rsync -l daemon -d "Run as an rsync daemon"
|
||||
complete -c rsync -l config -r -d "Specify alternate rsyncd.conf file"
|
||||
complete -c rsync -l dparam -x -d "Override global daemon config parameter"
|
||||
complete -c rsync -l no-detach -x -d "Do not detach from the parent"
|
||||
complete -c rsync -s V -l version -d "Display version and feature info"
|
||||
complete -c rsync -s h -l help -d "Display help and exit"
|
||||
|
||||
#
|
||||
# Hostname completion
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
complete source -k -xa '(__fish_complete_suffix .fish)'
|
||||
complete source -s h -l help -d 'Display help and exit'
|
||||
complete -c source -k -xa '(__fish_complete_suffix .fish)'
|
||||
complete -c source -s h -l help -d 'Display help and exit'
|
||||
|
||||
@@ -18,19 +18,7 @@ complete -c ssh -n 'test (__fish_number_of_cmd_args_wo_opts) -ge 2' -d "Command
|
||||
complete -c ssh -s a -d "Disables forwarding of the authentication agent"
|
||||
complete -c ssh -s A -d "Enables forwarding of the authentication agent"
|
||||
|
||||
|
||||
function __ssh_print_local_addresses_with_labels
|
||||
if command -sq ip
|
||||
command ip --oneline address | string replace -r '\d+:\s+(\S+)\s+\S+\s+(.+)/.*' '$2\t$1'
|
||||
else if command -sq ifconfig
|
||||
# This is for OSX/BSD/anything else that doesn't have `ip` installed.
|
||||
# Since ifconfig output is not guaranteed to be the same on these systems,
|
||||
# for now we will limit the completions to just the IP address.
|
||||
# TODO: check ifconfig output on each system and rework below to include label.
|
||||
ifconfig | awk '/^\tinet/ { print $2 } '
|
||||
end
|
||||
end
|
||||
complete -x -c ssh -s b -d "Local address to bind to" -a '(__ssh_print_local_addresses_with_labels)'
|
||||
complete -x -c ssh -s b -d "Local address to bind to" -a '(__fish_print_addresses)'
|
||||
|
||||
complete -x -c ssh -s e -d "Escape character" -a "\^ none"
|
||||
complete -c ssh -s f -d "Go to background"
|
||||
|
||||
@@ -10,13 +10,13 @@ complete -c useradd -s d -l home -d 'Home directory for the new user' -x -a '(__
|
||||
complete -c useradd -s G -l groups -d 'Supplementary groups' -xa '(__fish_append , (string split -f1 : /etc/group))'
|
||||
complete -c useradd -s h -l help -d 'Display help message and exit'
|
||||
complete -c useradd -s m -l create-home -d 'The user\'s home directory will be created if it does not exist'
|
||||
complete -c useradd -s n -d 'A group having the same name as the user being added to the system will be created by default (when -g is not specified)'
|
||||
complete -c useradd -s n -d 'Create group with name of added user if -g is not specified'
|
||||
complete -c useradd -s K -l key -d 'Overrides default key/value pairs from /etc/login'
|
||||
complete -c useradd -s o -l non-unique -d 'Allow the creation of a user account with a duplicate (non-unique) UID'
|
||||
complete -c useradd -s o -l non-unique -d 'Allow user account with a duplicate UID'
|
||||
complete -c useradd -s p -l password -d 'The encrypted password, as returned by crypt(3)' -r
|
||||
complete -c useradd -s u -l uid -d 'The numerical value of the user\'s ID' -r
|
||||
complete -c useradd -s b -l base-dir -d 'The initial path prefix for a new user\'s home directory' -r -a '(__fish_complete_directories)'
|
||||
complete -c useradd -s e -l expiredate -d 'The date on which the user account is disabled' -r
|
||||
complete -c useradd -s f -l inactive -d 'The number of days after a password has expired before the account will be disabled' -r
|
||||
complete -c useradd -s f -l inactive -d 'Number of days to disable account after password expiration' -r
|
||||
complete -c useradd -s g -l gid -d 'The group name or ID for a new user\'s initial group' -x -a '(string match -r "^[^#].*" < /etc/group | string split -f1,3 ":" | string join ":" | string replace -a ":" \n)'
|
||||
complete -c useradd -s s -l shell -d 'Name of the new user\'s login shell' -x -a '(string match -r "^[^#].*" < /etc/shells)'
|
||||
|
||||
@@ -30,13 +30,13 @@ function __fish_apropos
|
||||
set age (math (date +%s) - (/usr/bin/stat -f %m $db))
|
||||
end
|
||||
|
||||
MANPATH="$cache" apropos $argv
|
||||
MANPATH="$cache" apropos -- $argv
|
||||
|
||||
if test $age -ge $max_age
|
||||
mkdir -m 700 -p $cache
|
||||
/usr/libexec/makewhatis -o $db (man --path | string split :) >/dev/null 2>&1 </dev/null &
|
||||
end
|
||||
else
|
||||
apropos $argv
|
||||
apropos -- $argv
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,7 +16,7 @@ function __fish_complete_bittorrent
|
||||
complete -c $argv -l timeout_check_interval -x --description "Time between checking timeouts"
|
||||
complete -c $argv -l max_slice_length -x --description "Maximum outgoing slice length"
|
||||
complete -c $argv -l max_rate_period -x --description "Maximum time to guess rate"
|
||||
complete -c $argv -l bind -x --description "IP to bind to locally" -a "(__fish_print_addresses)"
|
||||
complete -c $argv -l bind -x --description "IP to bind to locally" -a "(__fish_print_addresses --all)"
|
||||
complete -c $argv -l display_interval -x --description "Time between screen updates"
|
||||
complete -c $argv -l rerequest_interval -x --description "Time to wait between requesting more peers"
|
||||
complete -c $argv -l min_peers -x --description "Minimum number of peers to not do requesting"
|
||||
|
||||
@@ -109,21 +109,6 @@ function __fish_config_interactive -d "Initializations that should be performed
|
||||
fish_greeting
|
||||
end
|
||||
|
||||
#
|
||||
# This event handler makes sure the prompt is repainted when
|
||||
# fish_color_cwd{,_root} changes value. Like all event handlers, it can't be
|
||||
# autoloaded.
|
||||
#
|
||||
set -l varargs --on-variable fish_key_bindings
|
||||
for var in user host{,_remote} cwd{,_root} status error
|
||||
set -a varargs --on-variable fish_color_$var
|
||||
end
|
||||
function __fish_repaint $varargs -d "Event handler, repaints the prompt when fish_color_cwd* changes"
|
||||
if status --is-interactive
|
||||
commandline -f repaint 2>/dev/null
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Completions for SysV startup scripts. These aren't bound to any
|
||||
# specific command, so they can't be autoloaded.
|
||||
|
||||
@@ -11,7 +11,7 @@ end
|
||||
|
||||
function __fish_describe_command -d "Command used to find descriptions for commands"
|
||||
# $argv will be inserted directly into the awk regex, so it must be escaped
|
||||
set -l argv_regex (string escape --style=regex "$argv")
|
||||
set -l argv_regex (string escape --style=regex -- "$argv")
|
||||
__fish_apropos $argv 2>/dev/null | awk -v FS=" +- +" '{
|
||||
split($1, names, ", ");
|
||||
for (name in names)
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
function __fish_print_addresses --description "Print a list of known network addresses"
|
||||
function __fish_print_addresses --description "List own network addresses with interface as description"
|
||||
# if --all is given, also print 0.0.0.0 and ::
|
||||
if contains -- --all $argv
|
||||
echo -e "0.0.0.0\tall"
|
||||
echo -e "::\tall"
|
||||
end
|
||||
if command -sq ip
|
||||
command ip --oneline address | string replace -r '(\S+\s+){3}(.+)/.*' '$2'
|
||||
command ip --oneline address | string replace -r '^\d+:\s+(\S+)\s+inet6?\s+([^\s/]+).*' '$2\t$1'
|
||||
else if command -sq ifconfig
|
||||
# This is for OSX/BSD
|
||||
# There's also linux ifconfig but that has at least two different output formats
|
||||
|
||||
@@ -10,7 +10,7 @@ function __fish_print_help --description "Print help message for the specified f
|
||||
|
||||
# Do nothing if the file does not exist
|
||||
if not test -e "$__fish_data_dir/man/man1/$item.1" -o -e "$__fish_data_dir/man/man1/$item.1.gz"
|
||||
return
|
||||
return 2
|
||||
end
|
||||
|
||||
# Render help output, save output into the variable 'help'
|
||||
|
||||
@@ -15,7 +15,7 @@ function __fish_print_pipestatus --description "Print pipestatus for prompt"
|
||||
|
||||
if not set -q argv[1]
|
||||
echo error: missing argument >&2
|
||||
status print-stacktrace >&2
|
||||
status print-stack-trace >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
@@ -28,8 +28,10 @@ function __fish_print_pipestatus --description "Print pipestatus for prompt"
|
||||
if test "$last_status" -ne "$argv[-1]"
|
||||
set last_status_string " "$status_color$last_status
|
||||
end
|
||||
printf "%s" $brace_sep_color $left_brace \
|
||||
set -l normal (set_color normal)
|
||||
# The "normal"s are to reset modifiers like bold - see #7771.
|
||||
printf "%s" $normal $brace_sep_color $left_brace \
|
||||
$status_color $last_pipestatus_string \
|
||||
$brace_sep_color $right_brace $last_status_string (set_color normal)
|
||||
$normal $brace_sep_color $right_brace $normal $last_status_string $normal
|
||||
end
|
||||
end
|
||||
|
||||
@@ -63,7 +63,7 @@ function fish_add_path --description "Add paths to the PATH"
|
||||
set -l newvar $$var
|
||||
if set -q _flag_move; and set -q indexes[1]
|
||||
# We remove in one step, so the indexes don't move.
|
||||
set -e newvar[$indexes]
|
||||
set -e newvar["$indexes"]
|
||||
end
|
||||
set $mode newvar $newpaths
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ function fish_clipboard_paste
|
||||
# in order to turn it into a single literal token.
|
||||
#
|
||||
# This eases pasting non-code (e.g. markdown or git commitishes).
|
||||
set -l quote_state (__fish_tokenizer_state -- (commandline -ct))
|
||||
set -l quote_state (__fish_tokenizer_state -- (commandline -ct | string collect))
|
||||
if contains -- $quote_state single single-escaped
|
||||
if status test-feature regex-easyesc
|
||||
set data (string replace -ra "(['\\\])" '\\\\$1' -- $data)
|
||||
|
||||
@@ -68,5 +68,9 @@ else if type -q pacman
|
||||
__fish_default_command_not_found_handler $argv[1]
|
||||
pacman -F $paths
|
||||
end
|
||||
else
|
||||
# Use standard fish command not found handler otherwise
|
||||
function fish_command_not_found --on-event fish_command_not_found
|
||||
__fish_default_command_not_found_handler $argv
|
||||
end
|
||||
end
|
||||
# Use standard fish command not found handler otherwise
|
||||
|
||||
@@ -766,7 +766,7 @@ set -l varargs
|
||||
for var in repaint describe_style show_informative_status use_informative_chars showdirtystate showstashstate showuntrackedfiles showupstream
|
||||
set -a varargs --on-variable __fish_git_prompt_$var
|
||||
end
|
||||
function __fish_git_prompt_repaint $varargs --description "Event handler, repaints prompt when functionality changes"
|
||||
function __fish_git_prompt_reset $varargs --description "Event handler, resets prompt when functionality changes"
|
||||
if status --is-interactive
|
||||
if contains -- $argv[3] __fish_git_prompt_show_informative_status __fish_git_prompt_use_informative_chars
|
||||
# Clear characters that have different defaults with/without informative status
|
||||
@@ -776,8 +776,6 @@ function __fish_git_prompt_repaint $varargs --description "Event handler, repain
|
||||
# Clear init so we reset the chars next time.
|
||||
set -e ___fish_git_prompt_init
|
||||
end
|
||||
|
||||
commandline -f repaint 2>/dev/null
|
||||
end
|
||||
end
|
||||
|
||||
@@ -786,7 +784,7 @@ for var in '' _prefix _suffix _bare _merging _cleanstate _invalidstate _upstream
|
||||
set -a varargs --on-variable __fish_git_prompt_color$var
|
||||
end
|
||||
set -a varargs --on-variable __fish_git_prompt_showcolorhints
|
||||
function __fish_git_prompt_repaint_color $varargs --description "Event handler, repaints prompt when any color changes"
|
||||
function __fish_git_prompt_reset_color $varargs --description "Event handler, resets prompt when any color changes"
|
||||
if status --is-interactive
|
||||
set -e ___fish_git_prompt_init
|
||||
set -l var $argv[3]
|
||||
@@ -799,7 +797,6 @@ function __fish_git_prompt_repaint_color $varargs --description "Event handler,
|
||||
set -e ___fish_git_prompt_color_{$name}_done
|
||||
end
|
||||
end
|
||||
commandline -f repaint 2>/dev/null
|
||||
end
|
||||
end
|
||||
|
||||
@@ -807,10 +804,9 @@ set -l varargs
|
||||
for var in cleanstate dirtystate invalidstate stagedstate stashstate stateseparator untrackedfiles upstream_ahead upstream_behind upstream_diverged upstream_equal upstream_prefix
|
||||
set -a varargs --on-variable __fish_git_prompt_char_$var
|
||||
end
|
||||
function __fish_git_prompt_repaint_char $varargs --description "Event handler, repaints prompt when any char changes"
|
||||
function __fish_git_prompt_reset_char $varargs --description "Event handler, resets prompt when any char changes"
|
||||
if status --is-interactive
|
||||
set -e ___fish_git_prompt_init
|
||||
set -e _$argv[3]
|
||||
commandline -f repaint 2>/dev/null
|
||||
end
|
||||
end
|
||||
|
||||
@@ -130,7 +130,7 @@ function funced --description 'Edit function definition'
|
||||
end
|
||||
|
||||
set -l stat $status
|
||||
rm $tmpname >/dev/null
|
||||
command rm $tmpname >/dev/null
|
||||
and rmdir $tmpdir >/dev/null
|
||||
return $stat
|
||||
end
|
||||
|
||||
@@ -94,7 +94,7 @@ function help --description 'Show help for the fish shell'
|
||||
|
||||
if not set -q fish_browser[1]
|
||||
printf (_ '%s: Could not find a web browser.\n') help
|
||||
printf (_ 'Please set the variable $BROWSER or fish_help_browser and try again.\n\n')
|
||||
printf (_ 'Please try `BROWSER=some_browser help`, `man fish-doc`, or `man fish-tutorial`.\n\n')
|
||||
return 1
|
||||
end
|
||||
|
||||
@@ -142,12 +142,20 @@ function help --description 'Show help for the fish shell'
|
||||
set fish_help_page "index.html#$fish_help_item"
|
||||
end
|
||||
|
||||
# In Crostini Chrome OS Linux, the default browser opens URLs in Chrome running outside the
|
||||
# linux VM. This browser does not have access to the Linux filesystem. This uses Garcon, see e.g.
|
||||
# https://chromium.googlesource.com/chromiumos/platform2/+/master/vm_tools/garcon/#opening-urls
|
||||
# https://source.chromium.org/search?q=garcon-url-handler
|
||||
string match -q '*garcon-url-handler*' $fish_browser[1]
|
||||
and set -l chromeos_linux_garcon
|
||||
|
||||
set -l page_url
|
||||
if test -f $__fish_help_dir/index.html
|
||||
if test -f $__fish_help_dir/index.html; and not set -lq chromeos_linux_garcon
|
||||
# Help is installed, use it
|
||||
set page_url file://$__fish_help_dir/$fish_help_page
|
||||
|
||||
# For Windows (Cygwin, msys2 and WSL), we need to convert the base help dir to a Windows path before converting it to a file URL
|
||||
# For Windows (Cygwin, msys2 and WSL), we need to convert the base
|
||||
# help dir to a Windows path before converting it to a file URL
|
||||
# but only if a Windows browser is being used
|
||||
if type -q cygpath
|
||||
and string match -qr '(cygstart|\.exe)(\s+|$)' $fish_browser[1]
|
||||
|
||||
@@ -2,13 +2,16 @@ body {
|
||||
background: linear-gradient(to bottom, #a7cfdf 0%, #23538a 100%);
|
||||
font-family: monospace, fixed;
|
||||
color: #222;
|
||||
min-height: 100vh; /* at least 1 screen high - to prevent the gradient from running out on a short tab */
|
||||
}
|
||||
|
||||
#ancestor {
|
||||
width: 90%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
-moz-box-shadow: 0 0 1px 1px #333;
|
||||
-webkit-box-shadow: 0 0 1px 1px #333;
|
||||
box-shadow: 0 0 5px 1px #333;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
code {
|
||||
@@ -33,6 +36,7 @@ code {
|
||||
display: table-cell;
|
||||
border: 1px solid #ccc;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
padding-bottom: 15px;
|
||||
padding-top: 15px;
|
||||
padding-left: 3px;
|
||||
@@ -45,22 +49,13 @@ code {
|
||||
|
||||
#tab_parent :first-child {
|
||||
border-top-left-radius: 8px;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
#tab_parent :last-child {
|
||||
border-top-right-radius: 8px;
|
||||
}
|
||||
|
||||
.tab_first {
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
.tab_last {
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
}
|
||||
|
||||
.selected_tab {
|
||||
background-color: #eeeefa;
|
||||
border-bottom: none;
|
||||
@@ -70,11 +65,24 @@ code {
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
width: 100%;
|
||||
min-height: 80vh;
|
||||
min-height: 90vh;
|
||||
background-color: #eeeefa;
|
||||
border-bottom-left-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* This may be placed directly inside a tab, to prevent its contents from growing vertically. */
|
||||
.height_limiter {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.footer {
|
||||
@@ -429,7 +437,10 @@ code {
|
||||
.prompt_choices_scrollview {
|
||||
padding-top: 5px;
|
||||
overflow-y: scroll;
|
||||
max-height: 70vh; /* fill out roughly the rest of the screen once scrolled to the preview */
|
||||
}
|
||||
|
||||
.prompt_choices_scrollview {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.color_scheme_choices_list,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div title="Background color for illustration only.
|
||||
|
||||
fish cannot change the background color of your terminal and it will not be saved. Refer to your terminal documentation to set its background color.">
|
||||
fish cannot change the background color of your terminal. Refer to your terminal documentation to set its background color.">
|
||||
<!-- ko with: color_picker -->
|
||||
<div class="colorpicker_text_sample" ng-style="{'background-color': terminalBackgroundColor}">
|
||||
<span style="position: absolute; left: 10px; top: 3px;" data-ng-style="{'color': text_color_for_color(terminalBackgroundColor || 'black')}">{{ selectedColorScheme.name }}</span><br>
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
<div class="height_limiter">
|
||||
<!-- The first 'sample' prompt is the current one; the remainders are samples. This ought to be cleaned up. -->
|
||||
<div class="current_prompt" style="min-height: 7.5em;" ng-style="{'background-color': terminalBackgroundColor}">
|
||||
<div class="prompt_demo_choice_label" style="color: #FFF;">{{ selectedPrompt.name }}</div>
|
||||
<div class="prompt_demo_choice_label" style="color: #FFF;">{{ selectedPrompt.name }}</div>
|
||||
<div ng-bind-html='selectedPrompt.demo | to_trusted' class="prompt_demo unbordered"></div>
|
||||
<div style="position: absolute; right: 5px; bottom: 5px; color:">
|
||||
<span class="save_button"
|
||||
ng-show="showSaveButton"
|
||||
style="color: #777"
|
||||
ng-click="setPrompt()">{{ savePromptButtonTitle }}</span>
|
||||
ng-show="showSaveButton"
|
||||
style="color: #CCC"
|
||||
ng-click="setPrompt()">{{ savePromptButtonTitle }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin: 10px 0 7px 35px;">Preview a prompt below:</div>
|
||||
<div style="margin: 10px 15px 7px 15px; padding-bottom: 10px; border-bottom: solid 1px #999">Preview a prompt below:</div>
|
||||
<div class="prompt_choices_scrollview">
|
||||
<div class="prompt_choices_list">
|
||||
<div ng-repeat="prompt in samplePrompts">
|
||||
<div class="prompt_demo_choice_label">{{ prompt.name }}</div>
|
||||
<div ng-bind-html='prompt.demo | to_trusted' class="prompt_demo" ng-click="selectPrompt(prompt)"></div>
|
||||
</div>
|
||||
<div ng-repeat="prompt in samplePrompts">
|
||||
<div class="prompt_demo_choice_label">{{ prompt.name }}</div>
|
||||
<div ng-bind-html='prompt.demo | to_trusted' class="prompt_demo" ng-click="selectPrompt(prompt)"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -22,7 +22,7 @@ function fish_prompt
|
||||
|
||||
# Line 2
|
||||
echo
|
||||
if test $VIRTUAL_ENV
|
||||
if test -n "$VIRTUAL_ENV"
|
||||
printf "(%s) " (set_color blue)(basename $VIRTUAL_ENV)(set_color normal)
|
||||
end
|
||||
printf '↪ '
|
||||
|
||||
@@ -23,7 +23,7 @@ from itertools import chain
|
||||
COMMON_WSL_CMD_PATHS = (
|
||||
"/mnt/c/Windows/System32",
|
||||
"/windir/c/Windows/System32",
|
||||
"/c/Windows/System32"
|
||||
"/c/Windows/System32",
|
||||
)
|
||||
FISH_BIN_PATH = False # will be set later
|
||||
IS_PY2 = sys.version_info[0] == 2
|
||||
@@ -37,6 +37,21 @@ else:
|
||||
import socketserver as SocketServer
|
||||
from urllib.parse import parse_qs
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
|
||||
# Disable CLI web browsers
|
||||
term = os.environ.pop("TERM", None)
|
||||
# This import must be done with an empty $TERM, otherwise a command-line browser may be started
|
||||
# which will block the whole process - see https://docs.python.org/3/library/webbrowser.html
|
||||
import webbrowser
|
||||
|
||||
if term:
|
||||
os.environ["TERM"] = term
|
||||
|
||||
|
||||
def find_executable(exe, paths=()):
|
||||
final_path = os.environ["PATH"].split(os.pathsep)
|
||||
@@ -71,19 +86,14 @@ def is_termux():
|
||||
return "com.termux" in os.environ["PATH"] and find_executable("termux-open-url")
|
||||
|
||||
|
||||
# Disable CLI web browsers
|
||||
term = os.environ.pop("TERM", None)
|
||||
# This import must be done with an empty $TERM, otherwise a command-line browser may be started
|
||||
# which will block the whole process - see https://docs.python.org/3/library/webbrowser.html
|
||||
import webbrowser
|
||||
|
||||
if term:
|
||||
os.environ["TERM"] = term
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
def is_chromeos_garcon():
|
||||
""" Return whether we are running in Chrome OS and the browser can't see local files """
|
||||
# In Crostini Chrome OS Linux, the default browser opens URLs in Chrome
|
||||
# running outside the linux VM. This browser does not have access to the
|
||||
# Linux filesystem. This uses Garcon, see for example
|
||||
# https://chromium.googlesource.com/chromiumos/platform2/+/master/vm_tools/garcon/#opening-urls
|
||||
# https://source.chromium.org/search?q=garcon-url-handler
|
||||
return "garcon-url-handler" in webbrowser.get().name
|
||||
|
||||
|
||||
def run_fish_cmd(text):
|
||||
@@ -982,7 +992,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
vars[name].exported = True
|
||||
|
||||
# Do not return history as a variable, it may be so large the browser hangs.
|
||||
vars.pop('history', None)
|
||||
vars.pop("history", None)
|
||||
|
||||
return [
|
||||
vars[key].get_json_obj()
|
||||
@@ -1549,6 +1559,8 @@ def runThing():
|
||||
sys.exit(-1)
|
||||
elif is_termux():
|
||||
subprocess.call(["termux-open-url", url])
|
||||
elif is_chromeos_garcon():
|
||||
webbrowser.open(url)
|
||||
else:
|
||||
webbrowser.open(fileurl)
|
||||
|
||||
|
||||
@@ -155,7 +155,6 @@ int parse_help_only_cmd_opts(struct help_only_cmd_opts_t &opts, int *optind, int
|
||||
/// Process and print help for the specified builtin or function.
|
||||
void builtin_print_help(parser_t &parser, const io_streams_t &streams, const wchar_t *name,
|
||||
wcstring *error_message) {
|
||||
UNUSED(streams);
|
||||
// This won't ever work if no_exec is set.
|
||||
if (no_exec()) return;
|
||||
const wcstring name_esc = escape_string(name, ESCAPE_ALL);
|
||||
@@ -166,8 +165,10 @@ void builtin_print_help(parser_t &parser, const io_streams_t &streams, const wch
|
||||
// If it's an error, redirect the output of __fish_print_help to stderr
|
||||
ios.push_back(std::make_shared<io_fd_t>(STDOUT_FILENO, STDERR_FILENO));
|
||||
}
|
||||
parser.eval(cmd, ios);
|
||||
// ignore the exit status of __fish_print_help
|
||||
auto res = parser.eval(cmd, ios);
|
||||
if (res.status.exit_code() == 2) {
|
||||
streams.err.append_format(BUILTIN_ERR_MISSING_HELP, name_esc.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform error reporting for encounter with unknown option.
|
||||
|
||||
@@ -36,6 +36,10 @@ enum { COMMAND_NOT_BUILTIN, BUILTIN_REGULAR, BUILTIN_FUNCTION };
|
||||
/// Error message on missing argument.
|
||||
#define BUILTIN_ERR_MISSING _(L"%ls: Expected argument for option %ls\n")
|
||||
|
||||
/// Error message on missing man page.
|
||||
#define BUILTIN_ERR_MISSING_HELP \
|
||||
_(L"fish: Missing man page for '%ls'. Did you install the documentation?\n")
|
||||
|
||||
/// Error message on invalid combination of options.
|
||||
#define BUILTIN_ERR_COMBO _(L"%ls: Invalid combination of options\n")
|
||||
|
||||
|
||||
@@ -188,13 +188,19 @@ maybe_t<int> builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t
|
||||
}
|
||||
}
|
||||
|
||||
const rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : L"");
|
||||
rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : L"");
|
||||
if (bgcolor && bg.is_none()) {
|
||||
streams.err.append_format(_(L"%ls: Unknown color '%ls'\n"), argv[0], bgcolor);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (print) {
|
||||
// Hack: Explicitly setting a background of "normal" crashes
|
||||
// for --print-colors. Because it's not interesting in terms of display,
|
||||
// just skip it.
|
||||
if (bgcolor && bg.is_special()) {
|
||||
bg = rgb_color_t(L"");
|
||||
}
|
||||
print_colors(streams, bold, underline, italics, dim, reverse, bg);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ struct options_t { //!OCLINT(too many fields)
|
||||
long max = 0;
|
||||
long start = 0;
|
||||
long end = 0;
|
||||
size_t width = 0;
|
||||
ssize_t width = 0;
|
||||
|
||||
wchar_t char_to_pad = L' ';
|
||||
|
||||
@@ -1181,24 +1181,24 @@ static int string_pad(parser_t &parser, io_streams_t &streams, int argc, wchar_t
|
||||
}
|
||||
|
||||
// Find max width of strings and keep the inputs
|
||||
size_t max_width = 0;
|
||||
ssize_t max_width = 0;
|
||||
std::vector<wcstring> inputs;
|
||||
|
||||
arg_iterator_t aiter_width(argv, optind, streams);
|
||||
while (const wcstring *arg = aiter_width.nextstr()) {
|
||||
wcstring input_string = *arg;
|
||||
size_t width = fish_wcswidth(input_string);
|
||||
ssize_t width = fish_wcswidth(input_string);
|
||||
if (width > max_width) max_width = width;
|
||||
inputs.push_back(std::move(input_string));
|
||||
}
|
||||
|
||||
size_t pad_width = max_width > opts.width ? max_width : opts.width;
|
||||
ssize_t pad_width = max_width > opts.width ? max_width : opts.width;
|
||||
for (auto &input : inputs) {
|
||||
wcstring padded;
|
||||
size_t padded_width = fish_wcswidth(input);
|
||||
ssize_t padded_width = fish_wcswidth(input);
|
||||
if (pad_width >= padded_width) {
|
||||
size_t pad = (pad_width - padded_width) / pad_char_width;
|
||||
size_t remaining_width = (pad_width - padded_width) % pad_char_width;
|
||||
ssize_t pad = (pad_width - padded_width) / pad_char_width;
|
||||
ssize_t remaining_width = (pad_width - padded_width) % pad_char_width;
|
||||
if (opts.left) {
|
||||
padded.append(pad, opts.char_to_pad);
|
||||
padded.append(remaining_width, L' ');
|
||||
|
||||
@@ -40,6 +40,7 @@ static const struct woption long_options[] = {{L"help", no_argument, nullptr, 'h
|
||||
{L"path", no_argument, nullptr, 'p'},
|
||||
{L"force-path", no_argument, nullptr, 'P'},
|
||||
{L"query", no_argument, nullptr, 'q'},
|
||||
{L"quiet", no_argument, nullptr, 'q'},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
|
||||
static int parse_cmd_opts(type_cmd_opts_t &opts, int *optind, int argc, wchar_t **argv,
|
||||
|
||||
@@ -212,7 +212,7 @@ bool is_windows_subsystem_for_linux() {
|
||||
status == 0 ? demangled
|
||||
: info.dli_sname == nullptr ? symbols[i]
|
||||
: info.dli_sname,
|
||||
static_cast<char *>(callstack[i]) - static_cast<char *>(info.dli_saddr));
|
||||
static_cast<char *>(callstack[i]) - static_cast<const char *>(info.dli_saddr));
|
||||
free(demangled);
|
||||
} else {
|
||||
swprintf(text, sizeof(text) / sizeof(wchar_t), L"%-3d %s", i - skip_levels, symbols[i]);
|
||||
|
||||
@@ -1582,11 +1582,10 @@ universal_notifier_t::notifier_strategy_t universal_notifier_t::resolve_default_
|
||||
return strategy_notifyd;
|
||||
#elif defined(__CYGWIN__)
|
||||
return strategy_shmem_polling;
|
||||
#elif defined(SIGIO) && (defined(__APPLE__) || defined(__BSD__) || defined(__linux__))
|
||||
// The SIGIO notifier relies on an extremely specific interaction between signal handling and
|
||||
// O_ASYNC writes, and doesn't excercise codepaths that are particularly well explored on all
|
||||
// POSIX and POSIX-like systems, so we only explicitly enable it on platforms where it's known
|
||||
// to work. See discussion in #6585 for examples of breakage.
|
||||
#elif 0 && defined(SIGIO) && (defined(__APPLE__) || defined(__BSD__) || defined(__linux__))
|
||||
// FIXME: The SIGIO notifier relies on an extremely specific interaction between signal handling and
|
||||
// O_ASYNC writes, and doesn't currently work particularly well, so it's disabled.
|
||||
// See discussion in #6585 and #7774 for examples of breakage.
|
||||
//
|
||||
// The SIGIO notifier does not yet work on WSL. See #7429
|
||||
if (is_windows_subsystem_for_linux()) {
|
||||
|
||||
@@ -97,8 +97,11 @@ static void set_signal_observed(int sig, bool val) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests if one event instance matches the definition of a event class.
|
||||
static bool handler_matches(const event_handler_t &classv, const event_t &instance) {
|
||||
/// Tests if one event instance matches the definition of an event class.
|
||||
/// In case of a match, \p only_once indicates that the event cannot match again by nature.
|
||||
static bool handler_matches(const event_handler_t &classv, const event_t &instance,
|
||||
bool &only_once) {
|
||||
only_once = false;
|
||||
if (classv.desc.type == event_type_t::any) return true;
|
||||
if (classv.desc.type != instance.desc.type) return false;
|
||||
|
||||
@@ -111,9 +114,11 @@ static bool handler_matches(const event_handler_t &classv, const event_t &instan
|
||||
}
|
||||
case event_type_t::exit: {
|
||||
if (classv.desc.param1.pid == EVENT_ANY_PID) return true;
|
||||
only_once = true;
|
||||
return classv.desc.param1.pid == instance.desc.param1.pid;
|
||||
}
|
||||
case event_type_t::caller_exit: {
|
||||
only_once = true;
|
||||
return classv.desc.param1.caller_id == instance.desc.param1.caller_id;
|
||||
}
|
||||
case event_type_t::generic: {
|
||||
@@ -234,22 +239,54 @@ static void event_fire_internal(parser_t &parser, const event_t &event) {
|
||||
scoped_push<bool> suppress_trace{&ld.suppress_fish_trace, true};
|
||||
|
||||
// Capture the event handlers that match this event.
|
||||
event_handler_list_t fire;
|
||||
for (const auto &handler : *s_event_handlers.acquire()) {
|
||||
// Check if this event is a match.
|
||||
if (handler_matches(*handler, event)) {
|
||||
fire.push_back(handler);
|
||||
struct firing_handler_t {
|
||||
std::shared_ptr<event_handler_t> handler;
|
||||
bool delete_after_call;
|
||||
};
|
||||
std::vector<firing_handler_t> fire;
|
||||
{
|
||||
for (const auto &handler : *s_event_handlers.acquire()) {
|
||||
// Check if this event is a match.
|
||||
bool only_once = false;
|
||||
if (!handler_matches(*handler, event, only_once)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the nature of the event means it can't be fired more than once, deregister the
|
||||
// event. This also works around a bug where jobs run without job control (no separate
|
||||
// pgrp) cause handlers to run for each subsequent job started without job control
|
||||
// (#7721). We can't erase it here because we check if the event is still extant before
|
||||
// actually calling it below, so we instead push it along with its "delete after
|
||||
// calling" value.
|
||||
fire.push_back(firing_handler_t{handler, only_once});
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over our list of matching events. Fire the ones that are still present.
|
||||
for (const shared_ptr<event_handler_t> &handler : fire) {
|
||||
for (const auto &firing_event : fire) {
|
||||
auto &handler = firing_event.handler;
|
||||
// Only fire if this event is still present.
|
||||
// TODO: this is kind of crazy. We want to support removing (and thereby suppressing) an
|
||||
// event handler from another, but we also don't want to hold the lock across callouts. How
|
||||
// can we make this less silly?
|
||||
if (!contains(*s_event_handlers.acquire(), handler)) {
|
||||
continue;
|
||||
{
|
||||
auto event_handlers = s_event_handlers.acquire();
|
||||
if (!contains(*event_handlers, handler)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Delete the event before firing it so we don't have to lock and unlock the event
|
||||
// handlers list when handing control off to the handler.
|
||||
if (firing_event.delete_after_call) {
|
||||
FLOGF(event, L"Pruning handler '%ls' before firing", event.desc.str_param1.c_str());
|
||||
for (auto event_handler = event_handlers->begin();
|
||||
event_handler != event_handlers->end(); ++event_handler) {
|
||||
if (event_handler->get() == firing_event.handler.get()) {
|
||||
event_handlers->erase(event_handler);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a buffer to evaluate, starting with the function name and then all the
|
||||
|
||||
@@ -445,7 +445,9 @@ static std::unique_ptr<output_stream_t> create_output_stream_for_builtin(
|
||||
// Our IO redirection is to an internal buffer, e.g. a command substitution.
|
||||
// We will write directly to it.
|
||||
std::shared_ptr<io_buffer_t> buffer =
|
||||
dynamic_cast<const io_bufferfill_t *>(io.get())->buffer();
|
||||
// (this is not a dynamic_cast because that needs rtti,
|
||||
// and we currently use it nowhere else)
|
||||
((const io_bufferfill_t *)io.get())->buffer();
|
||||
return make_unique<buffered_output_stream_t>(buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "fd_monitor.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <thread> //this_thread::sleep_for
|
||||
|
||||
#include "flog.h"
|
||||
#include "io.h"
|
||||
|
||||
@@ -491,6 +491,9 @@ int main(int argc, char **argv) {
|
||||
if (!opts.no_exec) {
|
||||
read_init(parser, paths);
|
||||
}
|
||||
// Re-read the terminal modes after config, it might have changed them.
|
||||
term_copy_modes();
|
||||
|
||||
// Stomp the exit status of any initialization commands (issue #635).
|
||||
parser.set_last_statuses(statuses_t::just(STATUS_CMD_OK));
|
||||
|
||||
|
||||
@@ -5058,9 +5058,11 @@ static void test_error_messages() {
|
||||
|
||||
static void test_highlighting() {
|
||||
say(L"Testing syntax highlighting");
|
||||
if (system("mkdir -p test/fish_highlight_test/")) err(L"mkdir failed");
|
||||
if (system("touch test/fish_highlight_test/foo")) err(L"touch failed");
|
||||
if (system("touch test/fish_highlight_test/bar")) err(L"touch failed");
|
||||
if (!pushd("test/fish_highlight_test/")) return;
|
||||
cleanup_t pop{[] { popd(); }};
|
||||
if (system("mkdir -p dir")) err(L"mkdir failed");
|
||||
if (system("touch foo")) err(L"touch failed");
|
||||
if (system("touch bar")) err(L"touch failed");
|
||||
|
||||
// Here are the components of our source and the colors we expect those to be.
|
||||
struct highlight_component_t {
|
||||
@@ -5079,14 +5081,14 @@ static void test_highlighting() {
|
||||
param_valid_path.valid_path = true;
|
||||
|
||||
highlight_tests.push_back({{L"echo", highlight_role_t::command},
|
||||
{L"test/fish_highlight_test/foo", param_valid_path},
|
||||
{L"./foo", param_valid_path},
|
||||
{L"&", highlight_role_t::statement_terminator}});
|
||||
|
||||
highlight_tests.push_back({
|
||||
{L"command", highlight_role_t::keyword},
|
||||
{L"echo", highlight_role_t::command},
|
||||
{L"abc", highlight_role_t::param},
|
||||
{L"test/fish_highlight_test/foo", param_valid_path},
|
||||
{L"foo", param_valid_path},
|
||||
{L"&", highlight_role_t::statement_terminator},
|
||||
});
|
||||
|
||||
@@ -5105,12 +5107,12 @@ static void test_highlighting() {
|
||||
// Verify that cd shows errors for non-directories.
|
||||
highlight_tests.push_back({
|
||||
{L"cd", highlight_role_t::command},
|
||||
{L"test/fish_highlight_test", param_valid_path},
|
||||
{L"dir", param_valid_path},
|
||||
});
|
||||
|
||||
highlight_tests.push_back({
|
||||
{L"cd", highlight_role_t::command},
|
||||
{L"test/fish_highlight_test/foo", highlight_role_t::error},
|
||||
{L"foo", highlight_role_t::error},
|
||||
});
|
||||
|
||||
highlight_tests.push_back({
|
||||
|
||||
@@ -774,12 +774,20 @@ bool history_impl_t::save_internal_via_rewrite() {
|
||||
// We want to rewrite the file, while holding the lock for as briefly as possible
|
||||
// To do this, we speculatively write a file, and then lock and see if our original file changed
|
||||
// Repeat until we succeed or give up
|
||||
const maybe_t<wcstring> target_name = history_filename(name);
|
||||
const maybe_t<wcstring> possibly_indirect_target_name = history_filename(name);
|
||||
const maybe_t<wcstring> tmp_name_template = history_filename(name, L".XXXXXX");
|
||||
if (!target_name.has_value() || !tmp_name_template.has_value()) {
|
||||
if (!possibly_indirect_target_name.has_value() || !tmp_name_template.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the history file is a symlink, we want to rewrite the real file so long as we can find it.
|
||||
wcstring target_name;
|
||||
if (auto maybe_real_path = wrealpath(*possibly_indirect_target_name)) {
|
||||
target_name = *maybe_real_path;
|
||||
} else {
|
||||
target_name = *possibly_indirect_target_name;
|
||||
}
|
||||
|
||||
// Make our temporary file
|
||||
// Remember that we have to close this fd!
|
||||
wcstring tmp_name;
|
||||
@@ -792,7 +800,7 @@ bool history_impl_t::save_internal_via_rewrite() {
|
||||
for (int i = 0; i < max_save_tries && !done; i++) {
|
||||
// Open any target file, but do not lock it right away
|
||||
autoclose_fd_t target_fd_before{
|
||||
wopen_cloexec(*target_name, O_RDONLY | O_CREAT, history_file_mode)};
|
||||
wopen_cloexec(target_name, O_RDONLY | O_CREAT, history_file_mode)};
|
||||
file_id_t orig_file_id = file_id_for_fd(target_fd_before.fd()); // possibly invalid
|
||||
bool wrote = this->rewrite_to_temporary_file(target_fd_before.fd(), tmp_fd);
|
||||
target_fd_before.close();
|
||||
@@ -805,14 +813,14 @@ bool history_impl_t::save_internal_via_rewrite() {
|
||||
// were rewriting it. Make an effort to take the lock before checking, to avoid racing.
|
||||
// If the open fails, then proceed; this may be because there is no current history
|
||||
file_id_t new_file_id = kInvalidFileID;
|
||||
autoclose_fd_t target_fd_after{wopen_cloexec(*target_name, O_RDONLY)};
|
||||
autoclose_fd_t target_fd_after{wopen_cloexec(target_name, O_RDONLY)};
|
||||
if (target_fd_after.valid()) {
|
||||
// critical to take the lock before checking file IDs,
|
||||
// and hold it until after we are done replacing
|
||||
// Also critical to check the file at the path, NOT based on our fd
|
||||
// It's only OK to replace the file while holding the lock
|
||||
history_file_lock(target_fd_after.fd(), LOCK_EX);
|
||||
new_file_id = file_id_for_path(*target_name);
|
||||
new_file_id = file_id_for_path(target_name);
|
||||
}
|
||||
bool can_replace_file = (new_file_id == orig_file_id || new_file_id == kInvalidFileID);
|
||||
if (!can_replace_file) {
|
||||
@@ -841,8 +849,9 @@ bool history_impl_t::save_internal_via_rewrite() {
|
||||
}
|
||||
|
||||
// Slide it into place
|
||||
if (wrename(tmp_name, *target_name) == -1) {
|
||||
FLOGF(history_file, L"Error %d when renaming history file", errno);
|
||||
if (wrename(tmp_name, target_name) == -1) {
|
||||
const char *error = std::strerror(errno);
|
||||
FLOGF(error, _(L"Error when renaming history file: %s"), error);
|
||||
}
|
||||
|
||||
// We did it
|
||||
|
||||
@@ -179,12 +179,14 @@ void outputter_t::set_color(rgb_color_t fg, rgb_color_t bg) {
|
||||
reset_modes();
|
||||
}
|
||||
|
||||
if (!last_color2.is_normal() && !last_color2.is_reset()) {
|
||||
if (!last_color2.is_special()) {
|
||||
// Background was set.
|
||||
// "Special" here refers to the special "normal", "reset" and "none" colors,
|
||||
// that really jus disable the background.
|
||||
last_bg_set = true;
|
||||
}
|
||||
|
||||
if (!bg.is_normal()) {
|
||||
if (!bg.is_special()) {
|
||||
// Background is set.
|
||||
bg_set = true;
|
||||
if (fg == bg) fg = (bg == rgb_color_t::white()) ? rgb_color_t::black() : rgb_color_t::white();
|
||||
|
||||
@@ -900,19 +900,14 @@ end_execution_reason_t parse_execution_context_t::populate_plain_process(
|
||||
return arg_result;
|
||||
}
|
||||
|
||||
// Determine the process type.
|
||||
process_type = process_type_for_command(statement, cmd);
|
||||
|
||||
// Only external commands and exec may redirect arbitrary fds.
|
||||
bool allow_high_fds =
|
||||
(process_type == process_type_t::external || process_type == process_type_t::exec);
|
||||
|
||||
// The set of IO redirections that we construct for the process.
|
||||
auto reason =
|
||||
this->determine_redirections(statement.args_or_redirs, allow_high_fds, &redirections);
|
||||
auto reason = this->determine_redirections(statement.args_or_redirs, &redirections);
|
||||
if (reason != end_execution_reason_t::ok) {
|
||||
return reason;
|
||||
}
|
||||
|
||||
// Determine the process type.
|
||||
process_type = process_type_for_command(statement, cmd);
|
||||
}
|
||||
|
||||
// Populate the process.
|
||||
@@ -985,8 +980,7 @@ end_execution_reason_t parse_execution_context_t::expand_arguments_from_nodes(
|
||||
}
|
||||
|
||||
end_execution_reason_t parse_execution_context_t::determine_redirections(
|
||||
const ast::argument_or_redirection_list_t &list, bool allow_high_fds,
|
||||
redirection_spec_list_t *out_redirections) {
|
||||
const ast::argument_or_redirection_list_t &list, redirection_spec_list_t *out_redirections) {
|
||||
// Get all redirection nodes underneath the statement.
|
||||
for (const ast::argument_or_redirection_t &arg_or_redir : list) {
|
||||
if (!arg_or_redir.is_redirection()) continue;
|
||||
@@ -1014,18 +1008,10 @@ end_execution_reason_t parse_execution_context_t::determine_redirections(
|
||||
redirection_spec_t spec{oper->fd, oper->mode, std::move(target)};
|
||||
|
||||
// Validate this spec.
|
||||
if (spec.mode == redirection_mode_t::fd && !spec.is_close()) {
|
||||
maybe_t<int> target_fd = spec.get_target_as_fd();
|
||||
if (!target_fd.has_value()) {
|
||||
// Like `cmd >&gibberish`.
|
||||
const wchar_t *fmt =
|
||||
_(L"Requested redirection to '%ls', which is not a valid file descriptor");
|
||||
return report_error(STATUS_INVALID_ARGS, redir_node, fmt, spec.target.c_str());
|
||||
} else if (*target_fd > STDERR_FILENO && !allow_high_fds) {
|
||||
// Like `echo foo 2>&5`. Don't allow internal procs to write to internal fish fds.
|
||||
const wchar_t *fmt = _(L"Redirection to fd %d is only valid for external commands");
|
||||
return report_error(STATUS_INVALID_ARGS, redir_node, fmt, *target_fd);
|
||||
}
|
||||
if (spec.mode == redirection_mode_t::fd && !spec.is_close() && !spec.get_target_as_fd()) {
|
||||
const wchar_t *fmt =
|
||||
_(L"Requested redirection to '%ls', which is not a valid file descriptor");
|
||||
return report_error(STATUS_INVALID_ARGS, redir_node, fmt, spec.target.c_str());
|
||||
}
|
||||
out_redirections->push_back(std::move(spec));
|
||||
|
||||
@@ -1080,8 +1066,7 @@ end_execution_reason_t parse_execution_context_t::populate_block_process(
|
||||
assert(args_or_redirs && "Should have args_or_redirs");
|
||||
|
||||
redirection_spec_list_t redirections;
|
||||
auto reason =
|
||||
this->determine_redirections(*args_or_redirs, false /* no high fds */, &redirections);
|
||||
auto reason = this->determine_redirections(*args_or_redirs, &redirections);
|
||||
if (reason == end_execution_reason_t::ok) {
|
||||
proc->type = process_type_t::block_node;
|
||||
proc->block_node_source = pstree;
|
||||
|
||||
@@ -130,11 +130,7 @@ class parse_execution_context_t {
|
||||
globspec_t glob_behavior);
|
||||
|
||||
// Determines the list of redirections for a node.
|
||||
// If \p allow_high_fds is false, then report an error for an fd redirection other than to
|
||||
// in/out/err. This is set when constructing an internal process and prevents writing random
|
||||
// data to internal fish fds.
|
||||
end_execution_reason_t determine_redirections(const ast::argument_or_redirection_list_t &list,
|
||||
bool allow_high_fds,
|
||||
redirection_spec_list_t *out_redirections);
|
||||
|
||||
end_execution_reason_t run_1_job(const ast::job_t &job, const block_t *associated_block);
|
||||
|
||||
33
src/path.cpp
33
src/path.cpp
@@ -24,9 +24,6 @@
|
||||
#include "wcstringutil.h"
|
||||
#include "wutil.h" // IWYU pragma: keep
|
||||
|
||||
/// Unexpected error in path_get_path().
|
||||
#define MISSING_COMMAND_ERR_MSG _(L"Error while searching for command '%ls'")
|
||||
|
||||
// Note that PREFIX is defined in the `Makefile` and is thus defined when this module is compiled.
|
||||
// This ensures we always default to "/bin", "/usr/bin" and the bin dir defined for the fish
|
||||
// programs. Possibly with a duplicate dir if PREFIX is empty, "/", "/usr" or "/usr/". If the PREFIX
|
||||
@@ -81,36 +78,6 @@ static bool path_get_path_core(const wcstring &cmd, wcstring *out_path,
|
||||
return true;
|
||||
}
|
||||
err = EACCES;
|
||||
} else {
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
case ENAMETOOLONG:
|
||||
case ENOENT:
|
||||
case ENOTDIR: {
|
||||
break;
|
||||
}
|
||||
#ifdef __sun
|
||||
// Solaris 5.11 can return any of the following three if the path
|
||||
// does not exist. Yes, even 0. No, none of this is documented.
|
||||
case 0:
|
||||
case EAGAIN:
|
||||
case EEXIST: {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
// WSL has a bug where access(2) can return EINVAL
|
||||
// See https://github.com/Microsoft/BashOnWindows/issues/2522
|
||||
// The only other way EINVAL can happen is if the wrong
|
||||
// mode was specified, but we have X_OK hard-coded above.
|
||||
case EINVAL: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
FLOGF(warning, MISSING_COMMAND_ERR_MSG, next_path.c_str());
|
||||
wperror(L"access");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
12
src/proc.cpp
12
src/proc.cpp
@@ -649,13 +649,17 @@ static bool process_clean_after_marking(parser_t &parser, bool allow_interactive
|
||||
printed = true;
|
||||
}
|
||||
|
||||
// Prepare events for completed jobs, except for jobs that themselves came from event
|
||||
// handlers.
|
||||
if (!j->from_event_handler() && j->is_completed()) {
|
||||
if (j->should_report_process_exits()) {
|
||||
// Prepare events for completed jobs
|
||||
if (j->is_completed()) {
|
||||
// If this job already came from an event handler,
|
||||
// don't create an event or it's easy to get an infinite loop.
|
||||
if (!j->from_event_handler() && j->should_report_process_exits()) {
|
||||
pid_t pgid = *j->get_pgid();
|
||||
exit_events.push_back(proc_create_event(L"JOB_EXIT", event_type_t::exit, -pgid, 0));
|
||||
}
|
||||
// Caller exit events we still create, which anecdotally fixes `source (thing | psub)` inside event handlers.
|
||||
// This seems benign since this event is barely used (basically only psub), and it seems hard
|
||||
// to construct an infinite loop with it.
|
||||
exit_events.push_back(
|
||||
proc_create_event(L"JOB_EXIT", event_type_t::caller_exit, j->job_id(), 0));
|
||||
exit_events.back().desc.param1.caller_id = j->internal_job_id;
|
||||
|
||||
@@ -839,13 +839,15 @@ static void redirect_tty_after_sighup() {
|
||||
}
|
||||
|
||||
/// Give up control of terminal.
|
||||
static void term_donate() {
|
||||
static void term_donate(bool quiet = false) {
|
||||
while (true) {
|
||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &tty_modes_for_external_cmds) == -1) {
|
||||
if (errno == EIO) redirect_tty_output();
|
||||
if (errno != EINTR) {
|
||||
FLOGF(warning, _(L"Could not set terminal mode for new job"));
|
||||
wperror(L"tcsetattr");
|
||||
if (!quiet) {
|
||||
FLOGF(warning, _(L"Could not set terminal mode for new job"));
|
||||
wperror(L"tcsetattr");
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else
|
||||
@@ -853,9 +855,8 @@ static void term_donate() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Grab control of terminal.
|
||||
static void term_steal() {
|
||||
// Copy the (potentially changed) terminal modes and use them from now on.
|
||||
/// Copy the (potentially changed) terminal modes and use them from now on.
|
||||
void term_copy_modes() {
|
||||
struct termios modes;
|
||||
tcgetattr(STDIN_FILENO, &modes);
|
||||
std::memcpy(&tty_modes_for_external_cmds, &modes, sizeof tty_modes_for_external_cmds);
|
||||
@@ -872,8 +873,11 @@ static void term_steal() {
|
||||
} else {
|
||||
shell_modes.c_iflag &= ~IXOFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Grab control of terminal.
|
||||
void term_steal() {
|
||||
term_copy_modes();
|
||||
while (true) {
|
||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &shell_modes) == -1) {
|
||||
if (errno == EIO) redirect_tty_output();
|
||||
@@ -1336,6 +1340,12 @@ void reader_init() {
|
||||
|
||||
term_fix_modes(&shell_modes);
|
||||
|
||||
// Set up our fixed terminal modes once,
|
||||
// so we don't get flow control just because we inherited it.
|
||||
if (getpgrp() == tcgetpgrp(STDIN_FILENO)) {
|
||||
term_donate(/* quiet */ true);
|
||||
}
|
||||
|
||||
// We do this not because we actually need the window size but for its side-effect of correctly
|
||||
// setting the COLUMNS and LINES env vars.
|
||||
termsize_container_t::shared().updating(parser);
|
||||
@@ -2817,14 +2827,25 @@ struct readline_loop_state_t {
|
||||
|
||||
/// Run a sequence of commands from an input binding.
|
||||
void reader_data_t::run_input_command_scripts(const wcstring_list_t &cmds) {
|
||||
// Need to donate/steal the tty - see #2114.
|
||||
term_donate();
|
||||
auto last_statuses = parser().get_last_statuses();
|
||||
for (const wcstring &cmd : cmds) {
|
||||
parser().eval(cmd, io_chain_t{});
|
||||
}
|
||||
parser().set_last_statuses(std::move(last_statuses));
|
||||
term_steal();
|
||||
|
||||
// Restore tty to shell modes.
|
||||
// Some input commands will take over the tty - see #2114 for an example where vim is invoked
|
||||
// from a key binding. However we do NOT want to invoke term_donate(), because that will enable
|
||||
// ECHO mode, causing a race between new input and restoring the mode (#7770). So we leave the
|
||||
// tty alone, run the commands in shell mode, and then restore shell modes.
|
||||
int res;
|
||||
do {
|
||||
res = tcsetattr(STDIN_FILENO, TCSANOW, &shell_modes);
|
||||
} while (res < 0 && errno == EINTR);
|
||||
if (res < 0) {
|
||||
wperror(L"tcsetattr");
|
||||
}
|
||||
termsize_container_t::shared().invalidate_tty();
|
||||
}
|
||||
|
||||
/// Read normal characters, inserting them into the command line.
|
||||
|
||||
@@ -141,6 +141,7 @@ void reader_sighup();
|
||||
|
||||
/// Initialize the reader.
|
||||
void reader_init();
|
||||
void term_copy_modes();
|
||||
|
||||
/// Restore the term mode at startup.
|
||||
void restore_term_mode();
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "wutil.h"
|
||||
|
||||
#ifdef HAVE_WINSIZE
|
||||
#include <sys/termios.h>
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
// A counter which is incremented every SIGWINCH, or when the tty is otherwise invalidated.
|
||||
|
||||
@@ -113,22 +113,28 @@ echo comment after conjunction
|
||||
|
||||
# --help works
|
||||
builtin and --help >/dev/null
|
||||
# CHECKERR: fish: Missing man page {{.*}}
|
||||
echo $status
|
||||
and --help >/dev/null
|
||||
# CHECKERR: fish: Missing man page {{.*}}
|
||||
echo $status
|
||||
# CHECK: 0
|
||||
# CHECK: 0
|
||||
|
||||
builtin or --help >/dev/null
|
||||
# CHECKERR: fish: Missing man page {{.*}}
|
||||
echo $status
|
||||
or --help >/dev/null
|
||||
# CHECKERR: fish: Missing man page {{.*}}
|
||||
echo $status
|
||||
# CHECK: 0
|
||||
# CHECK: 0
|
||||
|
||||
builtin not --help >/dev/null
|
||||
# CHECKERR: fish: Missing man page {{.*}}
|
||||
echo $status
|
||||
not --help >/dev/null
|
||||
# CHECKERR: fish: Missing man page {{.*}}
|
||||
echo $status
|
||||
# CHECK: 0
|
||||
# CHECK: 0
|
||||
|
||||
@@ -2,7 +2,19 @@
|
||||
# Test ALL THE FISH FILES
|
||||
# in share/, that is - the tests are exempt because they contain syntax errors, on purpose
|
||||
|
||||
for file in $__fish_data_dir/**.fish
|
||||
$fish -n $file
|
||||
set timestamp_file ./last_check_all_files
|
||||
set -l find_args
|
||||
if test -f $timestamp_file
|
||||
set find_args -newer $timestamp_file
|
||||
end
|
||||
set -l fail_count 0
|
||||
for file in (find $__fish_data_dir/ -name "*.fish" $find_args 2>/dev/null; or find $__fish_data_dir/ -name "*.fish")
|
||||
$fish -n $file; or set fail_count (math $fail_count + 1)
|
||||
end
|
||||
|
||||
# Prevent setting timestamp if any errors were encountered
|
||||
if test "$fail_count" -eq 0
|
||||
touch $timestamp_file
|
||||
end
|
||||
|
||||
# No output is good output
|
||||
|
||||
@@ -23,9 +23,6 @@ $helper print_fds </dev/null
|
||||
$helper print_fds 3</dev/null
|
||||
# CHECK: 0 1 2 3
|
||||
|
||||
$helper print_fds 5>&2
|
||||
# CHECK: 0 1 2 5
|
||||
|
||||
# This attempts to trip a case where the file opened in fish
|
||||
# has the same fd as the redirection. In this case, the dup2
|
||||
# does not clear the CLO_EXEC bit.
|
||||
|
||||
@@ -54,4 +54,8 @@ fish_add_path -nP $tmpdir/etc | string replace -- $tmpdir ''
|
||||
test "$oldpath" = "$PATH"
|
||||
or echo "PATH CHANGED!!!" >&2
|
||||
|
||||
# See that moving multiple arguments removes the correct ones - #7776
|
||||
PATH=$tmpdir/{bin,etc,link,sbin} fish_add_path -nPpm $tmpdir/{link,sbin} | string replace -a $tmpdir ''
|
||||
# CHECK: set PATH /link /sbin /bin /etc
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -24,7 +24,7 @@ git init >/dev/null 2>&1
|
||||
# Note: We *can't* list all here because in addition to aliases,
|
||||
# git also uses all commands in $PATH called `git-something` as custom commands,
|
||||
# so this depends on system state!
|
||||
complete -C'git ' | grep '^add\s'
|
||||
complete -C'git ' | grep '^add'\t
|
||||
# (note: actual tab character in the check here)
|
||||
#CHECK: add Add file contents to the index
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ or echo "pgroups were the same, job control did not work"
|
||||
|
||||
# fish ignores SIGTTIN and so may transfer the tty even if it
|
||||
# doesn't own the tty. Ensure that doesn't happen.
|
||||
set -l fish (status fish-path)
|
||||
$fish -c 'status job-control full ; $fth report_foreground' &
|
||||
wait
|
||||
#CHECKERR: background
|
||||
|
||||
@@ -101,3 +101,18 @@ echo $status
|
||||
#CHECK: Command
|
||||
#CHECK: sleep
|
||||
#CHECK: 0
|
||||
|
||||
function foo
|
||||
function caller --on-job-exit caller
|
||||
echo caller
|
||||
end
|
||||
echo foo
|
||||
end
|
||||
|
||||
function bar --on-event bar
|
||||
echo (foo)
|
||||
end
|
||||
|
||||
emit bar
|
||||
#CHECK: foo
|
||||
#CHECK: caller
|
||||
|
||||
@@ -100,35 +100,10 @@ echo $status
|
||||
read abc <&-
|
||||
#CHECKERR: read: stdin is closed
|
||||
|
||||
# This one should output nothing.
|
||||
echo derp >&-
|
||||
|
||||
# Verify that builtins, blocks, and functions may not write to arbitrary fds.
|
||||
echo derp >&12
|
||||
#CHECKERR: {{.*}} Redirection to fd 12 is only valid for external commands
|
||||
#CHECKERR: echo derp >&12
|
||||
#CHECKERR: ^
|
||||
|
||||
begin
|
||||
echo derp
|
||||
end <&42
|
||||
#CHECKERR: {{.*}} Redirection to fd 42 is only valid for external commands
|
||||
#CHECKERR: end <&42
|
||||
#CHECKERR: ^
|
||||
|
||||
outnerr 2>&7
|
||||
#CHECKERR: {{.*}} Redirection to fd 7 is only valid for external commands
|
||||
#CHECKERR: outnerr 2>&7
|
||||
#CHECKERR: ^
|
||||
|
||||
# Redirection to 0, 1, 2 is allowed. We don't test 0 since writing to stdin is weird and unpredictable.
|
||||
echo hooray1 >&1
|
||||
echo hooray2 >&2
|
||||
#CHECK: hooray1
|
||||
#CHECKERR: hooray2
|
||||
|
||||
# "Verify that pipes don't conflict with fd redirections"
|
||||
# This code is very similar to eval. We go over a bunch of fds
|
||||
# This code is very similar to eval. We go over a bunch of fads
|
||||
# to make it likely that we will nominally conflict with a pipe
|
||||
# fish is supposed to detect this case and dup the pipe to something else
|
||||
echo "/bin/echo pipe 3 <&3 3<&-" | source 3<&0
|
||||
@@ -138,6 +113,9 @@ echo "/bin/echo pipe 6 <&6 6<&-" | source 6<&0
|
||||
echo "/bin/echo pipe 7 <&7 7<&-" | source 7<&0
|
||||
echo "/bin/echo pipe 8 <&8 8<&-" | source 8<&0
|
||||
echo "/bin/echo pipe 9 <&9 9<&-" | source 9<&0
|
||||
echo "/bin/echo pipe 10 <&10 10<&-" | source 10<&0
|
||||
echo "/bin/echo pipe 11 <&11 11<&-" | source 11<&0
|
||||
echo "/bin/echo pipe 12 <&12 12<&-" | source 12<&0
|
||||
#CHECK: pipe 3
|
||||
#CHECK: pipe 4
|
||||
#CHECK: pipe 5
|
||||
@@ -145,3 +123,6 @@ echo "/bin/echo pipe 9 <&9 9<&-" | source 9<&0
|
||||
#CHECK: pipe 7
|
||||
#CHECK: pipe 8
|
||||
#CHECK: pipe 9
|
||||
#CHECK: pipe 10
|
||||
#CHECK: pipe 11
|
||||
#CHECK: pipe 12
|
||||
|
||||
@@ -241,6 +241,7 @@ echo 7 $status # no passthrough
|
||||
#CHECK: 7 4
|
||||
false
|
||||
set -h >/dev/null
|
||||
# CHECKERR: fish: Missing man page {{.*}}
|
||||
echo 8 $status # no passthrough
|
||||
#CHECK: 8 0
|
||||
true
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#RUN: %fish -C "set -g helper %fish_test_helper; set -g fish %fish" %s
|
||||
|
||||
# Check that nohup is propagated.
|
||||
set fish (status fish-path)
|
||||
set output_path (mktemp)
|
||||
nohup $fish -c "$helper print_ignored_signals" 2>&1 > $output_path
|
||||
cat $output_path
|
||||
|
||||
@@ -713,3 +713,8 @@ end
|
||||
|
||||
string escape \x7F
|
||||
# CHECK: \x7f
|
||||
|
||||
# This used to crash.
|
||||
string pad -w 8 he \eh
|
||||
# CHECK: he
|
||||
# CHECK: {{\x1bh}}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#RUN: %fish -C 'set -g fish %fish' %s
|
||||
begin
|
||||
set -gx XDG_CONFIG_HOME (mktemp -d)
|
||||
mkdir -p $XDG_CONFIG_HOME/fish
|
||||
set -l target_file $XDG_CONFIG_HOME/fish/target_fish_variables
|
||||
set -l fish_variables $XDG_CONFIG_HOME/fish/fish_variables
|
||||
|
||||
echo > $target_file
|
||||
ln -sf $target_file $fish_variables
|
||||
$fish -c 'set -U variable value'
|
||||
|
||||
if test -L $fish_variables
|
||||
echo fish_variables is still a symlink
|
||||
else
|
||||
echo fish_variables has been overwritten
|
||||
end
|
||||
# CHECK: fish_variables is still a symlink
|
||||
end
|
||||
49
tests/checks/symlinks-not-overwritten.fish
Normal file
49
tests/checks/symlinks-not-overwritten.fish
Normal file
@@ -0,0 +1,49 @@
|
||||
#RUN: %fish -C 'set -g fish %fish' %s
|
||||
|
||||
set -gx XDG_CONFIG_HOME (mktemp -d)
|
||||
set -gx XDG_DATA_HOME $XDG_CONFIG_HOME
|
||||
mkdir -p $XDG_CONFIG_HOME/fish
|
||||
|
||||
|
||||
# fish_variables
|
||||
set -l target_file $XDG_CONFIG_HOME/fish/target_fish_variables
|
||||
set -l fish_variables $XDG_CONFIG_HOME/fish/fish_variables
|
||||
set -l backup_file $XDG_CONFIG_HOME/fish/fish_variables_backup
|
||||
|
||||
echo >$target_file
|
||||
cp $target_file $backup_file
|
||||
ln -sf $target_file $fish_variables
|
||||
$fish -c 'set -U variable value'
|
||||
|
||||
if not test -L $fish_variables
|
||||
echo fish_variables has been overwritten
|
||||
else if cmp $target_file $backup_file >/dev/null
|
||||
echo fish_variables was never written
|
||||
else
|
||||
echo fish_variables is still a symlink
|
||||
end
|
||||
# CHECK: fish_variables is still a symlink
|
||||
|
||||
|
||||
# fish_history
|
||||
set -l history_file $XDG_DATA_HOME/fish/fish_history
|
||||
set -l target_file $XDG_DATA_HOME/fish/target_fish_history
|
||||
set -l backup_file $XDG_DATA_HOME/fish/fish_history_backup
|
||||
|
||||
echo '- cmd: echo I will be deleted from history
|
||||
when: 1614577746' >$target_file
|
||||
cp $target_file $backup_file
|
||||
ln -sf $target_file $history_file
|
||||
# The one way to ensure non-interactive fish writes to the history file
|
||||
$fish -c 'echo all | history delete deleted | grep echo'
|
||||
# CHECK: [1] echo I will be deleted from history
|
||||
|
||||
if not test -L $history_file
|
||||
echo fish_history has been overwritten
|
||||
else if cmp $target_file $backup_file &>/dev/null
|
||||
# cmp writes to stderr when one file is empty, thus &> above
|
||||
echo fish_history was never written
|
||||
else
|
||||
echo fish_history is still a symlink
|
||||
end
|
||||
# CHECK: fish_history is still a symlink
|
||||
@@ -23,6 +23,10 @@ echo $status
|
||||
type -q '['
|
||||
echo $status
|
||||
# CHECK: 0
|
||||
# Confirm that --quiet is still a thing
|
||||
type --quiet '['
|
||||
echo $status
|
||||
# CHECK: 0
|
||||
|
||||
# Test that we print a command path
|
||||
type sh
|
||||
|
||||
@@ -35,9 +35,10 @@ expect_str("bryellow")
|
||||
expect_str("cyan")
|
||||
expect_str("green")
|
||||
expect_str("magenta")
|
||||
expect_str("\x1b[31mred")
|
||||
expect_str("\x1b[37mwhite")
|
||||
expect_str("\x1b[33myellow")
|
||||
# These should be anchored at the beginning of the line, no e.g. bold sequence before.
|
||||
expect_str("\n\x1b[31mred")
|
||||
expect_str("\n\x1b[37mwhite")
|
||||
expect_str("\n\x1b[33myellow")
|
||||
expect_str("normal")
|
||||
expect_prompt()
|
||||
|
||||
@@ -60,3 +61,24 @@ expect_str("white")
|
||||
expect_str("yellow")
|
||||
expect_str("normal")
|
||||
expect_prompt()
|
||||
|
||||
# This used to crash
|
||||
sendline("set_color --print-colors --background normal")
|
||||
expect_str("black")
|
||||
expect_str("blue")
|
||||
expect_str("brblack")
|
||||
expect_str("brblue")
|
||||
expect_str("brcyan")
|
||||
expect_str("brgreen")
|
||||
expect_str("brmagenta")
|
||||
expect_str("brred")
|
||||
expect_str("brwhite")
|
||||
expect_str("bryellow")
|
||||
expect_str("cyan")
|
||||
expect_str("green")
|
||||
expect_str("magenta")
|
||||
expect_str("\n\x1b[31mred")
|
||||
expect_str("\n\x1b[37mwhite")
|
||||
expect_str("\n\x1b[33myellow")
|
||||
expect_str("normal")
|
||||
expect_prompt()
|
||||
|
||||
Reference in New Issue
Block a user