diff --git a/doc_src/tutorial.hdr b/doc_src/tutorial.hdr index 0e7727532..9d2ae535a 100644 --- a/doc_src/tutorial.hdr +++ b/doc_src/tutorial.hdr @@ -581,6 +581,12 @@ To prepend /usr/local/bin and /usr/sbin to `$PATH`, you can write: >_ set PATH /usr/local/bin /usr/sbin $PATH \endfish +To remove /usr/local/bin from `$PATH`, you can write: + +\fish{cli-dark} +>_ set PATH (string match -v /usr/local/bin $PATH) +\end{fish} + You can do so directly in `config.fish`, like you might do in other shells with `.profile`. See [this example](#path_example). A faster way is to modify the `$fish_user_paths` [universal variable](#tut_universal), which is automatically prepended to `$PATH`. For example, to permanently add `/usr/local/bin` to your `$PATH`, you could write: diff --git a/share/completions/git.fish b/share/completions/git.fish index e1272af5b..749d9df6e 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -161,7 +161,7 @@ function __fish_git_using_command # Check aliases. set -l varname __fish_git_alias_(string escape --style=var -- $cmd) - set -q $$varname + set -q $varname and contains -- $$varname $argv and return 0 return 1 diff --git a/share/completions/heroku.fish b/share/completions/heroku.fish index 2d11b15bb..ae46b8ef5 100644 --- a/share/completions/heroku.fish +++ b/share/completions/heroku.fish @@ -74,7 +74,6 @@ complete $heroku_looking -xa maintenance -d 'manage maintenance mode for an app' complete $heroku_looking -xa members -d 'manage membership in organization accounts' complete $heroku_looking -xa orgs -d 'manage organization accounts' complete $heroku_looking -xa pg -d 'manage heroku-postgresql databases' -complete $heroku_looking -xa pgbackups -d 'manage backups of heroku postgresql databases' complete $heroku_looking -xa plugins -d 'manage plugins to the heroku gem' complete $heroku_looking -xa regions -d 'list available regions' complete $heroku_looking -xa stack -d 'manage the stack for an app' @@ -168,6 +167,19 @@ complete -c heroku -n '__fish_heroku_using_command logs' -s p -l ps -l PS -d "on complete -c heroku -n '__fish_heroku_using_command logs' -s s -l source -l SOURCE -d "only display logs from the given source" complete -c heroku -n '__fish_heroku_using_command logs' -s t -l tail -d "continually stream logs" +# PG subcommands +complete $heroku_looking -xa pg:backups -d "manage backups of heroku postgresql databases" +complete $heroku_looking -xa pg:backups:cancel -d "cancel an in-progress backup or restore (default newest)" +complete $heroku_looking -xa pg:backups:capture -d "capture a new backup" +complete $heroku_looking -xa pg:backups:delete -d "delete a backup" +complete $heroku_looking -xa pg:backups:download -d "downloads database backup" +complete $heroku_looking -xa pg:backups:info -d "get information about a specific backup" +complete $heroku_looking -xa pg:backups:restore -d "restore a backup (default latest) to a database" +complete $heroku_looking -xa pg:backups:schedule -d "schedule daily backups for given database" +complete $heroku_looking -xa pg:backups:schedules -d "list backup schedule" +complete $heroku_looking -xa pg:backups:unschedule -d "stop daily backups" +complete $heroku_looking -xa pg:backups:url -d "get secret but publicly accessible URL of a backup" + # PS subcommands complete $heroku_looking -xa ps:resize -d "resize dynos to the given size (DYNO1=1X|2X|PX)" complete -c heroku -n '__fish_heroku_using_command ps:resize' -fa '(__fish_list_heroku_dynos)' -d "resize dynos to the given size (DYNO1=1X|2X|PX)" diff --git a/share/completions/npm.fish b/share/completions/npm.fish index d531dd1d3..0c57814a4 100644 --- a/share/completions/npm.fish +++ b/share/completions/npm.fish @@ -64,21 +64,28 @@ function __fish_complete_npm --description "Complete the commandline using npm's end # use npm completion for most of the things, -# except options completion because it sucks at it. +# except options completion (because it sucks at it) +# and run-script completion (reading package.json is faster). # see: https://github.com/npm/npm/issues/9524 # and: https://github.com/fish-shell/fish-shell/pull/2366 -complete -f -c npm -n 'not __fish_npm_needs_option' -a "(__fish_complete_npm)" +complete -f -c npm -n 'not __fish_npm_needs_option; and not __fish_npm_using_command run; and not __fish_npm_using_command run-script' -a "(__fish_complete_npm)" # list available npm scripts and their parial content +function __fish_parse_npm_run_completions + while read -l name + set -l trim 20 + read -l value + set value (string sub -l $trim -- $value) + printf "%s\t%s\n" $name $value + end +end + function __fish_npm_run # Like above, only try to call npm if there's a command by that name to facilitate aliases that call nvm. - if command -sq npm - command npm run | string match -r -v '^[^ ]|^$' | string trim | while read -l name - set -l trim 20 - read -l value - echo "$value" | cut -c1-$trim | read -l value - printf "%s\t%s\n" $name $value - end + if command -sq jq; and test -e package.json + jq -r '.scripts | to_entries[] | .key,.value' /dev/null ^ /dev/null complete -c tail -s c -l bytes -x -d 'output the last K bytes; alternatively, use -c +K to output bytes starting with the Kth of each file' - complete -c tail -s f -l follow -xa 'name descriptor' -d 'output appended data as the file grows; -f -l follow, and --follow=descriptor are equivalent' + complete -c tail -s f -l follow -a 'name descriptor' -d 'output appended data as the file grows; -f -l follow, and --follow=descriptor are equivalent' complete -c tail -s F -d 'same as --follow=name --retry' complete -c tail -s n -l lines -x -d 'output the last K lines, instead of the last 10; or use -n +K to output lines starting with the Kth' complete -c tail -l max-unchanged-stats -x -d 'with --follow=name, reopen a FILE which has not changed size after N iterations' @@ -9,8 +9,8 @@ if tail --version > /dev/null ^ /dev/null complete -c tail -l retry -d 'keep trying to open a file even when it is or becomes inaccessible; useful when following by name, i.e., with --follow=name' complete -c tail -s s -l sleep-interval -x -d 'with -f, sleep for approximately N seconds (default 1.0) between iterations' complete -c tail -s v -l verbose -d 'always output headers giving file names' - complete -c tail -l help -d 'display this help and exit' - complete -c tail -l version -d 'output version information and exit' + complete -c tail -x -l help -d 'display this help and exit' + complete -c tail -x -l version -d 'output version information and exit' else # OSX and similar - no longopts (and fewer shortopts) complete -c tail -s b -x -d 'output last K 512 byte blocks' complete -c tail -s c -x -d 'output the last K bytes or only K bytes with -r' diff --git a/share/functions/__fish_print_hostnames.fish b/share/functions/__fish_print_hostnames.fish index 8844154d2..efa3cac4f 100644 --- a/share/functions/__fish_print_hostnames.fish +++ b/share/functions/__fish_print_hostnames.fish @@ -44,14 +44,14 @@ function __fish_print_hostnames -d "Print a list of known hostnames" function _ssh_include --argument-names ssh_config # Relative paths in Include directive use /etc/ssh or ~/.ssh depending on # system or user level config. -F will not override this behaviour - if test $ssh_config = '/etc/ssh/ssh_config' + set -l relative_path $HOME/.ssh + if string match '/etc/ssh/*' -- $ssh_config set relative_path '/etc/ssh' - else - set relative_path $HOME/.ssh end function _recursive --no-scope-shadowing - set paths + set -l orig_dir $PWD + set -l paths for config in $argv set paths $paths (cat $config ^/dev/null \ # Keep only Include lines @@ -62,10 +62,11 @@ function __fish_print_hostnames -d "Print a list of known hostnames" | string trim | string replace -r -a '\s+' ' ') end + builtin cd $relative_path set -l new_paths for path in $paths set -l expanded_path - eval set expanded_path (echo $path) + eval "set expanded_path (printf \"%s\n\" $path)" for path in $expanded_path # Resolve "relative" paths in accordance to ssh path resolution if string match -qv '/*' $path @@ -75,9 +76,9 @@ function __fish_print_hostnames -d "Print a list of known hostnames" set new_paths $new_paths $path end end + builtin cd $orig_dir if test -n "$new_paths" - _recursive $new_paths end end diff --git a/share/tools/create_manpage_completions.py b/share/tools/create_manpage_completions.py index fb63f8fab..0eb4045bc 100755 --- a/share/tools/create_manpage_completions.py +++ b/share/tools/create_manpage_completions.py @@ -528,7 +528,6 @@ class TypeDarwinManParser(ManParser): line = line.replace('.Nm', CMDNAME) line = line.replace('\\ ', ' ') line = line.replace('\& ', '') - line = line.replace(r'.\"', '') return line def is_option(self, line): @@ -567,6 +566,9 @@ class TypeDarwinManParser(ManParser): desc_lines = [] while lines and not self.is_option(lines[0]): line = lossy_unicode(lines.pop(0).strip()) + # Ignore comments + if line.startswith(r'.\"'): + continue if line.startswith('.'): line = self.groff_replace_escapes(line) line = self.trim_groff(line).strip() diff --git a/src/common.cpp b/src/common.cpp index d0dea1c20..b52dbf076 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -598,16 +598,6 @@ void __attribute__((noinline)) debug(int level, const char *msg, ...) { errno = errno_old; } -void read_ignore(int fd, void *buff, size_t count) { - size_t ignore __attribute__((unused)); - ignore = read(fd, buff, count); -} - -void write_ignore(int fd, const void *buff, size_t count) { - size_t ignore __attribute__((unused)); - ignore = write(fd, buff, count); -} - void debug_safe(int level, const char *msg, const char *param1, const char *param2, const char *param3, const char *param4, const char *param5, const char *param6, const char *param7, const char *param8, const char *param9, const char *param10, @@ -626,14 +616,14 @@ void debug_safe(int level, const char *msg, const char *param1, const char *para const char *end = strchr(cursor, '%'); if (end == NULL) end = cursor + strlen(cursor); - write_ignore(STDERR_FILENO, cursor, end - cursor); + (void)write(STDERR_FILENO, cursor, end - cursor); if (end[0] == '%' && end[1] == 's') { // Handle a format string. assert(param_idx < sizeof params / sizeof *params); const char *format = params[param_idx++]; if (!format) format = "(null)"; - write_ignore(STDERR_FILENO, format, strlen(format)); + (void)write(STDERR_FILENO, format, strlen(format)); cursor = end + 2; } else if (end[0] == '\0') { // Must be at the end of the string. @@ -645,7 +635,7 @@ void debug_safe(int level, const char *msg, const char *param1, const char *para } // We always append a newline. - write_ignore(STDERR_FILENO, "\n", 1); + (void)write(STDERR_FILENO, "\n", 1); errno = errno_old; } diff --git a/src/common.h b/src/common.h index d4a2f646f..aa0085378 100644 --- a/src/common.h +++ b/src/common.h @@ -179,10 +179,6 @@ extern bool g_profiling_active; /// Name of the current program. Should be set at startup. Used by the debug function. extern const wchar_t *program_name; -// Variants of read() and write() that ignores return values, defeating a warning. -void read_ignore(int fd, void *buff, size_t count); -void write_ignore(int fd, const void *buff, size_t count); - /// Set to false at run-time if it's been determined we can't trust the last modified timestamp on /// the tty. extern bool has_working_tty_timestamps; @@ -207,7 +203,7 @@ extern bool has_working_tty_timestamps; { \ char exit_read_buff; \ show_stackframe(L'E'); \ - read_ignore(0, &exit_read_buff, 1); \ + (void)read(0, &exit_read_buff, 1); \ exit_without_destructors(1); \ } diff --git a/src/complete.cpp b/src/complete.cpp index d537b0bf3..51b6acd91 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -330,8 +330,6 @@ class completer_t { void complete_param_expand(const wcstring &str, bool do_file, bool handle_as_special_cd = false); - void complete_special_cd(const wcstring &str); - void complete_cmd(const wcstring &str, bool use_function, bool use_builtin, bool use_command, bool use_implicit_cd); diff --git a/src/env.cpp b/src/env.cpp index 36e84e396..78512c23e 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -630,8 +630,7 @@ static void react_to_variable_change(const wcstring &key) { } else if (key == L"FISH_READ_BYTE_LIMIT") { env_set_read_limit(); } else if (key == L"FISH_HISTORY") { - history_destroy(); - reader_push(history_session_id().c_str()); + reader_change_history(history_session_id().c_str()); } } diff --git a/src/env_universal_common.cpp b/src/env_universal_common.cpp index c340e5961..00228113f 100644 --- a/src/env_universal_common.cpp +++ b/src/env_universal_common.cpp @@ -1209,7 +1209,7 @@ class universal_notifier_named_pipe_t : public universal_notifier_t { // would cause us to hang! size_t read_amt = 64 * 1024; void *buff = malloc(read_amt); - read_ignore(this->pipe_fd, buff, read_amt); + (void)read(this->pipe_fd, buff, read_amt); free(buff); } @@ -1308,7 +1308,7 @@ class universal_notifier_named_pipe_t : public universal_notifier_t { while (this->readback_amount > 0) { char buff[64]; size_t amt_to_read = mini(this->readback_amount, sizeof buff); - read_ignore(this->pipe_fd, buff, amt_to_read); + (void)read(this->pipe_fd, buff, amt_to_read); this->readback_amount -= amt_to_read; } assert(this->readback_amount == 0); diff --git a/src/expand.cpp b/src/expand.cpp index 029c0af76..e00a1bff0 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -492,7 +492,7 @@ static bool find_job(const wchar_t *proc, expand_flags_t flags, while (const job_t *j = jobs.next()) { if (j->command_is_empty()) continue; - size_t offset; + size_t offset = 0; if (match_pid(j->command(), proc, &offset)) { if (flags & EXPAND_FOR_COMPLETIONS) { append_completion(completions, j->command_wcstr() + offset + wcslen(proc), @@ -514,7 +514,7 @@ static bool find_job(const wchar_t *proc, expand_flags_t flags, for (const process_ptr_t &p : j->processes) { if (p->actual_cmd.empty()) continue; - size_t offset; + size_t offset = 0; if (match_pid(p->actual_cmd, proc, &offset)) { if (flags & EXPAND_FOR_COMPLETIONS) { append_completion(completions, wcstring(p->actual_cmd, offset + wcslen(proc)), @@ -552,7 +552,7 @@ static void find_process(const wchar_t *proc, expand_flags_t flags, pid_t process_pid; process_iterator_t iterator; while (iterator.next_process(&process_name, &process_pid)) { - size_t offset; + size_t offset = 0; if (match_pid(process_name, proc, &offset)) { if (flags & EXPAND_FOR_COMPLETIONS) { append_completion(out, process_name.c_str() + offset + wcslen(proc), diff --git a/src/path.cpp b/src/path.cpp index fcb383474..7af742974 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -275,7 +275,7 @@ static void maybe_issue_path_warning(const wcstring &which_dir, const wcstring & debug(0, _(L"The error was '%s'."), strerror(saved_errno)); debug(0, _(L"Please set $%ls to a directory where you have write access."), env_var); } - write(STDERR_FILENO, "\n", 1); + (void)write(STDERR_FILENO, "\n", 1); } static void path_create(wcstring &path, const wcstring &xdg_var, const wcstring &which_dir, diff --git a/src/reader.cpp b/src/reader.cpp index 3e15b4b4e..72271f858 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -696,14 +696,14 @@ void reader_write_title(const wcstring &cmd, bool reset_cursor_position) { for (size_t i = 0; i < lst.size(); i++) { fputws(lst.at(i).c_str(), stdout); } - write(STDOUT_FILENO, "\a", 1); + (void)write(STDOUT_FILENO, "\a", 1); } proc_pop_interactive(); set_color(rgb_color_t::reset(), rgb_color_t::reset()); if (reset_cursor_position && !lst.empty()) { // Put the cursor back at the beginning of the line (issue #2453). - write(STDOUT_FILENO, "\r", 1); + (void)write(STDOUT_FILENO, "\r", 1); } } @@ -1291,7 +1291,7 @@ static void reader_flash() { } reader_repaint(); - write(STDOUT_FILENO, "\a", 1); + (void)write(STDOUT_FILENO, "\a", 1); pollint.tv_sec = 0; pollint.tv_nsec = 100 * 1000000; @@ -1983,6 +1983,11 @@ static parser_test_error_bits_t default_test(const wchar_t *b) { return 0; } +void reader_change_history(const wchar_t *name) { + data->history->save(); + data->history = &history_t::history_with_name(name); +} + void reader_push(const wchar_t *name) { reader_data_t *n = new reader_data_t(); @@ -3217,7 +3222,7 @@ const wchar_t *reader_readline(int nchars) { reader_repaint_if_needed(); } - write(STDOUT_FILENO, "\n", 1); + (void)write(STDOUT_FILENO, "\n", 1); // Ensure we have no pager contents when we exit. if (!data->pager.empty()) { diff --git a/src/reader.h b/src/reader.h index c773ea1ed..3dc0d0802 100644 --- a/src/reader.h +++ b/src/reader.h @@ -72,6 +72,9 @@ const wchar_t *reader_current_filename(); /// \param fn The fileanme to push void reader_push_current_filename(const wchar_t *fn); +/// Change the history file for the current command reading context. +void reader_change_history(const wchar_t *fn); + /// Pop the current filename from the stack of read files. void reader_pop_current_filename(); diff --git a/src/wutil.cpp b/src/wutil.cpp index 5b69c47f4..fd1586950 100644 --- a/src/wutil.cpp +++ b/src/wutil.cpp @@ -338,7 +338,7 @@ void safe_perror(const char *message) { safe_append(buff, safe_strerror(err), sizeof buff); safe_append(buff, "\n", sizeof buff); - write_ignore(STDERR_FILENO, buff, strlen(buff)); + (void)write(STDERR_FILENO, buff, strlen(buff)); errno = err; }