This is essentially the inverse of `string pad`.
Where that adds characters to get up to the specified width,
this adds an ellipsis to a string if it goes over a specific maximum width.
The char can be given, but defaults to our ellipsis string.
("…" if the locale can handle it and "..." otherwise)
If the ellipsis string is empty, it just truncates.
For arguments given via argv, it goes line-by-line,
because otherwise length makes no sense.
If "--no-newline" is given, it adds an ellipsis instead and removes all subsequent lines.
Like pad and `length --visible`, it goes by visible width,
skipping recognized escape sequences, as those have no influence on width.
The default target width is the shortest of the given widths that is non-zero.
If the ellipsis is already wider than the target width,
we truncate instead. This is safer overall, so we don't e.g. move into a new line.
This is especially important given our default ellipsis might be width 3.
This was written while we changed how our synopses are formatted, so
we missed adding a "synopsis" marker to it.
The tokenizer here is a bit cheesy, so we can't mark continuation
lines with a "\", and we also can't mark the general options with a
":=". Tbh that's not a big deal.
Fixes#9154
Note that every change to the search field still starts a new search, from
the end of history. We could change this in future but it's unclear to me
what the expected behavior is. I don't find the traditional readline behavior
very intuitive.
This reimplements ridiculousfish/control_r which is a more future-proof
approach than #6686.
Pressing Control+R shows history in our pager and allows to search filter
commands with the pager search field.
On the surface, this works just like in other shells; though there are
some differences.
- Our pager shows multiple results at a time.
- Other shells allow to use up arrow/down arrow to select adjacent entries
in history. Shouldn't be hard to implement but the hidden state might
confuse users and it doesn't play well with up-or-search, so this is
left out.
Users might expect the history pager to use subsequence matching (fuzzy
matching) like the completion pager, however due to the history pager design it
uses substring matching. We could change this in future, however that means
we would also want to change the ordering from "reverse-chronological" to
"longest common subsequence" (e.g. what fuzzy finders do), because otherwise
a query "fis" might give this ordering:
fsck /dev/disk/by-partlabel/Linux\x20filesystem
fish
which is probably not what the user wants.
The pager shows only a small number of history items at a time. This is
because, as explained above, the history pager does not support subsequence
matching, so navigating it does not scale well.
Closes#602
This can be used to print the modification time, like `stat` with some
options.
The reason is that `stat` has caused us a number of portability
headaches:
1. It's not available everywhere by default
2. The versions are quite different
For instance, with GNU stat it's `stat -c '%Y'`, with macOS it's `stat
-f %m`.
So now checking a cache file can be done just with builtins.
It's still useful without, for instance to implement a command that
takes no options, or to check min-args or max-args.
(technically no optspecs, no min/max args and --ignore-unknown does
nothing, but that's a very specific error that we don't need to forbid)
Fixes#9006
This makes it so
1. The informative status can work without showing untracked
files (previously it was disabled if bash.showUntrackedFiles was
false)
2. If untrackedfiles isn't explicitly enabled, we use -uno, so git
doesn't have to scan all the files.
In a large repository (like the FreeBSD ports repo), this can improve
performance by a factor of 5 or up.
Previously, `kill-whole-line` kills the line and its following
newline. This is insufficient when we are on the last line, because
it would not actually clear the line. The cursor would stay on the
line, which is not the correct behavior for bindings like `dd`.
Also, `cc` in vi-mode used `kill-whole-line`, which is not correct
because it should not remove any newlines. We have to introduce
another special input function (`kill-inner-line`) to fix this.
This makes it so `complete -c foo -n test1 -n test2` registers *both*
conditions, and when it comes time to check the candidate, tries both,
in that order. If any fails it stops, if all succeed the completion is offered.
The reason for this is that it helps with caching - we have a
condition cache, but conditions like
```fish
test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] length
test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] sub
```
defeats it pretty easily, because the cache only looks at the entire
script as a string - it can't tell that the first `test` is the same
in both.
So this means we separate it into
```fish
complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] length" -s V -l visible -d "Use the visible width, excluding escape sequences"
+complete -f -c string -n "test (count (commandline -opc)) -ge 2" -n "contains -- (commandline -opc)[2] length" -s V -l visible -d "Use the visible width, excluding escape sequences"
```
which allows the `test` to be cached.
In tests, this improves performance for the string completions by 30%
by reducing all the redundant `test` calls.
The `git` completions can also greatly benefit from this.
This adds a path builtin to deal with paths.
It offers the following subcommands:
filter to go through a list of paths and only print the ones that pass some filter - exist, are a directory, have read permission, ...
is as a shortcut for filter -q to only return true if one of the paths passed the filter
basename, dirname and extension to print certain parts of the path
change-extension to change the extension to a different one (as a string operation)
normalize and resolve to canonicalize the paths in various flavors
sort to sort paths, also only using the basename or dirname as a key
The definition of "extension" here was carefully considered and should line up with how extensions are actually used - ~/.bashrc doesn't have an extension, but ~/.conf.d does (".d").
These subcommands all compose well - they can read from arguments or stdin (like string), they can use null-delimited input or output (input is autodetected - if a NULL happens in the first PATH_MAX bytes it switches automatically).
It is both a failglob exception (so like set if a glob passed to it fails it just doesn't get any arguments for it instead of triggering an error), and passes output to command substitution buffers explicitly split (like string split0) so newlines are easy to handle.
This is now added to the two commands that definitely deal with
relative paths.
It doesn't work for e.g. `path basename`, because after removing the
dirname prepending a "./" doesn't refer to the same file, and the
basename is also expected to not contain any slashes.
This includes the "." in what `path extension` prints.
This allows distinguishing between an empty extension (just `.`) and a
non-existent extension (no `.` at all).
These are short flags for "--perm=read" and "--type=link" and such.
Not every type or permission has a shorthand - we don't want "-s" for
"suid". So just the big three each get one.
This is theoretically sound, because a path can only be PATH_MAX - 1
bytes long, so at least the PATH_MAXest byte needs to be a NULL.
The one case this could break is when something has a NULL-output mode
but doesn't bother printing the NULL for only one path, and that path
contains a newline. So we leave --null-in there, to force it on.
This adds a "path" builtin that can handle paths.
Implemented so far:
- "path filter PATHS", filters paths according to existence and optionally type and permissions
- "path base" and "path dir", run basename and dirname, respectively
- "path extension PATHS", prints the extension, if any
- "path strip-extension", prints the path without the extension
- "path normalize PATHS", normalizes paths - removing "/./" components
- and such.
- "path real", does realpath - i.e. normalizing *and* link resolution.
Some of these - base, dir, {strip-,}extension and normalize operate on the paths only as strings, so they handle nonexistent paths. filter and real ignore any nonexistent paths.
All output is split explicitly, so paths with newlines in them are
handled correctly. Alternatively, all subcommands have a "--null-input"/"-z" and "--null-output"/"-Z" option to handle null-terminated input and create null-terminated output. So
find . -print0 | path base -z
prints the basename of all files in the current directory,
recursively.
With "-Z" it also prints it null-separated.
(if stdout is going to a command substitution, we probably want to
skip this)
All subcommands also have a "-q"/"--quiet" flag that tells them to skip output. They return true "when something happened". For match/filter that's when a file passed, for "base"/"dir"/"extension"/"strip-extension" that's when something about the path *changed*.
Filtering
---------
`filter` supports all the file*types* `test` has - "dir", "file", "link", "block"..., as well as the permissions - "read", "write", "exec" and things like "suid".
It is missing the tty check and the check for the file being non-empty. The former is best done via `isatty`, the latter I don't think I've ever seen used.
There currently is no way to only get "real" files, i.e. ignore links pointing to files.
Examples
--------
> path real /bin///sh
/usr/bin/bash
> path extension foo.mp4
mp4
> path extension ~/.config
(nothing, because ".config" isn't an extension.)
This teaches `--on-signal SIGINT` (and by extension `trap cmd SIGINT`)
to work properly in scripts, not just interactively. Note any such
function will suppress the default behavior of exiting. Do this for
SIGTERM as well.
* New -n flag for string join command.
This is an argument that excludes empty result items. Fixes#8351
* New documentation for string-join.
The new argument --no-empty was added at string-join manpage.
* New completions for the new -n flag for string join.
* Remove the documentation of the new -n flag of string join0
The reason to remove this new argument in the join0 is that this flag basically doesn't make any difference in the join0.
* Refactor the validation for the string join.
The string join command was using the length of the argument, this commit changes the validation to use the empty function.
* Revert #4b56ab452
The reason for the revert is thath the build broke on the ubuntu in the Github actions.
* Revert #e72e239a1
The reason the compilation on GitHub broke is that the test was weird, it didn't even run it, Common CI systems are typically very very resource-constrained.
* Resolve conflicts in the string-join.rst.
* Resolve conflicts in the "string-join.rst".
commit #1242d0fd7 not fixed all conflicts.
* Implement fish_wcstod_underscores
* Add fish_wcstod_underscores unit tests
* Switch to using fish_wcstod_underscores in tinyexpr
* Add tests for math builtin underscore separator functionality
* Add documentation for underscore separators for math builtin
* Add a changelog entry for underscore numeric separators
Includes harmonizing the display of options and arguments, standardising
terminology, using the envvar directive more broadly, adding help options to all
commands that support them, simplifying some language, and tidying up multiple
formatting issues.
string documentation is not changed.
man(1) uses lowercase placeholders but we usually don't. Additionally,
the new synopsis autoformatting only recognizes placeholders if they
are uppercase. Use uppercase for all placeholders.
Recent synopsis changes move from literal code blocks to
[RST line blocks]. This does not translate well to HTML: it's not
rendered in monospace, so aligment is lost. Additionally, we don't
get syntax highlighting in HTML, which adds differences to our code
samples which are highlighted.
We hard-wrap synopsis lines (like code blocks). To align continuation
lines in manpages we need [backslashes in weird places]. Combined with
the **, *, and `` markup, it's a bit hard to get the alignment right.
Fix these by moving synopsis sources back to code blocks and compute
HTML syntax highlighting and manpage markup with a custom Sphinx
extension.
The new Pygments lexer can tokenize a synopsis and assign the various
highlighting roles, which closely matches fish's syntax highlighing:
- command/keyword (dark blue)
- parameter (light blue)
- operator like and/or/not/&&/|| (cyan)
- grammar metacharacter (black)
For manpage output, we don't project the fish syntax highlighting
but follow the markup convention in GNU's man(1):
bold text type exactly as shown.
italic text replace with appropriate argument.
To make it easy to separate these two automatically, formalize that
(italic) placeholders must be uppercase; while all lowercase text is
interpreted literally (so rendered bold).
This makes manpages more consistent, see string-join(1) and and(1).
Implementation notes:
Since we want manpage formatting but Sphinx's Pygments highlighing
plugin does not support manpage output, add our custom "synopsis"
directive. This directive parses differently when manpage output is
specified. This means that the HTML and manpage build processes must
not share a cache, because the parsed doctrees are cached. Work around
this by using separate cache locations for build targets "sphinx-docs"
(which creates HTML) and "sphinx-manpages". A better solution would
be to only override Sphinx's ManualPageBuilder but that would take a
bit more code (ideally we could override ManualPageWriter but Sphinx
4.3.2 doesn't really support that).
---
Alternative solution: stick with line blocks but use roles like
:command: or :option: (or custom ones). While this would make it
possible to produce HTML that is consistent with code blocks (by adding
a bit of CSS), the source would look uglier and is harder to maintain.
(Let's say we want to add custom formatting to the [|] metacharacters
in HTML. This is much easier with the proposed patch.)
---
[RST line blocks]: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#line-blocks
[backslashes in weird places]: https://github.com/fish-shell/fish-shell/pull/8626#discussion_r782837750
This corrects what looks like wrong alignment of some synopsis lines.
(I think the alignment is not a bad idea but it makes us do more
manual work, maybe we can automate that in future. We still need to
figure out how to translate it to HTML.)
"man -l build/user_doc/man/man1/history.1" before:
string match [-a | --all] [-e | --entire] [-i | --ignore-case]
[-r | --regex] [-n | --index] [-q | --quiet] [-v | --invert]
PATTERN [STRING…]
and after:
string match [-a | --all] [-e | --entire] [-i | --ignore-case]
[-r | --regex] [-n | --index] [-q | --quiet] [-v | --invert]
PATTERN [STRING…]
Also make the lines align the same way in the RST source by carefully
choosing the position of the backslash. I'm not sure why we used
two backslashes per line. Use only one; this gives us no choice
of where to put it so both source and man page output are aligned.
Change tabs to spaces to make the alignment in the source work.
The ellipsis is a grammar metacharacter, just like the []()|.
Write *FOO*… instead of *FOO…*, so the ellipsis is not underlined
in the man page. Not super sure about this one.
This matches the style in man(1) (except that we use the … ligature).
A previous iteration did the reverse (never use a space before the
ellipsis). That would be a smaller change.
We use plural "*OPTIONS*" more often than "*OPTION*...", so let's do
that everywhere.
In some other places where we do have an ellipsis, make sure to use
singular, since the ellipsis already means repetition. This change
is incomplete, and I'm not sure if this is worth it, since it's
subjective, so I might drop it.
Correct the grammar by moving the options after the command argument.
Also group the -c/--command and -p/--path pairs, to convey that the
short and long variants are equivalent.
While at it, consolidate the -C/--do-complete forms, like we usually
do.
One synopsis misrenders as
set [options] VARIABLE*[*INDICES]… VALUES…
Add a missing backslash to fix that. Also go back to uppercase
because I'm not sure why this was changed to lowercase.
Finally, remove the spurious ellipsis after VARIABLE[INDICES].
This element cannot be repeated. Multiple index values and ranges
can be specified but that's already implied by the plural INDICES.
For alteration we usually use "(a | b)", not "{a | b}".
While at it, instead of writing 4/6 subcommands in one line, write them
on separate lines, so it's very obvious that all these are separate
subcommands. We mainly use the (a | b) syntax for long/short options.
The -- is not special here and we don't mention it in other synopses.
It was originally added for a good reason in 98449fec5 (fix `math`
regression, 2017-07-14), along this addition to math.rst:
> You should always place a `--` flag separator before the expression. [...]
However, since 56d913453 (Cache math expressions, 2017-08-24) that
line was changed to
> You don't need to use `--` before the expression even if it begins with a minus sign [...]