From 488a09fffbdbd2cc737a688ff9b38d86f74a9f9b Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Fri, 7 Oct 2016 23:52:33 -0700 Subject: [PATCH 01/42] Don't prefer clang++ This change causes our configure script to just use the default behavior of autoconf: in practice it will try g++ instead of clang++ first. There are good reasons to use the behavior this reverts, namely g++ might be a symlink to clang++ and clang++ is never a symlink to g++ - when `configure` says using "g++" that doens't tell us much. On more systems than not, as far as I can tell, clang++ will often be a newer compiler than g++ from what I can see as well. However, it appears we have some bad things happening with Cygwin on clang. Fixes #3435 --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 2df950807..a72c8b8bd 100644 --- a/configure.ac +++ b/configure.ac @@ -87,9 +87,9 @@ fi # So ensure this happens before we modify CXXFLAGS below # Do CC also, because PCRE2 will use it. Prefer clang++, # targets like FreeBSD ship an ancient one. -AC_PROG_CC([clang llvm-gcc gcc cc]) +AC_PROG_CC AC_PROG_CC_STDC # c99 -AC_PROG_CXX([clang++ llvm-g++ g++ c++]) +AC_PROG_CXX AC_LANG(C++) AC_PROG_INSTALL AC_PROG_LN_S From 8d40bf325de2c79b89e87de24d05293e4d054a81 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 8 Oct 2016 16:08:37 -0700 Subject: [PATCH 02/42] Fix configure.ac comments --- configure.ac | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index a72c8b8bd..0f7aec665 100644 --- a/configure.ac +++ b/configure.ac @@ -85,8 +85,7 @@ fi # Set up various programs needed for install # Note AC_PROG_CXX sets CXXFLAGS if not set, which we want # So ensure this happens before we modify CXXFLAGS below -# Do CC also, because PCRE2 will use it. Prefer clang++, -# targets like FreeBSD ship an ancient one. +# Do CC also, because PCRE2 will use it. AC_PROG_CC AC_PROG_CC_STDC # c99 AC_PROG_CXX From 5d4fffcae4ff24a9fb205cf99421c7e98ba009dd Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sun, 9 Oct 2016 07:09:52 -0700 Subject: [PATCH 03/42] Remove nan() fallback We stopped using nan() when @krader1961 changed the timef() function a while back. I removed the autoconf check recently as well. --- src/fallback.cpp | 4 ---- src/fallback.h | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/fallback.cpp b/src/fallback.cpp index c3ef3462f..cc12d53c9 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -255,10 +255,6 @@ int killpg(int pgr, int sig) { } #endif -#ifndef HAVE_NAN -double nan(char *tagp) { return 0.0 / 0.0; } -#endif - // Big hack to use our versions of wcswidth where we know them to be broken, which is // EVERYWHERE (https://github.com/fish-shell/fish-shell/issues/2199) #ifndef HAVE_BROKEN_WCWIDTH diff --git a/src/fallback.h b/src/fallback.h index 7a609b8dd..49120c901 100644 --- a/src/fallback.h +++ b/src/fallback.h @@ -125,8 +125,4 @@ char *fish_textdomain(const char *domainname); int killpg(int pgr, int sig); #endif -#ifndef HAVE_NAN -double nan(char *tagp); -#endif - #endif From 30e56c02371dbbb8177675b8cfe0c477f68982ba Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sun, 9 Oct 2016 07:27:00 -0700 Subject: [PATCH 04/42] Make calc_prompt_layout detect bright escapes --- src/screen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screen.cpp b/src/screen.cpp index a59c60882..29d9639a9 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -214,7 +214,7 @@ size_t escape_code_length(const wchar_t *code) { for (size_t p = 0; p < sizeof esc / sizeof *esc && !found; p++) { if (!esc[p]) continue; - for (size_t k = 0; k < 8; k++) { + for (size_t k = 0; k < std::min(16, static_cast(max_colors)); k++) { size_t len = try_sequence(tparm(esc[p], k), code); if (len) { resulting_length = len; From 213ef3ee561de1a25b065203175bf5896f01dba7 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Sun, 9 Oct 2016 14:11:04 -0700 Subject: [PATCH 05/42] don't produce *.pyc files Producing man pages is done infrequently (basically just at `make test` and `make install`) so there isn't any point in writing compiled byte-code versions of the python modules. --- share/tools/create_manpage_completions.py | 30 +++++++++++------------ share/tools/deroff.py | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/share/tools/create_manpage_completions.py b/share/tools/create_manpage_completions.py index 87c9b93b8..b8b3aa104 100755 --- a/share/tools/create_manpage_completions.py +++ b/share/tools/create_manpage_completions.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python -B # -*- coding: utf-8 -*- # Run me like this: ./create_manpage_completions.py /usr/share/man/man{1,8}/* > man_completions.fish @@ -115,7 +115,7 @@ def lossy_unicode(s): except UnicodeEncodeError: pass return s.decode('latin-1', 'ignore') - + def output_complete_command(cmdname, args, description, output_list): comps = ['complete -c', cmdname] @@ -163,31 +163,31 @@ def built_command(options, description): else: ELLIPSIS_CODE_POINT = 0x2026 truncation_suffix = unichr(ELLIPSIS_CODE_POINT) - + # Try to include as many whole sentences as will fit # Clean up some probably bogus escapes in the process clean_desc = description.replace("\\'", "'").replace("\\.", ".") sentences = clean_desc.split('.') - + # Clean up "sentences" that are just whitespace # But don't let it be empty sentences = [x for x in sentences if x.strip()] if not sentences: sentences = [''] udot = lossy_unicode('.') - uspace = lossy_unicode(' ') - - truncated_description = lossy_unicode(sentences[0]) + udot + uspace = lossy_unicode(' ') + + truncated_description = lossy_unicode(sentences[0]) + udot for line in sentences[1:]: if not line: continue - proposed_description = lossy_unicode(truncated_description) + uspace + lossy_unicode(line) + udot + proposed_description = lossy_unicode(truncated_description) + uspace + lossy_unicode(line) + udot if len(proposed_description) <= max_description_width: # It fits truncated_description = proposed_description else: # No fit break - + # If the first sentence does not fit, truncate if necessary if len(truncated_description) > max_description_width: prefix_len = max_description_width - len(truncation_suffix) @@ -504,7 +504,7 @@ class TypeDarwinManParser(ManParser): # Skip leading groff crud while re.match('[A-Z][a-z]\s', line): line = line[3:] - + # If the line ends with a space and then a period or comma, then erase the space # This hack handles lines of the form '.Ar projectname .' if line.endswith(' ,') or line.endswith(' .'): @@ -551,10 +551,10 @@ class TypeDarwinManParser(ManParser): # Get the line and clean it up line = lines.pop(0) - + # Try to guess how many dashes this argument has dash_count = self.count_argument_dashes(line) - + line = self.groff_replace_escapes(line) line = self.trim_groff(line) line = line.strip() @@ -661,7 +661,7 @@ def file_is_overwritable(path): file.close() return result - + # Remove any and all autogenerated completions in the given directory def cleanup_autogenerated_completions_in_directory(dir): try: @@ -895,7 +895,7 @@ if __name__ == "__main__": print(err.msg) # will print something like "option -a not recognized" usage(script_name) sys.exit(2) - + # Directories within which we will clean up autogenerated completions # This script originally wrote completions into ~/.config/fish/completions # Now it writes them into a separate directory @@ -935,7 +935,7 @@ if __name__ == "__main__": if not file_paths: print("No paths specified") sys.exit(0) - + if not WRITE_TO_STDOUT and not output_directory: # Default to ~/.local/share/fish/generated_completions/ # Create it if it doesn't exist diff --git a/share/tools/deroff.py b/share/tools/deroff.py index 214f2815a..02ba52538 100755 --- a/share/tools/deroff.py +++ b/share/tools/deroff.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python -B # -*- coding: utf-8 -*- """ Deroff.py, ported to Python from the venerable deroff.c """ From 851e44934780f469927f19770d0fc65d82bed129 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Sun, 9 Oct 2016 14:36:08 -0700 Subject: [PATCH 06/42] eliminate signed/unsigned comparison warnings This partially addresses #3430. --- src/builtin.cpp | 2 +- src/common.cpp | 2 +- src/common.h | 14 ++++++------- src/env_universal_common.cpp | 6 +++--- src/event.cpp | 2 +- src/expand.cpp | 5 ++--- src/history.cpp | 6 ++++-- src/input.cpp | 4 ++-- src/output.cpp | 2 +- src/pager.cpp | 31 ++++++++++++++--------------- src/pager.h | 18 ++++++++--------- src/parse_util.cpp | 38 ++++++++++++------------------------ src/reader.cpp | 2 +- src/screen.cpp | 10 +++++----- src/utf8.cpp | 9 ++++----- src/wutil.cpp | 2 +- 16 files changed, 70 insertions(+), 83 deletions(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index 7621cf46d..fd4d89d0d 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -2001,7 +2001,7 @@ static int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) line = reader_readline(nchars); proc_pop_interactive(); if (line) { - if (0 < nchars && nchars < wcslen(line)) { + if (0 < nchars && (size_t)nchars < wcslen(line)) { // Line may be longer than nchars if a keybinding used `commandline -i` // note: we're deliberately throwing away the tail of the commandline. // It shouldn't be unread because it was produced with `commandline -i`, diff --git a/src/common.cpp b/src/common.cpp index 539cd2133..5287f359e 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -118,7 +118,7 @@ show_stackframe(const wchar_t msg_level, int frame_count, int skip_levels) { if (frame_count < 1) frame_count = 999; debug_shared(msg_level, L"Backtrace:"); std::vector bt = demangled_backtrace(frame_count, skip_levels + 2); - for (int i = 0; i < bt.size(); i++) { + for (int i = 0; (size_t)i < bt.size(); i++) { debug_shared(msg_level, bt[i]); } } diff --git a/src/common.h b/src/common.h index 5a961054a..ba404e6e1 100644 --- a/src/common.h +++ b/src/common.h @@ -52,8 +52,8 @@ typedef std::vector wcstring_list_t; // Use Unicode "noncharacters" for internal characters as much as we can. This // gives us 32 "characters" for internal use that we can guarantee should not // appear in our input stream. See http://www.unicode.org/faq/private_use.html. -#define RESERVED_CHAR_BASE 0xFDD0u -#define RESERVED_CHAR_END 0xFDF0u +#define RESERVED_CHAR_BASE (wchar_t)0xFDD0 +#define RESERVED_CHAR_END (wchar_t)0xFDF0 // Split the available noncharacter values into two ranges to ensure there are // no conflicts among the places we use these special characters. #define EXPAND_RESERVED_BASE RESERVED_CHAR_BASE @@ -63,9 +63,9 @@ typedef std::vector wcstring_list_t; // Make sure the ranges defined above don't exceed the range for noncharacters. // This is to make sure we didn't do something stupid in subdividing the // Unicode range for our needs. -#if WILDCARD_RESERVED_END > RESERVED_CHAR_END -#error -#endif +//#if WILDCARD_RESERVED_END > RESERVED_CHAR_END +//#error +//#endif // These are in the Unicode private-use range. We really shouldn't use this // range but have little choice in the matter given how our lexer/parser works. @@ -79,9 +79,9 @@ typedef std::vector wcstring_list_t; // Note: We don't use the highest 8 bit range (0xF800 - 0xF8FF) because we know // of at least one use of a codepoint in that range: the Apple symbol (0xF8FF) // on Mac OS X. See http://www.unicode.org/faq/private_use.html. -#define ENCODE_DIRECT_BASE 0xF600u +#define ENCODE_DIRECT_BASE (wchar_t)0xF600 #define ENCODE_DIRECT_END (ENCODE_DIRECT_BASE + 256) -#define INPUT_COMMON_BASE 0xF700u +#define INPUT_COMMON_BASE (wchar_t)0xF700 #define INPUT_COMMON_END (INPUT_COMMON_BASE + 64) // Flags for unescape_string functions. diff --git a/src/env_universal_common.cpp b/src/env_universal_common.cpp index bb997e46d..fd889fcf5 100644 --- a/src/env_universal_common.cpp +++ b/src/env_universal_common.cpp @@ -826,7 +826,7 @@ var_table_t env_universal_t::read_message_internal(int fd) { // Walk over it by lines. The contents of an unterminated line will be left in 'line' for // the next iteration. - size_t line_start = 0; + ssize_t line_start = 0; while (line_start < amt) { // Run until we hit a newline. size_t cursor = line_start; @@ -1033,7 +1033,7 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t { } // Set the size, if it's too small. - if (!errored && size < sizeof(universal_notifier_shmem_t)) { + if (!errored && size < (off_t)sizeof(universal_notifier_shmem_t)) { if (ftruncate(fd, sizeof(universal_notifier_shmem_t)) < 0) { int err = errno; report_error(err, L"Unable to truncate shared memory object with path '%s'", path); @@ -1120,7 +1120,7 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t { // If it's been less than five seconds since the last change, we poll quickly Otherwise we // poll more slowly. Note that a poll is a very cheap shmem read. The bad part about making // this high is the process scheduling/wakeups it produces. - unsigned long usec_per_sec = 1000000; + long long usec_per_sec = 1000000; if (get_time() - last_change_time < 5LL * usec_per_sec) { return usec_per_sec / 10; // 10 times a second } diff --git a/src/event.cpp b/src/event.cpp index 84a4d31e6..143992c7e 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -301,7 +301,7 @@ int event_get(const event_t &criterion, std::vector *out) { bool event_is_signal_observed(int sig) { // We are in a signal handler! Don't allocate memory, etc. bool result = false; - if (sig >= 0 && sig < sizeof s_observed_signals / sizeof *s_observed_signals) { + if (sig >= 0 && (unsigned long)sig < sizeof(s_observed_signals) / sizeof(*s_observed_signals)) { result = s_observed_signals[sig]; } return result; diff --git a/src/expand.cpp b/src/expand.cpp index 1b80fd334..af0ad2e91 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -756,13 +756,12 @@ static int expand_variables(const wcstring &instr, std::vector *ou for (long i = last_idx - 1; (i >= 0) && is_ok && !empty; i--) { const wchar_t c = instr.at(i); if ((c == VARIABLE_EXPAND) || (c == VARIABLE_EXPAND_SINGLE)) { - long start_pos = i + 1; - long stop_pos; + size_t start_pos = i + 1; + size_t stop_pos; long var_len; int is_single = (c == VARIABLE_EXPAND_SINGLE); stop_pos = start_pos; - while (stop_pos < insize) { const wchar_t nc = instr.at(stop_pos); if (nc == VARIABLE_EXPAND_EMPTY) { diff --git a/src/history.cpp b/src/history.cpp index 16c8fab26..c8f3f31ba 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -562,7 +562,7 @@ static size_t offset_of_next_item_fish_2_0(const char *begin, size_t mmap_length // leading "- cmd: - cmd: - cmd:". Trim all but one leading "- cmd:". const char *double_cmd = "- cmd: - cmd: "; const size_t double_cmd_len = strlen(double_cmd); - while (a_newline - line_start > double_cmd_len && + while ((size_t)(a_newline - line_start) > double_cmd_len && !memcmp(line_start, double_cmd, double_cmd_len)) { // Skip over just one of the - cmd. In the end there will be just one left. line_start += strlen("- cmd: "); @@ -572,8 +572,10 @@ static size_t offset_of_next_item_fish_2_0(const char *begin, size_t mmap_length // 123456". Ignore those. const char *cmd_when = "- cmd: when:"; const size_t cmd_when_len = strlen(cmd_when); - if (a_newline - line_start >= cmd_when_len && !memcmp(line_start, cmd_when, cmd_when_len)) + if ((size_t)(a_newline - line_start) >= cmd_when_len && + !memcmp(line_start, cmd_when, cmd_when_len)) { continue; + } // At this point, we know line_start is at the beginning of an item. But maybe we want to // skip this item because of timestamps. A 0 cutoff means we don't care; if we do care, then diff --git a/src/input.cpp b/src/input.cpp index 1fc1eb601..1e6d9b726 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -124,7 +124,7 @@ static const wchar_t *const name_arr[] = {L"beginning-of-line", wcstring describe_char(wint_t c) { wint_t initial_cmd_char = R_BEGINNING_OF_LINE; - size_t name_count = sizeof name_arr / sizeof *name_arr; + long name_count = sizeof(name_arr) / sizeof(*name_arr); if (c >= initial_cmd_char && c < initial_cmd_char + name_count) { return format_string(L"%02x (%ls)", c, name_arr[c - initial_cmd_char]); } @@ -535,7 +535,7 @@ static void input_mapping_execute_matching_or_generic(bool allow_commands) { const wcstring bind_mode = input_get_bind_mode(); - for (int i = 0; i < mapping_list.size(); i++) { + for (size_t i = 0; i < mapping_list.size(); i++) { const input_mapping_t &m = mapping_list.at(i); // debug(0, L"trying mapping (%ls,%ls,%ls)\n", escape(m.seq.c_str(), ESCAPE_ALL).c_str(), diff --git a/src/output.cpp b/src/output.cpp index 7a4cd5524..d6e81b695 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -49,7 +49,7 @@ void output_set_writer(int (*writer)(char)) { int (*output_get_writer())(char) { return out; } /// Returns true if we think tparm can handle outputting a color index -static bool term_supports_color_natively(unsigned int c) { return max_colors >= (c + 1); } +static bool term_supports_color_natively(unsigned int c) { return (unsigned)max_colors >= c + 1; } color_support_t output_get_color_support(void) { return color_support; } diff --git a/src/pager.cpp b/src/pager.cpp index 385b48057..44e189bc7 100644 --- a/src/pager.cpp +++ b/src/pager.cpp @@ -50,8 +50,8 @@ static size_t divide_round_up(size_t numer, size_t denom) { void pager_t::recalc_min_widths(comp_info_list_t *lst) const { for (size_t i = 0; i < lst->size(); i++) { comp_t *c = &lst->at(i); - c->min_width = mini(c->desc_width, maxi(0, available_term_width / 3 - 2)) + - mini(c->desc_width, maxi(0, available_term_width / 5 - 4)) + 4; + c->min_width = mini(c->desc_width, maxi((size_t)0, available_term_width / 3 - 2)) + + mini(c->desc_width, maxi((size_t)0, available_term_width / 5 - 4)) + 4; } } @@ -84,14 +84,13 @@ static int print_max(const wcstring &str, highlight_spec_t color, int max, bool /// Print the specified item using at the specified amount of space. line_t pager_t::completion_print_item(const wcstring &prefix, const comp_t *c, size_t row, - size_t column, int width, bool secondary, bool selected, + size_t column, size_t width, bool secondary, bool selected, page_rendering_t *rendering) const { - int comp_width = 0, desc_width = 0; - int written = 0; - + size_t comp_width = 0, desc_width = 0; + size_t written = 0; line_t line_data; - if (c->pref_width <= width) { + if (c->pref_width <= (size_t)width) { // The entry fits, we give it as much space as it wants. comp_width = c->comp_width; desc_width = c->desc_width; @@ -379,12 +378,12 @@ bool pager_t::completion_try_print(size_t cols, const wcstring &prefix, const co bool print = false; // Compute the effective term width and term height, accounting for disclosure. - int term_width = this->available_term_width; - int term_height = + size_t term_width = this->available_term_width; + size_t term_height = this->available_term_height - 1 - (search_field_shown ? 1 : 0); // we always subtract 1 to make room for a comment row if (!this->fully_disclosed) { - term_height = mini(term_height, PAGER_UNDISCLOSED_MAX_ROWS); + term_height = mini(term_height, (size_t)PAGER_UNDISCLOSED_MAX_ROWS); } size_t row_count = divide_round_up(lst.size(), cols); @@ -404,15 +403,15 @@ bool pager_t::completion_try_print(size_t cols, const wcstring &prefix, const co rendering->remaining_to_disclose = 0; } - int pref_tot_width = 0; - int min_tot_width = 0; + size_t pref_tot_width = 0; + size_t min_tot_width = 0; // Skip completions on tiny terminals. if (term_width < PAGER_MIN_WIDTH) return true; // Calculate how wide the list would be. - for (long col = 0; col < cols; col++) { - for (long row = 0; row < row_count; row++) { + for (size_t col = 0; col < cols; col++) { + for (size_t row = 0; row < row_count; row++) { int pref, min; const comp_t *c; if (lst.size() <= col * row_count + row) continue; @@ -526,7 +525,7 @@ page_rendering_t pager_t::render() const { rendering.search_field_shown = this->search_field_shown; rendering.search_field_line = this->search_field_line; - for (int cols = PAGER_MAX_COLS; cols > 0; cols--) { + for (size_t cols = PAGER_MAX_COLS; cols > 0; cols--) { // Initially empty rendering. rendering.screen_data.resize(0); @@ -641,7 +640,7 @@ bool pager_t::select_next_completion_in_direction(selection_direction_t directio // Cardinal directions. We have a completion index; we wish to compute its row and column. size_t current_row = this->get_selected_row(rendering); size_t current_col = this->get_selected_column(rendering); - size_t page_height = maxi(rendering.term_height - 1, 1); + size_t page_height = maxi(rendering.term_height - 1, (size_t)1); switch (direction) { case direction_page_north: { diff --git a/src/pager.h b/src/pager.h index c0b322522..3f7bfce0d 100644 --- a/src/pager.h +++ b/src/pager.h @@ -17,8 +17,8 @@ /// Represents rendering from the pager. class page_rendering_t { public: - int term_width; - int term_height; + size_t term_width; + size_t term_height; size_t rows; size_t cols; size_t row_start; @@ -47,8 +47,8 @@ page_rendering_t render_completions(const completion_list_t &raw_completions, const wcstring &prefix); class pager_t { - int available_term_width; - int available_term_height; + size_t available_term_width; + size_t available_term_height; size_t selected_completion_idx; size_t suggested_row_start; @@ -73,13 +73,13 @@ class pager_t { /// The representative completion. completion_t representative; /// On-screen width of the completion string. - int comp_width; + size_t comp_width; /// On-screen width of the description information. - int desc_width; + size_t desc_width; /// Preferred total width. - int pref_width; + size_t pref_width; /// Minimum acceptable width. - int min_width; + size_t min_width; comp_t() : comp(), @@ -114,7 +114,7 @@ class pager_t { const wcstring &prefix, const comp_info_list_t &lst, page_rendering_t *rendering) const; line_t completion_print_item(const wcstring &prefix, const comp_t *c, size_t row, size_t column, - int width, bool secondary, bool selected, + size_t width, bool secondary, bool selected, page_rendering_t *rendering) const; public: diff --git a/src/parse_util.cpp b/src/parse_util.cpp index bb8f08fdc..509c6a612 100644 --- a/src/parse_util.cpp +++ b/src/parse_util.cpp @@ -67,16 +67,11 @@ size_t parse_util_get_offset_from_line(const wcstring &str, int line) { size_t i; int count = 0; - if (line < 0) { - return (size_t)-1; - } - + if (line < 0) return (size_t)-1; if (line == 0) return 0; for (i = 0;; i++) { - if (!buff[i]) { - return -1; - } + if (!buff[i]) return (size_t)-1; if (buff[i] == L'\n') { count++; @@ -91,25 +86,18 @@ size_t parse_util_get_offset(const wcstring &str, int line, long line_offset) { const wchar_t *buff = str.c_str(); size_t off = parse_util_get_offset_from_line(buff, line); size_t off2 = parse_util_get_offset_from_line(buff, line + 1); - long line_offset2 = line_offset; - if (off == (size_t)(-1)) { - return -1; + if (off == (size_t)-1) return (size_t)-1; + + if (off2 == (size_t)-1) off2 = wcslen(buff) + 1; + + if (line_offset < 0) line_offset = 0; + + if ((size_t)line_offset >= off2 - off - 1) { + line_offset = off2 - off - 1; } - if (off2 == (size_t)(-1)) { - off2 = wcslen(buff) + 1; - } - - if (line_offset2 < 0) { - line_offset2 = 0; - } - - if (line_offset2 >= off2 - off - 1) { - line_offset2 = off2 - off - 1; - } - - return off + line_offset2; + return off + line_offset; } static int parse_util_locate_brackets_of_type(const wchar_t *in, wchar_t **begin, wchar_t **end, @@ -305,7 +293,7 @@ static void job_or_process_extent(const wchar_t *buff, size_t cursor_pos, const return; } - assert(cursor_pos >= (begin - buff)); + assert(cursor_pos >= (size_t)(begin - buff)); const size_t pos = cursor_pos - (begin - buff); if (a) *a = begin; @@ -369,7 +357,7 @@ void parse_util_token_extent(const wchar_t *buff, size_t cursor_pos, const wchar } // pos is equivalent to cursor_pos within the range of the command substitution {begin, end}. - long offset_within_cmdsubst = cursor_pos - (cmdsubst_begin - buff); + size_t offset_within_cmdsubst = cursor_pos - (cmdsubst_begin - buff); a = cmdsubst_begin + offset_within_cmdsubst; b = a; diff --git a/src/reader.cpp b/src/reader.cpp index 60682673a..2ba41732d 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2743,7 +2743,7 @@ const wchar_t *reader_readline(int nchars) { if (data->search_mode) { data->search_mode = NO_SEARCH; - if (data->token_history_pos == -1) { + if (data->token_history_pos == (size_t)-1) { // history_reset(); data->history_search.go_to_end(); reader_set_buffer(data->search_buff, data->search_buff.size()); diff --git a/src/screen.cpp b/src/screen.cpp index 29d9639a9..093fd9989 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -388,13 +388,12 @@ static void s_desired_append_char(screen_t *s, wchar_t b, int c, int indent, siz int line_no = s->desired.cursor.y; if (b == L'\n') { - int i; // Current line is definitely hard wrapped. s->desired.create_line(s->desired.line_count()); s->desired.line(s->desired.cursor.y).is_soft_wrapped = false; s->desired.cursor.y++; s->desired.cursor.x = 0; - for (i = 0; i < prompt_width + indent * INDENT_STEP; i++) { + for (size_t i = 0; i < prompt_width + indent * INDENT_STEP; i++) { s_desired_append_char(s, L' ', 0, indent, prompt_width); } } else if (b == L'\r') { @@ -732,7 +731,7 @@ static void s_update(screen_t *scr, const wchar_t *left_prompt, const wchar_t *r // avoid repeatedly outputting it. const size_t shared_prefix = line_shared_prefix(o_line, s_line); if (shared_prefix > 0) { - int prefix_width = fish_wcswidth(&o_line.text.at(0), shared_prefix); + size_t prefix_width = fish_wcswidth(&o_line.text.at(0), shared_prefix); if (prefix_width > skip_remaining) skip_remaining = prefix_width; } @@ -754,7 +753,7 @@ static void s_update(screen_t *scr, const wchar_t *left_prompt, const wchar_t *r // Skip over skip_remaining width worth of characters. size_t j = 0; for (; j < o_line.size(); j++) { - int width = fish_wcwidth_min_0(o_line.char_at(j)); + size_t width = fish_wcwidth_min_0(o_line.char_at(j)); if (skip_remaining < width) break; skip_remaining -= width; current_width += width; @@ -772,7 +771,8 @@ static void s_update(screen_t *scr, const wchar_t *left_prompt, const wchar_t *r // the screen after we output into the last column, it can erase the last character due // to the sticky right cursor. If we clear the screen too early, we can defeat soft // wrapping. - if (j + 1 == screen_width && should_clear_screen_this_line && !has_cleared_screen) { + if (j + 1 == (size_t)screen_width && should_clear_screen_this_line && + !has_cleared_screen) { s_move(scr, &output, current_width, (int)i); s_write_mbs(&output, clr_eos); has_cleared_screen = true; diff --git a/src/utf8.cpp b/src/utf8.cpp index 8c894800d..535902059 100644 --- a/src/utf8.cpp +++ b/src/utf8.cpp @@ -31,7 +31,7 @@ // We can tweak the following typedef to allow us to simulate Windows-style 16 bit wchar's on Unix. typedef wchar_t utf8_wchar_t; -#define UTF8_WCHAR_MAX ((size_t)std::numeric_limits::max()) +#define UTF8_WCHAR_MAX (wchar_t)std::numeric_limits::max() typedef std::basic_string utf8_wstring_t; @@ -197,7 +197,7 @@ static size_t utf8_to_wchar_internal(const char *in, size_t insize, utf8_wstring } // Does the sequence header tell us truth about length? - if (lim - p <= n - 1) { + if ((size_t)(lim - p) <= n - 1) { if ((flags & UTF8_IGNORE_ERROR) == 0) return 0; n = 1; continue; // skip @@ -238,7 +238,7 @@ static size_t utf8_to_wchar_internal(const char *in, size_t insize, utf8_wstring if (skip) { total--; - } else if (out_val > UTF8_WCHAR_MAX) { + } else if (out_val > (uint32_t)UTF8_WCHAR_MAX) { // wchar_t is UCS-2, but the UTF-8 specified an astral character. return 0; } else { @@ -304,8 +304,7 @@ static size_t wchar_to_utf8_internal(const utf8_wchar_t *in, size_t insize, char total += n; if (out == NULL) continue; - - if (lim - p <= n - 1) return 0; // no space left + if (size_t(lim - p) <= n - 1) return 0; // no space left // Extract the wchar_t as big-endian. If wchar_t is UCS-16, the first two bytes will be 0. unsigned char oc[4]; diff --git a/src/wutil.cpp b/src/wutil.cpp index c21fa199d..6b057545d 100644 --- a/src/wutil.cpp +++ b/src/wutil.cpp @@ -348,7 +348,7 @@ wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path) { if (narrow_res) { real_path.append(narrow_res); } else { - ssize_t pathsep_idx = narrow_path.rfind('/'); + size_t pathsep_idx = narrow_path.rfind('/'); if (pathsep_idx == 0) { // If the only pathsep is the first character then it's an absolute path with a // single path component and thus doesn't need conversion. From c07c98ac05e0ae511babb677b050039d5c0344b4 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Sun, 9 Oct 2016 14:38:26 -0700 Subject: [PATCH 07/42] eliminate many "unused parameter" warnings Partially addresses issue #3430. --- share/functions/history.fish | 2 +- src/autoload.h | 2 +- src/builtin.cpp | 28 +++++++++++++++++++++++++++- src/builtin.h | 3 ++- src/builtin_printf.cpp | 1 + src/builtin_test.cpp | 1 + src/common.cpp | 1 + src/common.h | 6 ++++++ src/env.cpp | 4 ++-- src/env_universal_common.cpp | 6 +++++- src/exec.cpp | 1 + src/expand.cpp | 9 +++++---- src/fallback.cpp | 12 ++++++++++-- src/function.cpp | 1 + src/highlight.cpp | 4 ++++ src/history.cpp | 3 ++- src/iothread.cpp | 1 + src/lru.h | 5 +++-- src/pager.cpp | 8 +++++--- src/parse_execution.cpp | 2 ++ src/parse_productions.cpp | 2 ++ src/postfork.cpp | 1 + src/proc.cpp | 14 +++++++++----- src/reader.cpp | 16 +++++++++++++--- src/reader.h | 2 +- src/screen.cpp | 2 ++ src/signal.cpp | 11 ++++++++++- tests/history.err | 12 ++++++------ 28 files changed, 125 insertions(+), 35 deletions(-) diff --git a/share/functions/history.fish b/share/functions/history.fish index c3dca2b22..286e0dd8e 100644 --- a/share/functions/history.fish +++ b/share/functions/history.fish @@ -22,7 +22,7 @@ function __fish_unexpected_hist_args --no-scope-shadowing return 0 end if set -q argv[1] - printf (_ "%ls: %ls command expected %d args, got %d\n") $cmd $hist_cmd 0 (count $argv) >&2 + printf (_ "%ls: %ls expected %d args, got %d\n") $cmd $hist_cmd 0 (count $argv) >&2 return 0 end return 1 diff --git a/src/autoload.h b/src/autoload.h index a5bd206ce..49891828f 100644 --- a/src/autoload.h +++ b/src/autoload.h @@ -82,7 +82,7 @@ class autoload_t : private lru_cache_t { protected: /// Overridable callback for when a command is removed. - virtual void command_removed(const wcstring &cmd) {} + virtual void command_removed(const wcstring &cmd) { UNUSED(cmd); } public: /// Create an autoload_t for the given environment variable name. diff --git a/src/builtin.cpp b/src/builtin.cpp index fd4d89d0d..d21d81f53 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -123,6 +123,7 @@ static int count_char(const wchar_t *str, wchar_t c) { /// A wcstring with a formatted manpage. /// wcstring builtin_help_get(parser_t &parser, io_streams_t &streams, const wchar_t *name) { + UNUSED(parser); // This won't ever work if no_exec is set. if (no_exec) return wcstring(); @@ -1294,6 +1295,7 @@ static bool builtin_echo_parse_numeric_sequence(const wchar_t *str, size_t *cons /// Bash only respects -n if it's the first argument. We'll do the same. We also support a new /// option -s to mean "no spaces" static int builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **argv) { + UNUSED(parser); // Skip first arg if (!*argv++) return STATUS_BUILTIN_ERROR; @@ -1446,6 +1448,12 @@ static int builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **argv) /// The pwd builtin. We don't respect -P to resolve symbolic links because we /// try to always resolve them. static int builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv) { + UNUSED(parser); + if (argv[1] != NULL) { + streams.err.append_format(BUILTIN_ERR_ARG_COUNT1, argv[0], 0, builtin_count_args(argv)); + return STATUS_BUILTIN_ERROR; + } + wcstring res = wgetcwd(); if (res.empty()) { return STATUS_BUILTIN_ERROR; @@ -2402,6 +2410,7 @@ static int builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv) { /// Implementation of the builtin count command, used to count the number of arguments sent to it. static int builtin_count(parser_t &parser, io_streams_t &streams, wchar_t **argv) { + UNUSED(parser); int argc; argc = builtin_count_args(argv); streams.out.append_format(L"%d\n", argc - 1); @@ -2726,6 +2735,11 @@ static int builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar /// Implementation of the builtin breakpoint command, used to launch the interactive debugger. static int builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t **argv) { + if (argv[1] != NULL) { + streams.err.append_format(BUILTIN_ERR_ARG_COUNT1, argv[0], 0, builtin_count_args(argv)); + return STATUS_BUILTIN_ERROR; + } + parser.push_block(new breakpoint_block_t()); reader_read(STDIN_FILENO, streams.io_chain ? *streams.io_chain : io_chain_t()); @@ -2846,7 +2860,7 @@ static bool set_hist_cmd(wchar_t *const cmd, hist_cmd_t *hist_cmd, hist_cmd_t su break; \ } \ if (args.size() != 0) { \ - streams.err.append_format(BUILTIN_ERR_ARG_COUNT, cmd, \ + streams.err.append_format(BUILTIN_ERR_ARG_COUNT2, cmd, \ hist_cmd_to_string(hist_cmd).c_str(), 0, args.size()); \ status = STATUS_BUILTIN_ERROR; \ break; \ @@ -3094,10 +3108,22 @@ int builtin_parse(parser_t &parser, io_streams_t &streams, wchar_t **argv) #endif int builtin_true(parser_t &parser, io_streams_t &streams, wchar_t **argv) { + UNUSED(parser); + UNUSED(streams); + if (argv[1] != NULL) { + streams.err.append_format(BUILTIN_ERR_ARG_COUNT1, argv[0], 0, builtin_count_args(argv)); + return STATUS_BUILTIN_ERROR; + } return STATUS_BUILTIN_OK; } int builtin_false(parser_t &parser, io_streams_t &streams, wchar_t **argv) { + UNUSED(parser); + UNUSED(streams); + if (argv[1] != NULL) { + streams.err.append_format(BUILTIN_ERR_ARG_COUNT1, argv[0], 0, builtin_count_args(argv)); + return STATUS_BUILTIN_ERROR; + } return STATUS_BUILTIN_ERROR; } diff --git a/src/builtin.h b/src/builtin.h index 45c0b0f9a..b76f75a35 100644 --- a/src/builtin.h +++ b/src/builtin.h @@ -53,7 +53,8 @@ enum { COMMAND_NOT_BUILTIN, BUILTIN_REGULAR, BUILTIN_FUNCTION }; #define BUILTIN_ERR_UNKNOWN _(L"%ls: Unknown option '%ls'\n") /// Error message for unexpected args. -#define BUILTIN_ERR_ARG_COUNT _(L"%ls: %ls command expected %d args, got %d\n") +#define BUILTIN_ERR_ARG_COUNT1 _(L"%ls: expected %d args, got %d\n") +#define BUILTIN_ERR_ARG_COUNT2 _(L"%ls: %ls expected %d args, got %d\n") /// Error message for invalid character in variable name. #define BUILTIN_ERR_VARCHAR \ diff --git a/src/builtin_printf.cpp b/src/builtin_printf.cpp index 35e5b18d4..7442673fe 100644 --- a/src/builtin_printf.cpp +++ b/src/builtin_printf.cpp @@ -695,6 +695,7 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch /// The printf builtin. int builtin_printf(parser_t &parser, io_streams_t &streams, wchar_t **argv) { + UNUSED(parser); builtin_printf_state_t state(streams); wchar_t *format; diff --git a/src/builtin_test.cpp b/src/builtin_test.cpp index b0a131026..334cbfb50 100644 --- a/src/builtin_test.cpp +++ b/src/builtin_test.cpp @@ -771,6 +771,7 @@ static bool unary_primary_evaluate(test_expressions::token_t token, const wcstri /// /// Return status is the final shell status, i.e. 0 for true, 1 for false and 2 for error. int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) { + UNUSED(parser); using namespace test_expressions; // The first argument should be the name of the command ('test'). diff --git a/src/common.cpp b/src/common.cpp index 5287f359e..9f7d9c504 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -1340,6 +1340,7 @@ bool unescape_string(const wcstring &input, wcstring *output, unescape_flags_t e void common_handle_winch(int signal) { // Don't run ioctl() here, it's not safe to use in signals. + UNUSED(signal); termsize_valid = false; } diff --git a/src/common.h b/src/common.h index ba404e6e1..c6aa76449 100644 --- a/src/common.h +++ b/src/common.h @@ -766,4 +766,10 @@ __attribute__((noinline)) void debug_thread_error(void); /// specified base, return -1. long convert_digit(wchar_t d, int base); +/// This is a macro that can be used to silence "unused parameter" warnings from the compiler for +/// functions which need to accept parameters they do not use because they need to be compatible +/// with an interface. It's similar to the Python idiom of doing `_ = expr` at the top of a +/// function in the same situation. +#define UNUSED(expr) do { (void)(expr); } while (0) + #endif diff --git a/src/env.cpp b/src/env.cpp index cf0f0d02b..f34ee9c27 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -267,7 +267,7 @@ static void react_to_variable_change(const wcstring &key) { /// Universal variable callback function. This function makes sure the proper events are triggered /// when an event occurs. -static void universal_callback(fish_message_type_t type, const wchar_t *name, const wchar_t *val) { +static void universal_callback(fish_message_type_t type, const wchar_t *name) { const wchar_t *str = NULL; switch (type) { @@ -1102,7 +1102,7 @@ void env_universal_barrier() { // Post callbacks. for (size_t i = 0; i < changes.size(); i++) { const callback_data_t &data = changes.at(i); - universal_callback(data.type, data.key.c_str(), data.val.c_str()); + universal_callback(data.type, data.key.c_str()); } } } diff --git a/src/env_universal_common.cpp b/src/env_universal_common.cpp index fd889fcf5..a77eb6a6e 100644 --- a/src/env_universal_common.cpp +++ b/src/env_universal_common.cpp @@ -1299,6 +1299,7 @@ class universal_notifier_named_pipe_t : public universal_notifier_t { // select() on our fd for a while, and sync periodically until the fd is no longer readable. // However, if we are the one who posted the notification, we don't sync (until we clean // up!) + UNUSED(fd); bool should_sync = false; if (readback_time_usec == 0) { polling_due_to_readable_fd = true; @@ -1494,4 +1495,7 @@ bool universal_notifier_t::poll() { return false; } unsigned long universal_notifier_t::usec_delay_between_polls() const { return 0; } -bool universal_notifier_t::notification_fd_became_readable(int fd) { return false; } +bool universal_notifier_t::notification_fd_became_readable(int fd) { + UNUSED(fd); + return false; +} diff --git a/src/exec.cpp b/src/exec.cpp index 7d826766d..777f8e354 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -159,6 +159,7 @@ char *get_interpreter(const char *command, char *interpreter, size_t buff_size) /// specified in \c p. It never returns. Called in a forked child! Do not allocate memory, etc. static void safe_launch_process(process_t *p, const char *actual_cmd, const char *const *cargv, const char *const *cenvv) { + UNUSED(p); int err; // debug( 1, L"exec '%ls'", p->argv[0] ); diff --git a/src/expand.cpp b/src/expand.cpp index af0ad2e91..1c2a92eb1 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -212,7 +212,7 @@ static int iswnumeric(const wchar_t *n) { } /// See if the process described by \c proc matches the commandline \c cmd. -static bool match_pid(const wcstring &cmd, const wchar_t *proc, int flags, size_t *offset) { +static bool match_pid(const wcstring &cmd, const wchar_t *proc, size_t *offset) { // Test for a direct match. If the proc string is empty (e.g. the user tries to complete against // %), then return an offset pointing at the base command. That ensures that you don't see a // bunch of dumb paths when completing against all processes. @@ -507,7 +507,7 @@ static int find_job(const struct find_job_data_t *info) { if (j->command_is_empty()) continue; size_t offset; - if (match_pid(j->command(), proc, flags, &offset)) { + if (match_pid(j->command(), proc, &offset)) { if (flags & EXPAND_FOR_COMPLETIONS) { append_completion(&completions, j->command_wcstr() + offset + wcslen(proc), COMPLETE_JOB_DESC, 0); @@ -527,7 +527,7 @@ static int find_job(const struct find_job_data_t *info) { if (p->actual_cmd.empty()) continue; size_t offset; - if (match_pid(p->actual_cmd, proc, flags, &offset)) { + if (match_pid(p->actual_cmd, proc, &offset)) { if (flags & EXPAND_FOR_COMPLETIONS) { append_completion(&completions, wcstring(p->actual_cmd, offset + wcslen(proc)), @@ -570,7 +570,7 @@ static void find_process(const wchar_t *proc, expand_flags_t flags, process_iterator_t iterator; while (iterator.next_process(&process_name, &process_pid)) { size_t offset; - if (match_pid(process_name, proc, flags, &offset)) { + if (match_pid(process_name, proc, &offset)) { if (flags & EXPAND_FOR_COMPLETIONS) { append_completion(out, process_name.c_str() + offset + wcslen(proc), COMPLETE_PROCESS_DESC, 0); @@ -1381,6 +1381,7 @@ static expand_error_t expand_stage_home_and_pid(const wcstring &input, static expand_error_t expand_stage_wildcards(const wcstring &input, std::vector *out, expand_flags_t flags, parse_error_list_t *errors) { + UNUSED(errors); expand_error_t result = EXPAND_OK; wcstring path_to_expand = input; diff --git a/src/fallback.cpp b/src/fallback.cpp index cc12d53c9..0c386fa1e 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -39,6 +39,7 @@ #include // IWYU pragma: keep #include // IWYU pragma: keep +#include "common.h" // IWYU pragma: keep #include "fallback.h" // IWYU pragma: keep #include "util.h" // IWYU pragma: keep @@ -244,8 +245,15 @@ char *fish_bindtextdomain(const char *domainname, const char *dirname) { char *fish_textdomain(const char *domainname) { return textdomain(domainname); } #else char *fish_gettext(const char *msgid) { return (char *)msgid; } -char *fish_bindtextdomain(const char *domainname, const char *dirname) { return NULL; } -char *fish_textdomain(const char *domainname) { return NULL; } +char *fish_bindtextdomain(const char *domainname, const char *dirname) { + UNUSED(domainname); + UNUSED(dirname); + return NULL; +} +char *fish_textdomain(const char *domainname) { + UNUSED(domainname); + return NULL; +} #endif #ifndef HAVE_KILLPG diff --git a/src/function.cpp b/src/function.cpp index 6b8d4c7fb..34dbd85cd 100644 --- a/src/function.cpp +++ b/src/function.cpp @@ -158,6 +158,7 @@ function_info_t::function_info_t(const function_info_t &data, const wchar_t *fil shadow_scope(data.shadow_scope) {} void function_add(const function_data_t &data, const parser_t &parser, int definition_line_offset) { + UNUSED(parser); ASSERT_IS_MAIN_THREAD(); CHECK(!data.name.empty(), ); diff --git a/src/highlight.cpp b/src/highlight.cpp index 49dd2f065..21b75bce3 100644 --- a/src/highlight.cpp +++ b/src/highlight.cpp @@ -1186,6 +1186,7 @@ const highlighter_t::color_array_t &highlighter_t::highlight() { void highlight_shell(const wcstring &buff, std::vector &color, size_t pos, wcstring_list_t *error, const env_vars_snapshot_t &vars) { + UNUSED(error); // Do something sucky and get the current working directory on this background thread. This // should really be passed in. const wcstring working_directory = env_get_pwd_slash(); @@ -1197,6 +1198,7 @@ void highlight_shell(const wcstring &buff, std::vector &color, void highlight_shell_no_io(const wcstring &buff, std::vector &color, size_t pos, wcstring_list_t *error, const env_vars_snapshot_t &vars) { + UNUSED(error); // Do something sucky and get the current working directory on this background thread. This // should really be passed in. const wcstring working_directory = env_get_pwd_slash(); @@ -1291,6 +1293,8 @@ static void highlight_universal_internal(const wcstring &buffstr, void highlight_universal(const wcstring &buff, std::vector &color, size_t pos, wcstring_list_t *error, const env_vars_snapshot_t &vars) { + UNUSED(error); + UNUSED(vars); assert(buff.size() == color.size()); std::fill(color.begin(), color.end(), 0); highlight_universal_internal(buff, color, pos); diff --git a/src/history.cpp b/src/history.cpp index c8f3f31ba..4a6d19629 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -1662,7 +1662,8 @@ static int threaded_perform_file_detection(file_detection_context_t *ctx) { } static void perform_file_detection_done(file_detection_context_t *ctx, - int success) { //!OCLINT(success is ignored) + int success) { + UNUSED(success); ASSERT_IS_MAIN_THREAD(); // Now that file detection is done, update the history item with the valid file paths. diff --git a/src/iothread.cpp b/src/iothread.cpp index 21ca3694c..a83631ef8 100644 --- a/src/iothread.cpp +++ b/src/iothread.cpp @@ -116,6 +116,7 @@ static void *this_thread() { return (void *)(intptr_t)pthread_self(); } /// The function that does thread work. static void *iothread_worker(void *unused) { + UNUSED(unused); scoped_lock locker(s_spawn_queue_lock); struct SpawnRequest_t *req; while ((req = dequeue_spawn_request()) != NULL) { diff --git a/src/lru.h b/src/lru.h index d8a692c2e..1097489d4 100644 --- a/src/lru.h +++ b/src/lru.h @@ -93,7 +93,7 @@ class lru_cache_t { lru_node_t mouth; /// Overridable callback for when a node is evicted. - virtual void node_was_evicted(node_type_t *node) {} + virtual void node_was_evicted(node_type_t *node) { UNUSED(node); } public: /// Constructor @@ -185,7 +185,8 @@ class lru_cache_t { public: explicit iterator(lru_node_t *val) : node(val) {} void operator++() { node = lru_cache_t::get_previous(node); } - void operator++(int x) { node = lru_cache_t::get_previous(node); } + //WTF + //void operator++(int x) { node = lru_cache_t::get_previous(node); } bool operator==(const iterator &other) { return node == other.node; } bool operator!=(const iterator &other) { return !(*this == other); } node_type_t *operator*() { return static_cast(node); } diff --git a/src/pager.cpp b/src/pager.cpp index 44e189bc7..b6663a24b 100644 --- a/src/pager.cpp +++ b/src/pager.cpp @@ -86,6 +86,9 @@ static int print_max(const wcstring &str, highlight_spec_t color, int max, bool line_t pager_t::completion_print_item(const wcstring &prefix, const comp_t *c, size_t row, size_t column, size_t width, bool secondary, bool selected, page_rendering_t *rendering) const { + UNUSED(column); + UNUSED(row); + UNUSED(rendering); size_t comp_width = 0, desc_width = 0; size_t written = 0; line_t line_data; @@ -254,8 +257,7 @@ static void join_completions(comp_info_list_t *comps) { } /// Generate a list of comp_t structures from a list of completions. -static comp_info_list_t process_completions_into_infos(const completion_list_t &lst, - const wcstring &prefix) { +static comp_info_list_t process_completions_into_infos(const completion_list_t &lst) { const size_t lst_size = lst.size(); // Make the list of the correct size up-front. @@ -340,7 +342,7 @@ void pager_t::refilter_completions() { void pager_t::set_completions(const completion_list_t &raw_completions) { // Get completion infos out of it. - unfiltered_completion_infos = process_completions_into_infos(raw_completions, prefix); + unfiltered_completion_infos = process_completions_into_infos(raw_completions); // Maybe join them. if (prefix == L"-") join_completions(&unfiltered_completion_infos); diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 5ee3a12d0..a4a87c99e 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -1076,6 +1076,7 @@ parse_execution_result_t parse_execution_context_t::populate_block_process( job_t *job, process_t *proc, const parse_node_t &statement_node) { // We handle block statements by creating INTERNAL_BLOCK_NODE, that will bounce back to us when // it's time to execute them. + UNUSED(job); assert(statement_node.type == symbol_block_statement || statement_node.type == symbol_if_statement || statement_node.type == symbol_switch_statement); @@ -1133,6 +1134,7 @@ parse_execution_result_t parse_execution_context_t::populate_job_process( parse_execution_result_t parse_execution_context_t::populate_job_from_job_node( job_t *j, const parse_node_t &job_node, const block_t *associated_block) { + UNUSED(associated_block); assert(job_node.type == symbol_job); // Tell the job what its command is. diff --git a/src/parse_productions.cpp b/src/parse_productions.cpp index a9da3b325..3fff5a2b1 100644 --- a/src/parse_productions.cpp +++ b/src/parse_productions.cpp @@ -80,6 +80,7 @@ RESOLVE(job_list) { RESOLVE_ONLY(job) = {symbol_statement, symbol_job_continuation, symbol_optional_background}; RESOLVE(job_continuation) { + UNUSED(out_tag); P empty = {}; P piped = {parse_token_type_pipe, symbol_statement, symbol_job_continuation}; switch (token1.type) { @@ -94,6 +95,7 @@ RESOLVE(job_continuation) { // A statement is a normal command, or an if / while / and etc. RESOLVE(statement) { + UNUSED(out_tag); P boolean = {symbol_boolean_statement}; P block = {symbol_block_statement}; P ifs = {symbol_if_statement}; diff --git a/src/postfork.cpp b/src/postfork.cpp index 1c246a975..5f15f9954 100644 --- a/src/postfork.cpp +++ b/src/postfork.cpp @@ -285,6 +285,7 @@ pid_t execute_fork(bool wait_for_threads_to_die) { bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_file_actions_t *actions, job_t *j, process_t *p, const io_chain_t &io_chain) { + UNUSED(p); // Initialize the output. if (posix_spawnattr_init(attr) != 0) { return false; diff --git a/src/proc.cpp b/src/proc.cpp index 69a53b9c2..1cdaece4f 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -254,12 +254,12 @@ int job_signal(job_t *j, int signal) { int res = 0; if (j->pgid != my_pid) { - res = killpg(j->pgid, SIGHUP); + res = killpg(j->pgid, signal); } else { for (process_t *p = j->first_process; p; p = p->next) { if (!p->completed) { if (p->pid) { - if (kill(p->pid, SIGHUP)) { + if (kill(p->pid, signal)) { res = -1; break; } @@ -272,7 +272,7 @@ int job_signal(job_t *j, int signal) { } /// Store the status of the process pid that was returned by waitpid. -static void mark_process_status(const job_t *j, process_t *p, int status) { +static void mark_process_status(process_t *p, int status) { // debug( 0, L"Process %ls %ls", p->argv[0], WIFSTOPPED (status)?L"stopped":(WIFEXITED( status // )?L"exited":(WIFSIGNALED( status )?L"signaled to exit":L"BLARGH")) ); p->status = status; @@ -291,6 +291,7 @@ static void mark_process_status(const job_t *j, process_t *p, int status) { void job_mark_process_as_failed(const job_t *job, process_t *p) { // The given process failed to even lift off (e.g. posix_spawn failed) and so doesn't have a // valid pid. Mark it as dead. + UNUSED(job); for (process_t *cursor = p; cursor != NULL; cursor = cursor->next) { cursor->completed = 1; } @@ -310,7 +311,7 @@ static void handle_child_status(pid_t pid, int status) { process_t *prev = 0; for (p = j->first_process; p; p = p->next) { if (pid == p->pid) { - mark_process_status(j, p, status); + mark_process_status(p, status); if (p->completed && prev != 0) { if (!prev->completed && prev->pid) { kill(prev->pid, SIGPIPE); @@ -455,7 +456,10 @@ static int process_mark_finished_children(bool wants_await) { } /// This is called from a signal handler. The signal is always SIGCHLD. -void job_handle_signal(int signal, siginfo_t *info, void *con) { +void job_handle_signal(int signal, siginfo_t *info, void *context) { + UNUSED(signal); + UNUSED(info); + UNUSED(context); // This is the only place that this generation count is modified. It's OK if it overflows. s_sigchld_generation_count += 1; } diff --git a/src/reader.cpp b/src/reader.cpp index 2ba41732d..d044a1753 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -468,7 +468,7 @@ static void reader_kill(editable_line_t *el, size_t begin_idx, size_t length, in } // This is called from a signal handler! -void reader_handle_int(int sig) { +void reader_handle_sigint() { if (!is_interactive_read) { parser_t::skip_all_blocks(); } @@ -846,7 +846,10 @@ void reader_repaint_if_needed() { } } -static void reader_repaint_if_needed_one_arg(void *unused) { reader_repaint_if_needed(); } +static void reader_repaint_if_needed_one_arg(void *unused) { + UNUSED(unused); + reader_repaint_if_needed(); +} void reader_react_to_color_change() { if (!data) return; @@ -2003,7 +2006,13 @@ parser_test_error_bits_t reader_shell_test(const wchar_t *b) { /// Test if the given string contains error. Since this is the error detection for general purpose, /// there are no invalid strings, so this function always returns false. -static parser_test_error_bits_t default_test(const wchar_t *b) { return 0; } +/// +/// TODO: Possibly remove this. It is called from only only one place: reader_push().Since it always +/// returns a static result it's not clear why it's needed. +static parser_test_error_bits_t default_test(const wchar_t *b) { + UNUSED(b); + return 0; +} void reader_push(const wchar_t *name) { reader_data_t *n = new reader_data_t(); @@ -2149,6 +2158,7 @@ static void highlight_search(void) { } static void highlight_complete(background_highlight_context_t *ctx, int result) { + UNUSED(result); // ignored because of the indirect invocation via iothread_perform() ASSERT_IS_MAIN_THREAD(); if (ctx->string_to_highlight == data->command_line.text) { // The data hasn't changed, so swap in our colors. The colors may not have changed, so do diff --git a/src/reader.h b/src/reader.h index 61d757167..519aa2a10 100644 --- a/src/reader.h +++ b/src/reader.h @@ -192,7 +192,7 @@ void reader_set_exit_on_interrupt(bool flag); bool shell_is_exiting(); /// The readers interrupt signal handler. Cancels all currently running blocks. -void reader_handle_int(int signal); +void reader_handle_sigint(); /// This function returns true if fish is exiting by force, i.e. because stdin died. int reader_exit_forced(); diff --git a/src/screen.cpp b/src/screen.cpp index 093fd9989..88a97a2dd 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -528,6 +528,7 @@ static void s_move(screen_t *s, data_buffer_t *b, int new_x, int new_y) { /// Set the pen color for the terminal. static void s_set_color(screen_t *s, data_buffer_t *b, highlight_spec_t c) { + UNUSED(s); scoped_buffer_t scoped_buffer(b); unsigned int uc = (unsigned int)c; @@ -893,6 +894,7 @@ static screen_layout_t compute_layout(screen_t *s, size_t screen_width, const wcstring &left_prompt_str, const wcstring &right_prompt_str, const wcstring &commandline, const wcstring &autosuggestion_str, const int *indent) { + UNUSED(s); screen_layout_t result = {}; // Start by ensuring that the prompts themselves can fit. diff --git a/src/signal.cpp b/src/signal.cpp index 213b2ffb7..a20f51cc4 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -192,6 +192,8 @@ const wchar_t *signal_get_desc(int sig) { /// Standard signal handler. static void default_handler(int signal, siginfo_t *info, void *context) { + UNUSED(info); + UNUSED(context); if (event_is_signal_observed(signal)) { event_fire_signal(signal); } @@ -200,6 +202,8 @@ static void default_handler(int signal, siginfo_t *info, void *context) { #ifdef SIGWINCH /// Respond to a winch signal by checking the terminal size. static void handle_winch(int sig, siginfo_t *info, void *context) { + UNUSED(info); + UNUSED(context); common_handle_winch(sig); default_handler(sig, 0, 0); } @@ -208,6 +212,8 @@ static void handle_winch(int sig, siginfo_t *info, void *context) { /// Respond to a hup signal by exiting, unless it is caught by a shellscript function, in which case /// we do nothing. static void handle_hup(int sig, siginfo_t *info, void *context) { + UNUSED(info); + UNUSED(context); if (event_is_signal_observed(SIGHUP)) { default_handler(sig, 0, 0); } else { @@ -217,6 +223,9 @@ static void handle_hup(int sig, siginfo_t *info, void *context) { /// Handle sigterm. The only thing we do is restore the front process ID, then die. static void handle_term(int sig, siginfo_t *info, void *context) { + UNUSED(sig); + UNUSED(info); + UNUSED(context); restore_term_foreground_process_group(); signal(SIGTERM, SIG_DFL); raise(SIGTERM); @@ -225,7 +234,7 @@ static void handle_term(int sig, siginfo_t *info, void *context) { /// Interactive mode ^C handler. Respond to int signal by setting interrupted-flag and stopping all /// loops and conditionals. static void handle_int(int sig, siginfo_t *info, void *context) { - reader_handle_int(sig); + reader_handle_sigint(); default_handler(sig, info, context); } diff --git a/tests/history.err b/tests/history.err index 97f07762f..dcaf16dc2 100644 --- a/tests/history.err +++ b/tests/history.err @@ -2,15 +2,15 @@ history: Invalid combination of options, you cannot do both 'search' and 'merge' in the same invocation history: you cannot use any options with the clear command history: you cannot use any options with the merge command -history: save command expected 0 args, got 1 +history: save expected 0 args, got 1 history: you cannot use any options with the save command history: you cannot use any options with the clear command -history: merge command expected 0 args, got 1 -history: clear command expected 0 args, got 2 +history: merge expected 0 args, got 1 +history: clear expected 0 args, got 2 history: you cannot use any options with the clear command history: you cannot use any options with the merge command -history: save command expected 0 args, got 1 +history: save expected 0 args, got 1 history: you cannot use any options with the clear command history: you cannot use any options with the merge command @@ -18,7 +18,7 @@ history: Invalid combination of options, you cannot do both 'search' and 'merge' in the same invocation history: you cannot use any options with the save command history: you cannot use any options with the clear command -history: merge command expected 0 args, got 1 -history: clear command expected 0 args, got 2 +history: merge expected 0 args, got 1 +history: clear expected 0 args, got 2 history: you cannot use any options with the save command history: you cannot use any options with the merge command From 37c4247cb7d6ee84b7849ec6d557a566ec1b674e Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Sun, 9 Oct 2016 14:41:56 -0700 Subject: [PATCH 08/42] eliminate more "unused parameter" warnings Partially addresses issue #3430. --- src/parse_productions.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/parse_productions.cpp b/src/parse_productions.cpp index 3fff5a2b1..3c1fcbcb2 100644 --- a/src/parse_productions.cpp +++ b/src/parse_productions.cpp @@ -30,6 +30,9 @@ using namespace parse_productions; extern const production_t sym##_only; \ static const production_t *resolve_##sym( \ const parse_token_t &token1, const parse_token_t &token2, parse_node_tag_t *out_tag) { \ + UNUSED(token1); \ + UNUSED(token2); \ + UNUSED(out_tag); \ return &sym##_only; \ } \ const production_t sym##_only @@ -41,6 +44,8 @@ using namespace parse_productions; /// A job_list is a list of jobs, separated by semicolons or newlines. RESOLVE(job_list) { + UNUSED(token2); + UNUSED(out_tag); P list_end = {}; P normal = {symbol_job, symbol_job_list}; P empty_line = {parse_token_type_end, symbol_job_list}; @@ -80,6 +85,7 @@ RESOLVE(job_list) { RESOLVE_ONLY(job) = {symbol_statement, symbol_job_continuation, symbol_optional_background}; RESOLVE(job_continuation) { + UNUSED(token2); UNUSED(out_tag); P empty = {}; P piped = {parse_token_type_pipe, symbol_statement, symbol_job_continuation}; @@ -175,6 +181,8 @@ RESOLVE_ONLY(if_clause) = {KEYWORD(parse_keyword_if), symbol_job, parse_token_ty symbol_andor_job_list, symbol_job_list}; RESOLVE(else_clause) { + UNUSED(token2); + UNUSED(out_tag); P empty = {}; P else_cont = {KEYWORD(parse_keyword_else), symbol_else_continuation}; switch (token1.keyword) { @@ -186,6 +194,8 @@ RESOLVE(else_clause) { } RESOLVE(else_continuation) { + UNUSED(token2); + UNUSED(out_tag); P elseif = {symbol_if_clause, symbol_else_clause}; P elseonly = {parse_token_type_end, symbol_job_list}; @@ -202,6 +212,8 @@ RESOLVE_ONLY(switch_statement) = { symbol_case_item_list, symbol_end_command, symbol_arguments_or_redirections_list}; RESOLVE(case_item_list) { + UNUSED(token2); + UNUSED(out_tag); P empty = {}; P case_item = {symbol_case_item, symbol_case_item_list}; P blank_line = {parse_token_type_end, symbol_case_item_list}; @@ -217,6 +229,7 @@ RESOLVE_ONLY(case_item) = {KEYWORD(parse_keyword_case), symbol_argument_list, pa symbol_job_list}; RESOLVE(andor_job_list) { + UNUSED(out_tag); P list_end = {}; P andor_job = {symbol_job, symbol_andor_job_list}; P empty_line = {parse_token_type_end, symbol_andor_job_list}; @@ -235,6 +248,8 @@ RESOLVE(andor_job_list) { } RESOLVE(argument_list) { + UNUSED(token2); + UNUSED(out_tag); P empty = {}; P arg = {symbol_argument, symbol_argument_list}; switch (token1.type) { @@ -246,6 +261,8 @@ RESOLVE(argument_list) { } RESOLVE(freestanding_argument_list) { + UNUSED(token2); + UNUSED(out_tag); P empty = {}; P arg = {symbol_argument, symbol_freestanding_argument_list}; P semicolon = {parse_token_type_end, symbol_freestanding_argument_list}; @@ -265,6 +282,8 @@ RESOLVE_ONLY(block_statement) = {symbol_block_header, symbol_job_list, symbol_en symbol_arguments_or_redirections_list}; RESOLVE(block_header) { + UNUSED(token2); + UNUSED(out_tag); P forh = {symbol_for_header}; P whileh = {symbol_while_header}; P funch = {symbol_function_header}; @@ -297,6 +316,7 @@ RESOLVE_ONLY(function_header) = {KEYWORD(parse_keyword_function), symbol_argumen // A boolean statement is AND or OR or NOT. RESOLVE(boolean_statement) { + UNUSED(token2); P ands = {KEYWORD(parse_keyword_and), symbol_statement}; P ors = {KEYWORD(parse_keyword_or), symbol_statement}; P nots = {KEYWORD(parse_keyword_not), symbol_statement}; @@ -354,6 +374,8 @@ RESOLVE(decorated_statement) { RESOLVE_ONLY(plain_statement) = {parse_token_type_string, symbol_arguments_or_redirections_list}; RESOLVE(arguments_or_redirections_list) { + UNUSED(token2); + UNUSED(out_tag); P empty = {}; P value = {symbol_argument_or_redirection, symbol_arguments_or_redirections_list}; switch (token1.type) { @@ -366,6 +388,8 @@ RESOLVE(arguments_or_redirections_list) { } RESOLVE(argument_or_redirection) { + UNUSED(token2); + UNUSED(out_tag); P arg = {symbol_argument}; P redir = {symbol_redirection}; switch (token1.type) { @@ -383,6 +407,7 @@ RESOLVE_ONLY(argument) = {parse_token_type_string}; RESOLVE_ONLY(redirection) = {parse_token_type_redirection, parse_token_type_string}; RESOLVE(optional_background) { + UNUSED(token2); P empty = {}; P background = {parse_token_type_background}; switch (token1.type) { From a5034874ab71c2baaaab1e4753ebfbf4ee063dc8 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Sun, 9 Oct 2016 14:43:25 -0700 Subject: [PATCH 09/42] eliminate warnings in auxiliary programs Partially addresses issue #3430. --- src/fish_indent.cpp | 4 +++- src/fish_key_reader.cpp | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/fish_indent.cpp b/src/fish_indent.cpp index d2e9856c6..7f8df7cab 100644 --- a/src/fish_indent.cpp +++ b/src/fish_indent.cpp @@ -84,7 +84,9 @@ static void dump_node(indent_t node_indent, const parse_node_t &node, const wcst wcstring source_txt = L""; if (node.source_start != SOURCE_OFFSET_INVALID && node.source_length != SOURCE_OFFSET_INVALID) { int nextc_idx = node.source_start + node.source_length; - if (nextc_idx < source.size()) nextc = source[node.source_start + node.source_length]; + if ((size_t)nextc_idx < source.size()) { + nextc = source[node.source_start + node.source_length]; + } if (node.source_start > 0) prevc = source[node.source_start - 1]; source_txt = source.substr(node.source_start, node.source_length); } diff --git a/src/fish_key_reader.cpp b/src/fish_key_reader.cpp index 7771a6309..c2deb5076 100644 --- a/src/fish_key_reader.cpp +++ b/src/fish_key_reader.cpp @@ -54,7 +54,7 @@ static bool should_exit(wchar_t wc) { } /// Return the name if the recent sequence of characters matches a known terminfo sequence. -static char *const sequence_name(wchar_t wc) { +static char *sequence_name(wchar_t wc) { unsigned char c = wc < 0x80 ? wc : 0; static char recent_chars[8] = {0}; @@ -157,7 +157,7 @@ static void add_char_to_bind_command(wchar_t wc, std::vector &bind_char static void output_bind_command(std::vector &bind_chars) { if (bind_chars.size()) { fputs("bind ", stdout); - for (int i = 0; i < bind_chars.size(); i++) { + for (size_t i = 0; i < bind_chars.size(); i++) { fputs(char_to_symbol(bind_chars[i], true), stdout); } fputs(" 'do something'\n", stdout); From 92e14d7e4a3c832f238e9dbe829f387b87f07412 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Sun, 9 Oct 2016 15:09:44 -0700 Subject: [PATCH 10/42] deal with Linux shebang handling The Linux kernel only splits on the first whitespace in the shebang line (unlike BSD which splits on all whitespace). Which means there can be only one argument after the path to the program. --- share/tools/create_manpage_completions.py | 3 ++- share/tools/deroff.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/share/tools/create_manpage_completions.py b/share/tools/create_manpage_completions.py index b8b3aa104..837760262 100755 --- a/share/tools/create_manpage_completions.py +++ b/share/tools/create_manpage_completions.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python -B +#!/usr/bin/env python # -*- coding: utf-8 -*- # Run me like this: ./create_manpage_completions.py /usr/share/man/man{1,8}/* > man_completions.fish @@ -20,6 +20,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND import string, sys, re, os.path, bz2, gzip, traceback, getopt, errno, codecs from deroff import Deroffer +sys.dont_write_bytecode = True lzma_available = True try: try: diff --git a/share/tools/deroff.py b/share/tools/deroff.py index 02ba52538..f0fe1be6c 100755 --- a/share/tools/deroff.py +++ b/share/tools/deroff.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python -B +#!/usr/bin/env python # -*- coding: utf-8 -*- """ Deroff.py, ported to Python from the venerable deroff.c """ @@ -6,6 +6,7 @@ import sys, re, string +sys.dont_write_bytecode = True IS_PY3 = sys.version_info[0] >= 3 class Deroffer: From f33ece11ace7e91fb021d2db43f76d2bb46fba19 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Sun, 9 Oct 2016 18:42:55 -0700 Subject: [PATCH 11/42] simplify invoking create_manpage_completions.py My previous change to avoid creating a *.pyc file when running create_manpage_completions.py was wrong because I put the `sys.dont_write_bytecode = True` on the wrong line. Rather than simply move that statement make the simpler, cleaner, fix that removes the need for `eval` where that program is invoked. --- share/functions/fish_update_completions.fish | 2 +- share/tools/create_manpage_completions.py | 1 - share/tools/deroff.py | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/share/functions/fish_update_completions.fish b/share/functions/fish_update_completions.fish index 5928b3784..17b47ecb9 100644 --- a/share/functions/fish_update_completions.fish +++ b/share/functions/fish_update_completions.fish @@ -1,4 +1,4 @@ function fish_update_completions --description "Update man-page based completions" # Clean up old paths - eval (string escape $__fish_datadir/tools/create_manpage_completions.py) --manpath --progress --cleanup-in '~/.config/fish/completions' --cleanup-in '~/.config/fish/generated_completions' + python -B $__fish_datadir/tools/create_manpage_completions.py --manpath --progress --cleanup-in '~/.config/fish/completions' --cleanup-in '~/.config/fish/generated_completions' end diff --git a/share/tools/create_manpage_completions.py b/share/tools/create_manpage_completions.py index 837760262..a65c057bb 100755 --- a/share/tools/create_manpage_completions.py +++ b/share/tools/create_manpage_completions.py @@ -20,7 +20,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND import string, sys, re, os.path, bz2, gzip, traceback, getopt, errno, codecs from deroff import Deroffer -sys.dont_write_bytecode = True lzma_available = True try: try: diff --git a/share/tools/deroff.py b/share/tools/deroff.py index f0fe1be6c..4ef4fb690 100755 --- a/share/tools/deroff.py +++ b/share/tools/deroff.py @@ -3,10 +3,8 @@ """ Deroff.py, ported to Python from the venerable deroff.c """ - import sys, re, string -sys.dont_write_bytecode = True IS_PY3 = sys.version_info[0] >= 3 class Deroffer: From 4ffc6e02b726dc1de4c407bcb2e113de22864c75 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Sun, 9 Oct 2016 19:52:02 -0700 Subject: [PATCH 12/42] fix a couple of "unused parameter" warnings This fixes two of the three "unused parameter" compiler warnings in the fish_tests.cpp module. The third I'm deferring to issue #3439. --- src/fish_tests.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index a8a4b30cd..323570718 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -2165,8 +2165,7 @@ static void test_autosuggest_suggest_special() { if (system("rm -Rf ~/test_autosuggest_suggest_special/")) err(L"rm failed"); } -static void perform_one_autosuggestion_should_ignore_test(const wcstring &command, - const wcstring &wd, long line) { +static void perform_one_autosuggestion_should_ignore_test(const wcstring &command, long line) { completion_list_t comps; complete(command, &comps, COMPLETION_REQUEST_AUTOSUGGESTION, env_vars_snapshot_t::current()); do_test(comps.empty()); @@ -2181,10 +2180,10 @@ static void test_autosuggestion_ignores() { say(L"Testing scenarios that should produce no autosuggestions"); const wcstring wd = L"/tmp/autosuggest_test/"; // Do not do file autosuggestions immediately after certain statement terminators - see #1631. - perform_one_autosuggestion_should_ignore_test(L"echo PIPE_TEST|", wd, __LINE__); - perform_one_autosuggestion_should_ignore_test(L"echo PIPE_TEST&", wd, __LINE__); - perform_one_autosuggestion_should_ignore_test(L"echo PIPE_TEST#comment", wd, __LINE__); - perform_one_autosuggestion_should_ignore_test(L"echo PIPE_TEST;", wd, __LINE__); + perform_one_autosuggestion_should_ignore_test(L"echo PIPE_TEST|", __LINE__); + perform_one_autosuggestion_should_ignore_test(L"echo PIPE_TEST&", __LINE__); + perform_one_autosuggestion_should_ignore_test(L"echo PIPE_TEST#comment", __LINE__); + perform_one_autosuggestion_should_ignore_test(L"echo PIPE_TEST;", __LINE__); } static void test_autosuggestion_combining() { @@ -3844,6 +3843,7 @@ static void test_env_vars(void) { /// Main test. int main(int argc, char **argv) { + UNUSED(argc); // Look for the file tests/test.fish. We expect to run in a directory containing that file. // If we don't find it, walk up the directory hierarchy until we do, or error. while (access("./tests/test.fish", F_OK) != 0) { From 14efcb7cc53ac8db583c32f15427ff13284befed Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sun, 9 Oct 2016 21:58:14 -0700 Subject: [PATCH 13/42] escape_code_length: cast to size_t, not int --- src/screen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screen.cpp b/src/screen.cpp index 88a97a2dd..40bc5cbee 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -214,7 +214,7 @@ size_t escape_code_length(const wchar_t *code) { for (size_t p = 0; p < sizeof esc / sizeof *esc && !found; p++) { if (!esc[p]) continue; - for (size_t k = 0; k < std::min(16, static_cast(max_colors)); k++) { + for (size_t k = 0; k < std::min(16UL, static_cast(max_colors)); k++) { size_t len = try_sequence(tparm(esc[p], k), code); if (len) { resulting_length = len; From ea3e144f2dd06c1f51229686b308b83f12ab6afc Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Mon, 10 Oct 2016 11:50:39 -0700 Subject: [PATCH 14/42] Fix warning: Found unknown command `\args' The problem was that 'cd' is a builtin. Thanks @MarkGriffiths Fixes #3418 --- doc_src/bind.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc_src/bind.txt b/doc_src/bind.txt index c76795e4d..a9148a1b5 100644 --- a/doc_src/bind.txt +++ b/doc_src/bind.txt @@ -131,7 +131,7 @@ The following special input functions are available: \subsection bind-example Examples \fish -bind \\cd 'exit' +bind \\cd 'exit' \endfish Causes `fish` to exit when @key{Control,D} is pressed. From f4647048848fa5256183671c4bb11b9113753def Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Mon, 10 Oct 2016 11:56:25 -0700 Subject: [PATCH 15/42] escape_code_length: test all setaf parameters Taking a different approach here. I can't see why we'd only want to recognize certain colors. Now, we'll just try all the colors fish might use. This could probably be optimized now that there are more than 8 (or 16) colors fish can do. --- src/screen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/screen.cpp b/src/screen.cpp index 40bc5cbee..82a711763 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -205,7 +205,7 @@ size_t escape_code_length(const wchar_t *code) { bool found = false; if (cur_term != NULL) { - // Detect these terminfo color escapes with parameter value 0..16, all of which don't move + // Detect these terminfo color escapes with parameter value up to max_colors-1, all of which don't move // the cursor. char *const esc[] = { set_a_foreground, set_a_background, set_foreground, set_background, @@ -214,7 +214,7 @@ size_t escape_code_length(const wchar_t *code) { for (size_t p = 0; p < sizeof esc / sizeof *esc && !found; p++) { if (!esc[p]) continue; - for (size_t k = 0; k < std::min(16UL, static_cast(max_colors)); k++) { + for (int k = 0; k < (max_colors - 1); k++) { size_t len = try_sequence(tparm(esc[p], k), code); if (len) { resulting_length = len; From d8497f0f1ed243ce8ee8eeeedee6d083183284a9 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Mon, 10 Oct 2016 13:53:11 -0700 Subject: [PATCH 16/42] Use the nonbright variant of brights on lame terms With this change, 'set_color brred; echo bright red' will at leaat be red on Linux/FreeBSD virt consoles. --- src/output.cpp | 8 ++++++++ src/screen.cpp | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/output.cpp b/src/output.cpp index d6e81b695..2533a0dd1 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -71,6 +71,14 @@ static bool write_color_escape(char *todo, unsigned char idx, bool is_fg) { // We are attempting to bypass the term here. Generate the ANSI escape sequence ourself. char buff[16] = ""; if (idx < 16) { + // this allows the non-bright color to happen instead of no color working at all when + // a bright is attempted when only colors 0-7 are supported. + // TODO: enter bold mode in builtin_set_color in the same circumstance- doing that + // combined + // with what we do here, will make the brights actually work for virtual + // consoles/ancient emulators. + if (max_colors == 8 && idx > 8) idx -= 8; + snprintf(buff, sizeof buff, "\x1b[%dm", ((idx > 7) ? 82 : 30) + idx + !is_fg * 10); } else { snprintf(buff, sizeof buff, "\x1b[%d;5;%dm", is_fg ? 38 : 48, idx); diff --git a/src/screen.cpp b/src/screen.cpp index 82a711763..391e3876a 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -214,7 +214,7 @@ size_t escape_code_length(const wchar_t *code) { for (size_t p = 0; p < sizeof esc / sizeof *esc && !found; p++) { if (!esc[p]) continue; - for (int k = 0; k < (max_colors - 1); k++) { + for (short k = 0; k < max_colors; k++) { size_t len = try_sequence(tparm(esc[p], k), code); if (len) { resulting_length = len; From 36f320598e500fc64e58ade73f16a9c1ef220b81 Mon Sep 17 00:00:00 2001 From: Fredrik Fornwall Date: Tue, 11 Oct 2016 00:40:33 +0200 Subject: [PATCH 17/42] Check for struct stat.st_ctime_nsec before using Using a configure check for stat.st_ctime_nsec fixes building on Android which has that field but does not define STAT_HAVE_NSEC. Before this change the Android build failed on the st_ctim.tv_nsec fallback #else clause. --- configure.ac | 1 + src/wutil.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0f7aec665..0e5e13b56 100644 --- a/configure.ac +++ b/configure.ac @@ -284,6 +284,7 @@ AC_DEFINE_UNQUOTED([WCHAR_T_BITS], [$WCHAR_T_BITS], [The size of wchar_t in bits # # Detect nanoseconds fields in struct stat # +AC_CHECK_MEMBERS([struct stat.st_ctime_nsec]) AC_CHECK_MEMBERS([struct stat.st_mtimespec.tv_nsec]) AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec]) diff --git a/src/wutil.cpp b/src/wutil.cpp index 6b057545d..0461b9a38 100644 --- a/src/wutil.cpp +++ b/src/wutil.cpp @@ -548,7 +548,7 @@ file_id_t file_id_t::file_id_from_stat(const struct stat *buf) { result.change_seconds = buf->st_ctime; result.mod_seconds = buf->st_mtime; -#if STAT_HAVE_NSEC +#ifdef HAVE_STRUCT_STAT_ST_CTIME_NSEC result.change_nanoseconds = buf->st_ctime_nsec; result.mod_nanoseconds = buf->st_mtime_nsec; #elif defined(__APPLE__) From cda415cb5d837410291de0c67d488488dfc4a4ef Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Mon, 10 Oct 2016 19:52:22 -0700 Subject: [PATCH 18/42] fix more style bogosities that have crept in --- src/builtin.cpp | 2 +- src/common.h | 5 ++++- src/history.cpp | 5 ++--- src/lru.h | 2 -- src/screen.cpp | 5 +++-- src/utf8.cpp | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index d21d81f53..4d8b09179 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -2860,7 +2860,7 @@ static bool set_hist_cmd(wchar_t *const cmd, hist_cmd_t *hist_cmd, hist_cmd_t su break; \ } \ if (args.size() != 0) { \ - streams.err.append_format(BUILTIN_ERR_ARG_COUNT2, cmd, \ + streams.err.append_format(BUILTIN_ERR_ARG_COUNT2, cmd, \ hist_cmd_to_string(hist_cmd).c_str(), 0, args.size()); \ status = STATUS_BUILTIN_ERROR; \ break; \ diff --git a/src/common.h b/src/common.h index c6aa76449..0cf6a3bc0 100644 --- a/src/common.h +++ b/src/common.h @@ -770,6 +770,9 @@ long convert_digit(wchar_t d, int base); /// functions which need to accept parameters they do not use because they need to be compatible /// with an interface. It's similar to the Python idiom of doing `_ = expr` at the top of a /// function in the same situation. -#define UNUSED(expr) do { (void)(expr); } while (0) +#define UNUSED(expr) \ + do { \ + (void)(expr); \ + } while (0) #endif diff --git a/src/history.cpp b/src/history.cpp index 4a6d19629..fc09dbe0a 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -573,7 +573,7 @@ static size_t offset_of_next_item_fish_2_0(const char *begin, size_t mmap_length const char *cmd_when = "- cmd: when:"; const size_t cmd_when_len = strlen(cmd_when); if ((size_t)(a_newline - line_start) >= cmd_when_len && - !memcmp(line_start, cmd_when, cmd_when_len)) { + !memcmp(line_start, cmd_when, cmd_when_len)) { continue; } @@ -1661,8 +1661,7 @@ static int threaded_perform_file_detection(file_detection_context_t *ctx) { return ctx->perform_file_detection(true /* test all */); } -static void perform_file_detection_done(file_detection_context_t *ctx, - int success) { +static void perform_file_detection_done(file_detection_context_t *ctx, int success) { UNUSED(success); ASSERT_IS_MAIN_THREAD(); diff --git a/src/lru.h b/src/lru.h index 1097489d4..4a7c2dcff 100644 --- a/src/lru.h +++ b/src/lru.h @@ -185,8 +185,6 @@ class lru_cache_t { public: explicit iterator(lru_node_t *val) : node(val) {} void operator++() { node = lru_cache_t::get_previous(node); } - //WTF - //void operator++(int x) { node = lru_cache_t::get_previous(node); } bool operator==(const iterator &other) { return node == other.node; } bool operator!=(const iterator &other) { return !(*this == other); } node_type_t *operator*() { return static_cast(node); } diff --git a/src/screen.cpp b/src/screen.cpp index 391e3876a..a199672fc 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -205,7 +205,8 @@ size_t escape_code_length(const wchar_t *code) { bool found = false; if (cur_term != NULL) { - // Detect these terminfo color escapes with parameter value up to max_colors-1, all of which don't move + // Detect these terminfo color escapes with parameter value up to max_colors-1, all of which + // don't move // the cursor. char *const esc[] = { set_a_foreground, set_a_background, set_foreground, set_background, @@ -773,7 +774,7 @@ static void s_update(screen_t *scr, const wchar_t *left_prompt, const wchar_t *r // to the sticky right cursor. If we clear the screen too early, we can defeat soft // wrapping. if (j + 1 == (size_t)screen_width && should_clear_screen_this_line && - !has_cleared_screen) { + !has_cleared_screen) { s_move(scr, &output, current_width, (int)i); s_write_mbs(&output, clr_eos); has_cleared_screen = true; diff --git a/src/utf8.cpp b/src/utf8.cpp index 535902059..0e87e50ab 100644 --- a/src/utf8.cpp +++ b/src/utf8.cpp @@ -31,7 +31,7 @@ // We can tweak the following typedef to allow us to simulate Windows-style 16 bit wchar's on Unix. typedef wchar_t utf8_wchar_t; -#define UTF8_WCHAR_MAX (wchar_t)std::numeric_limits::max() +#define UTF8_WCHAR_MAX (wchar_t) std::numeric_limits::max() typedef std::basic_string utf8_wstring_t; From 3663726689427c71fd66de66ce587b70bee60798 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Tue, 11 Oct 2016 18:59:45 -0700 Subject: [PATCH 19/42] fix interactive deletion of "all" items While working on making the history command support case-sensitive and insensitive searches I noticed that entering "all" when interactively deleting history entries resulted in an error. That's because the history builtin currently only supports `--exact` so we need to loop over the matching entries and delete them one at a time. Fixes #3448 --- share/functions/history.fish | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/share/functions/history.fish b/share/functions/history.fish index 286e0dd8e..569fd6ef2 100644 --- a/share/functions/history.fish +++ b/share/functions/history.fish @@ -169,7 +169,12 @@ function history --description "display or manipulate interactive command histor if test "$choice" = "all" printf "Deleting all matching entries!\n" - builtin history delete $search_mode -- $argv + # TODO: Use the following when the builtin is enhanced to support the + # --prefix and --contains options (at the moment it only supports --exact). + # builtin history delete $search_mode -- $argv + for item in $found_items + builtin history delete --exact -- $item + end builtin history save return end From d35cbb6594f87f9775d3a802890a02a8f613a14f Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Tue, 11 Oct 2016 20:08:07 -0700 Subject: [PATCH 20/42] fix `string` documentation wrt `--no-quoted` --- doc_src/string.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc_src/string.txt b/doc_src/string.txt index 7eae32155..92b0cb75e 100644 --- a/doc_src/string.txt +++ b/doc_src/string.txt @@ -42,7 +42,7 @@ The following subcommands are available: - `trim` removes leading and trailing whitespace from each STRING. If `-l` or `--left` is given, only leading whitespace is removed. If `-r` or `--right` is given, only trailing whitespace is trimmed. The `-c` or `--chars` switch causes the characters in CHARS to be removed instead of whitespace. Exit status: 0 if at least one character was trimmed, or 1 otherwise. -- `escape` escapes each STRING such that it can be passed back to `eval` to produce the original argument again. By default, all special characters are escaped, and quotes are used to simplify the output when possible. If `-n` or `--no-quote` is given, the simplifying quoted format is not used. Exit status: 0 if at least one string was escaped, or 1 otherwise. +- `escape` escapes each STRING such that it can be passed back to `eval` to produce the original argument again. By default, all special characters are escaped, and quotes are used to simplify the output when possible. If `-n` or `--no-quoted` is given, the simplifying quoted format is not used. Exit status: 0 if at least one string was escaped, or 1 otherwise. - `match` tests each STRING against PATTERN and prints matching substrings. Only the first match for each STRING is reported unless `-a` or `--all` is given, in which case all matches are reported. Matching can be made case-insensitive with `-i` or `--ignore-case`. If `-n` or `--index` is given, each match is reported as a 1-based start position and a length. By default, PATTERN is interpreted as a glob pattern matched against each entire STRING argument. A glob pattern is only considered a valid match if it matches the entire STRING. If `-r` or `--regex` is given, PATTERN is interpreted as a Perl-compatible regular expression, which does not have to match the entire STRING. For a regular expression containing capturing groups, multiple items will be reported for each match, one for the entire match and one for each capturing group. If --invert or -v is used the selected lines will be only those which do not match the given glob pattern or regular expression. Exit status: 0 if at least one match was found, or 1 otherwise. From a3d0ea5c7facff3337ceca6ae6338155983e4737 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Tue, 11 Oct 2016 16:02:50 -0700 Subject: [PATCH 21/42] document making abbreviations global People regularly ask how to make abbreviations global (i.e., private to a fish session) rather than universal. So explain how to do so in the `abbr` man page. Fixes #3446 --- doc_src/abbr.txt | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/doc_src/abbr.txt b/doc_src/abbr.txt index 9e7ebf666..96a499adf 100644 --- a/doc_src/abbr.txt +++ b/doc_src/abbr.txt @@ -2,10 +2,10 @@ \subsection abbr-synopsis Synopsis \fish{synopsis} -abbr -a word phrase... -abbr -s -abbr -l -abbr -e word +abbr --add word phrase... +abbr --show +abbr --list +abbr --erase word \endfish \subsection abbr-description Description @@ -14,11 +14,24 @@ abbr -e word Abbreviations are user-defined character sequences or words that are replaced with longer phrases after they are entered. For example, a frequently-run command such as `git checkout` can be abbreviated to `gco`. After entering `gco` and pressing @key{Space} or @key{Enter}, the full text `git checkout` will appear in the command line. -Abbreviations are stored using universal variables. You can create abbreviations directly on the command line, and they will be saved automatically. Calling `abbr -a` in config.fish will lead to slightly worse startup performance. +Abbreviations are stored in a variable named `fish_user_abbreviations`. This is automatically created as a universal variable the first time an abbreviation is created. If you want your abbreviations to be private to a particular fish session you can put the following in your *~/.config/fish/config.fish* file before you define your first abbrevation: + +\fish +if status --is-interactive + set -g fish_user_abbreviations + abbr --add first 'echo my first abbreviation' + abbr --add second 'echo my second abbreviation' + # etcetera +end +\endfish + +You can create abbreviations directly on the command line and they will be saved automatically and made visible to other fish sessions if `fish_user_abbreviations` is a universal variable. If you keep the variable as universal, a`bbr --add` statements in config.fish will do nothing but slow down startup slightly. + +\subsection abbr-options Options The following parameters are available: -- `-a WORD PHRASE` or `--add WORD PHRASE` Adds a new abbreviation, where WORD will be expanded to PHRASE. +- `-a WORD PHRASE` or `--add WORD PHRASE` Adds a new abbreviation, causing WORD to be expanded to PHRASE. - `-s` or `--show` Show all abbreviated words and their expanded phrases in a manner suitable for export and import. From 1d418365b57436a1d98a0c1f21dadb13dd3255b0 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Wed, 12 Oct 2016 18:04:20 -0700 Subject: [PATCH 22/42] fix misplaced backtick --- doc_src/abbr.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc_src/abbr.txt b/doc_src/abbr.txt index 96a499adf..d34f55e1f 100644 --- a/doc_src/abbr.txt +++ b/doc_src/abbr.txt @@ -25,7 +25,7 @@ if status --is-interactive end \endfish -You can create abbreviations directly on the command line and they will be saved automatically and made visible to other fish sessions if `fish_user_abbreviations` is a universal variable. If you keep the variable as universal, a`bbr --add` statements in config.fish will do nothing but slow down startup slightly. +You can create abbreviations directly on the command line and they will be saved automatically and made visible to other fish sessions if `fish_user_abbreviations` is a universal variable. If you keep the variable as universal, `abbr --add` statements in config.fish will do nothing but slow down startup slightly. \subsection abbr-options Options From 3c0de01c07a057550241ae60e14900886c247caf Mon Sep 17 00:00:00 2001 From: Anmol Sethi Date: Thu, 13 Oct 2016 15:38:22 -0400 Subject: [PATCH 23/42] docs: set should have -x for PATH in config.fish --- doc_src/index.hdr.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc_src/index.hdr.in b/doc_src/index.hdr.in index a31e12917..685a2070f 100644 --- a/doc_src/index.hdr.in +++ b/doc_src/index.hdr.in @@ -1170,7 +1170,7 @@ If you want to add the directory `~/linux/bin` to your PATH variable when using \fish if status --is-login - set PATH $PATH ~/linux/bin + set -x PATH $PATH ~/linux/bin end \endfish From e8ed45ecd3f2c50d342d0f3139ec5558b23d9fa0 Mon Sep 17 00:00:00 2001 From: Anmol Sethi Date: Fri, 14 Oct 2016 17:40:27 -0400 Subject: [PATCH 24/42] docs: fixed incorrect phrasing in Variable expansion section --- doc_src/index.hdr.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc_src/index.hdr.in b/doc_src/index.hdr.in index 685a2070f..3972eabe1 100644 --- a/doc_src/index.hdr.in +++ b/doc_src/index.hdr.in @@ -506,7 +506,7 @@ A dollar sign followed by a string of characters is expanded into the value of t Undefined and empty variables expand to nothing. -To separate a variable name from text it should immediately be followed by, encase the variable within quotes. +To separate a variable name from text encase the variable within double-quotes or braces. Examples: \fish From 4acfdcb0a0d5b26aba0991af4141965e1ca59e3d Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 15 Oct 2016 19:40:17 +0200 Subject: [PATCH 25/42] Remove CDPATH default from docs This was overlooked in 0e4f2cca01ea911e9b6efabe1b2ae4d3eb1d0ec0. --- doc_src/index.hdr.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc_src/index.hdr.in b/doc_src/index.hdr.in index 3972eabe1..07b8eb27c 100644 --- a/doc_src/index.hdr.in +++ b/doc_src/index.hdr.in @@ -813,7 +813,7 @@ The user can change the settings of `fish` by changing the values of certain var - `BROWSER`, the user's preferred web browser. If this variable is set, fish will use the specified browser instead of the system default browser to display the fish documentation. -- `CDPATH`, an array of directories in which to search for the new directory for the `cd` builtin. By default, the fish configuration defines `CDPATH` to be a universal variable with the values `.` and `~`. +- `CDPATH`, an array of directories in which to search for the new directory for the `cd` builtin. - `LANG`, `LC_ALL`, `LC_COLLATE`, `LC_CTYPE`, `LC_MESSAGES`, `LC_MONETARY`, `LC_NUMERIC` and `LC_TIME` set the language option for the shell and subprograms. See the section Locale variables for more information. From 44baf0f9bd87e326cb965987c4939b5b9b9079b4 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 15 Oct 2016 19:50:23 +0200 Subject: [PATCH 26/42] docs: Correct history path. Fixes #3462. --- doc_src/index.hdr.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc_src/index.hdr.in b/doc_src/index.hdr.in index 07b8eb27c..27a7ed9a6 100644 --- a/doc_src/index.hdr.in +++ b/doc_src/index.hdr.in @@ -1105,7 +1105,7 @@ History searches can be aborted by pressing the escape key. Prefixing the commandline with a space will prevent the entire line from being stored in the history. -The history is stored in the file `~/.config/fish/fish_history`. +The history is stored in the file `~/.local/share/fish/fish_history` (or `$XDG_DATA_HOME/fish/fish_history` if that variable is set). Examples: From fe8727fb71848e0508a9b1a2ea35ac9080fd42c8 Mon Sep 17 00:00:00 2001 From: Fredrik Fornwall Date: Sun, 16 Oct 2016 02:20:53 +0200 Subject: [PATCH 27/42] Fix building on Android by avoiding getpwent() (#3441) * Fix building on Android by avoiding getpwent() if missing with autoconf check The getpwent() function does not link when building for Android, and user names on that platform are not interesting anyway. --- configure.ac | 1 + src/complete.cpp | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/configure.ac b/configure.ac index 0e5e13b56..f6558112e 100644 --- a/configure.ac +++ b/configure.ac @@ -302,6 +302,7 @@ AC_CHECK_FUNCS( futimes ) AC_CHECK_FUNCS( wcslcpy lrand48_r killpg ) AC_CHECK_FUNCS( backtrace_symbols getifaddrs ) AC_CHECK_FUNCS( futimens clock_gettime ) +AC_CHECK_FUNCS( getpwent ) AC_CHECK_DECL( [mkostemp], [ AC_CHECK_FUNCS([mkostemp]) ] ) diff --git a/src/complete.cpp b/src/complete.cpp index 5ecf80eb9..9491c58b8 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -1187,6 +1187,13 @@ bool completer_t::try_complete_variable(const wcstring &str) { /// /// \return 0 if unable to complete, 1 otherwise bool completer_t::try_complete_user(const wcstring &str) { +#ifndef HAVE_GETPWENT + // The getpwent() function does not exist on Android. A Linux user on Android isn't + // really a user - each installed app gets an UID assigned. Listing all UID:s is not + // possible without root access, and doing a ~USER type expansion does not make sense + // since every app is sandboxed and can't access eachother. + return false; +#else const wchar_t *cmd = str.c_str(); const wchar_t *first_char = cmd; int res = 0; @@ -1233,6 +1240,7 @@ bool completer_t::try_complete_user(const wcstring &str) { } return res; +#endif } void complete(const wcstring &cmd_with_subcmds, std::vector *out_comps, From 6d322dff73dc3422403180c4caa92c27ab62534e Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 15 Oct 2016 17:29:20 -0700 Subject: [PATCH 28/42] Update osx/config.h Needs update or the undefined symbol should cause the fallback Android behavior on xcode builds inadvertently. --- osx/config.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osx/config.h b/osx/config.h index 33f51aa55..f273f679f 100644 --- a/osx/config.h +++ b/osx/config.h @@ -29,6 +29,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_GETOPT_H 1 +/* Define to 1 if you have the `getpwent' function. */ +#define HAVE_GETPWENT 1 + /* Define to 1 if you have the `gettext' function. */ /* #undef HAVE_GETTEXT */ @@ -86,6 +89,9 @@ /* Define to 1 if `d_type' is a member of `struct dirent'. */ #define HAVE_STRUCT_DIRENT_D_TYPE 1 +/* Define to 1 if `st_ctime_nsec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_CTIME_NSEC */ + /* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */ #define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1 From 36352c037056fa6df2bbac8f5653fa5c6511cf99 Mon Sep 17 00:00:00 2001 From: Olivier Perret Date: Sun, 16 Oct 2016 11:02:12 +0200 Subject: [PATCH 29/42] Add completions for connmanctl (#3419) * Add completions for connmanctl * Move connmanctl functions to completion file * Add description for services completion in connmanctl * Fix connmanctl services completion regex * Also fix connmanctl vpnconnections regex --- share/completions/connmanctl.fish | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 share/completions/connmanctl.fish diff --git a/share/completions/connmanctl.fish b/share/completions/connmanctl.fish new file mode 100644 index 000000000..df97de307 --- /dev/null +++ b/share/completions/connmanctl.fish @@ -0,0 +1,49 @@ +function __fish_print_connman_services + # connmanctl services follows this pattern (to be interpreted as a regex): + # "[\* ][A ][ORacd ] service_name +identification_string" + # where [\* ] indicates whether a service is a favorite + # [A ] indicates whether a service is in autoconnect mode + # [ORacd ] indicates the current status of the service: online, ready, association, configuration, disconnect or idle + connmanctl services | string replace -r '.{4}(.*) +(.*)' '$2\t$1' +end + +function __fish_print_connman_technologies + connmanctl technologies | string match '*Type*' | string replace -r ' Type = (.*)' '$1' +end + +function __fish_print_connman_vpnconnections + # formatting of the vpn connections: + # " [RCF ] service_name +identification_string" + # where [RCF ] indicates the current status which can be: ready, configuration, failure or idle + connmanctl vpnconnections | string replace -r '.{4}(.*) +(.*)' '$2\t$1' +end + +# connmanctl does not accept options before commands, so requiring the commands to be in second position is okay +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "state" -d "Shows if the system is online or offline" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "technologies" -d "Display technologies" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "clock" -d "Get System Clock Properties" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "enable" -d "Enables given technology or offline mode" +complete -f -c connmanctl -n "test (count (commandline -opc)) -eq 2; and contains -- (commandline -opc)[2] enable" -a "(__fish_print_connman_technologies) offline" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "disable" -d "Disables given technology or offline mode" +complete -f -c connmanctl -n "test (count (commandline -opc)) -eq 2; and contains -- (commandline -opc)[2] disable" -a "(__fish_print_connman_technologies) offline" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "tether" -d "Enable, disable tethering, set SSID and passphrase for wifi" +complete -f -c connmanctl -n "test (count (commandline -opc)) -eq 2; and contains -- (commandline -opc)[2] tether" -a "(__fish_print_connman_technologies)" +complete -f -c connmanctl -n "test (count (commandline -opc)) -eq 3; and contains -- (commandline -opc)[2] tether" -a "on off" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "services" -d "Display services" +complete -f -c connmanctl -n "test (count (commandline -opc)) -eq 2; and contains -- (commandline -opc)[2] services" -a "(__fish_print_connman_services)" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "peers" -d "Display peers" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "scan" -d "Scans for new services for given technology" +complete -f -c connmanctl -n "test (count (commandline -opc)) -eq 2; and contains -- (commandline -opc)[2] scan" -a "(__fish_print_connman_technologies)" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "connect" -d "Connect a given service or peer" +complete -f -c connmanctl -n "test (count (commandline -opc)) -eq 2; and contains -- (commandline -opc)[2] connect" -a "(__fish_print_connman_services)" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "disconnect" -d "Disconnect a given service or peer" +complete -f -c connmanctl -n "test (count (commandline -opc)) -eq 2; and contains -- (commandline -opc)[2] disconnect" -a "(__fish_print_connman_services)" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "config" -d "Set service configuration options" +complete -f -c connmanctl -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] config" -a "(__fish_print_connman_services)" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "monitor" -d "Monitor signals from interfaces" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "vpnconnections" -d "Display VPN connections" +complete -f -c connmanctl -n "test (count (commandline -opc)) -eq 2; and contains -- (commandline -opc)[2] vpnconnections" -a "(__fish_print_connman_vpnconnections)" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "session" -d "Enable or disable a session" +complete -f -c connmanctl -n "test (count (commandline -opc)) -eq 2; and contains -- (commandline -opc)[2] session" -a "on off connect disconnect config" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "peer_service" -d "(Un)Register a Peer Service" +complete -f -c connmanctl -n "test (count (commandline -opc)) -lt 2" -a "help" -d "Show help" From 4f95c4b8ac6446e15f867ada22b3affd9dddb90c Mon Sep 17 00:00:00 2001 From: David Adam Date: Sun, 16 Oct 2016 18:43:53 +0800 Subject: [PATCH 30/42] CHANGELOG: update to current git master --- CHANGELOG.md | 53 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d4b0a43a..c918f7c35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,25 +1,42 @@ # next-2.x + ## Significant changes -- The clipboard integration has been revamped with explicit bindings. OS X clipboard support provided for out of the box in addition to X11. (#3061) -- Vi-style bindings no longer build upon the default emacs-style bindings, instead they share some definitions (#3068). -- Fish will now try to set the locale when it doesn't inherit one by reading system configuration (#277) -- A number followed by a caret is no longer treated as a redirection (#1873) +- The clipboard integration has been revamped with explicit bindings. The killring commands no longer copy from, or paste to, the X11 clipboard - use the new copy (`C-x`) and paste (`C-v`) bindings instead. The clipboard is now available on OS X as well as systems using X11 (e.g. Linux). (#3061) +- `history` uses subcommands (`history delete`) rather than options (`history --delete`) for its actions (#3367). New options have been added, including `--max=n` to limit the number of history entries and `--show-time` option to show timestamps (#3175, #3244). +- Vi-style bindings no longer include all of the default emacs-style bindings; instead, they share some definitions (#3068). +- If there is no locale set in the environment, various known system configuration files will be checked for a default (#277). +- A number followed by a caret (e.g. `5^`) is no longer treated as a redirection (#1873). +- The `$version` special variable can be overwritten, so that it can be used for other purposes if required. ## Notable fixes and improvements -- Completions that don't match the prefix will no longer expand to a common prefix (#3090) -- Suggestions will be offered more often, like after removing characters (#3069) -- The argument handling for the `history` function has been revamped (#3293, #3224, #3220, #3182) -- Improved argument handling for the `abbr` function (#2997, #3267) -- `history --merge` now correctly interleaves items in chronological order (#2312) -- `history` gained a new "--with-time" ("-t") option to show timestamps (#3175) -- The "-d" option to `fish_indent` was removed (#3191) -- A bug where fish would sometimes hang using 100% CPU in the C locale (#3214) -- Fish now uses the $TZ variable for its idea of localtime (#3181) -- Some performance improvments to the git prompt (#3294, 3083) -- Working completion after an escaped space character (#2447) -- Less output to fish's build (#3248) -- Some additions or fixes to the completions for `brew` (#3309), `git` (#3274, #3226, #3225, #3094, #3087, #3035, #3021, #2982, #3230), `aura` (#3297) -- New completions for perforce ("p4") (#3314) +- The `fish_realpath` builtin has been renamed to `realpath` and made compatible with GNU `realpath` when run without arguments (#3400). It is used only for systems without a `realpath` or `grealpath` utility (#3374). +- `fish_indent` can now read from named files, rather than just standard input (#3037). +- Fuzzy tab completions behave in a less surprising manner (#3090, #3211). +- `jobs` should only print its header line once (#3127). +- Improved color handling on terminals with limited colors (#3176, #3260). +- Wildcards in redirections are highlighted appropriately (#2789). +- Suggestions will be offered more often, like after removing characters (#3069). +- `history --merge` now correctly interleaves items in chronological order (#2312). +- Options for `fish_indent` have been aligned with the other binaries - in particular, `-d` now means `--debug`. The `--dump` option has been renamed to `--dump-parse-tree` (#3191). +- The display of bindings in the Web-based configuration has been greatly improved (#3325), as has the rendering of prompts (#2924). +- fish should no longer hang using 100% CPU in the C locale (#3214). +- A bug in FreeBSD 11 & 12, Dragonfly BSD & illumos prevented fish from working correctly on these platforms under UTF-8 locales; fish now avoids the buggy behaviour (#3050). +- Prompts which show git repository information (via `__fish_git_prompt`) are faster in large repositories (#3294) and slow filesystems (#3083). +- fish 2.3.0 reintroduced a problem where the greeting was printed even when using `read`; this has been corrected again (#3261). +- Vi mode changes the cursor depending on the current mode (#3215). +- Command lines with escaped space characters at the end tab-complete correctly (#2447). +- Added completions for: + - `arcanist` (#3256) + - `connmanctl` (#3419) + - `figlet` (#3378) + - `mdbook` (#3378) + - `ninja` (#3415) + - `p4`, the Perforce client (#3314) + - `pygmentize` (#3378) + - `ranger` (#3378) +- Improved completions for `aura` (#3297), `abbr` (#3267), `brew` (#3309), `chown` (#3380, #3383),`cygport` (#3392), `git` (#3274, #3226, #3225, #3094, #3087, #3035, #3021, #2982, #3230), `kill & `pkill` (#3200) `screen` (#3271), and `xz` (#3378). +- Distributors, packagers and developers will notice that the build process produces more succinct output by default; use `make V=1` to get verbose output (#3248). +- Improved compatibility with minor platforms including musl (#2988), Cygwin (#2993), Android (#3441, #3442), Haiku (#3322) and Solaris . --- From 170a5ea31cfb1a2573f15a7829f112d5ed9cd96c Mon Sep 17 00:00:00 2001 From: David Adam Date: Sun, 16 Oct 2016 18:56:55 +0800 Subject: [PATCH 31/42] Travis: add a 32-bit build This will help prevent build failures on 32-bit platforms; for example, 14efcb7cc53ac worked on 64-bit platforms but not on 32-bit platforms. --- .travis.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9822f64e2..690506a01 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,17 @@ matrix: - expect - gettext - libncurses5-dev + - os: linux + compiler: gcc + addons: + apt: + packages: + - bc + - expect + - gettext + - libncurses5-dev + env: + - CXXFLAGS="-g -m32" - os: linux compiler: clang addons: @@ -43,7 +54,7 @@ script: - make -j2 - make install - make test DESTDIR=$HOME/prefix/ SHOW_INTERACTIVE_LOG=1 - + notifications: # Some items are encrypted so that notifications from other repositories # don't flood the official repositories. From bb47dfcabcea40f167dd6e8ff74b8c64c2a1adb7 Mon Sep 17 00:00:00 2001 From: David Adam Date: Sun, 16 Oct 2016 19:16:26 +0800 Subject: [PATCH 32/42] Travis: remove some incorrect syntax Introduced in 7b17d20099a021637b3 --- .travis.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 690506a01..44a6a29cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,8 +22,8 @@ matrix: - expect - gettext - libncurses5-dev - env: - - CXXFLAGS="-g -m32" + env: + - CXXFLAGS="-g -m32" - os: linux compiler: clang addons: @@ -33,19 +33,17 @@ matrix: - expect - gettext - libncurses5-dev - env: - - CXXFLAGS="-g -fno-omit-frame-pointer" + env: + - CXXFLAGS="-g -fno-omit-frame-pointer" - os: osx osx_image: xcode8 before_install: - brew update - - brew outdated pcre2 || brew upgrade pcre2 # use system PCRE2 + - brew install pcre2 # use system PCRE2 - brew outdated xctool || brew upgrade xctool # for xcode... soon. - addons: - env: - - CXXFLAGS="-g -fno-omit-frame-pointer -fsanitize=address -lstdc++" - - ASAN_OPTIONS=check_initialization_order=1:detect_stack_use_after_return=1:detect_leaks=1 + env: + - CXXFLAGS="-g -fno-omit-frame-pointer -fsanitize=address -lstdc++" ASAN_OPTIONS=check_initialization_order=1:detect_stack_use_after_return=1:detect_leaks=1 fast_finish: true script: From 0f65d9306bab3c7bfe49ea7948abbcbaea762452 Mon Sep 17 00:00:00 2001 From: David Adam Date: Sun, 16 Oct 2016 20:07:26 +0800 Subject: [PATCH 33/42] Travis: install 32-bit development libraries A 32-bit architecture will need 32-bit libraries. --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 44a6a29cb..bbb504c2f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,9 +21,10 @@ matrix: - bc - expect - gettext - - libncurses5-dev + - lib32ncurses5-dev + - g++-multilib env: - - CXXFLAGS="-g -m32" + - CXXFLAGS="-g -m32" CFLAGS="-g -m32" - os: linux compiler: clang addons: From f48fec31d659dcc6a770d48abe8e95732e9d852e Mon Sep 17 00:00:00 2001 From: David Adam Date: Sun, 16 Oct 2016 20:13:04 +0800 Subject: [PATCH 34/42] Travis: move ASan back to Linux for full features Address Sanitiser on OS X does not support leak detection. --- .travis.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index bbb504c2f..0ea24e0bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,16 +27,21 @@ matrix: - CXXFLAGS="-g -m32" CFLAGS="-g -m32" - os: linux compiler: clang + env: + - CXXFLAGS="-g -fno-omit-frame-pointer -fsanitize=address" ASAN_OPTIONS=check_initialization_order=1:detect_stack_use_after_return=1:detect_leaks=1 + before_install: export CXX=clang++-3.8 addons: apt: + sources: + - llvm-toolchain-precise-3.8 + - ubuntu-toolchain-r-test packages: + - clang-3.8 + - llvm-3.8 # for llvm-symbolizer - bc - expect - gettext - libncurses5-dev - env: - - CXXFLAGS="-g -fno-omit-frame-pointer" - - os: osx osx_image: xcode8 before_install: @@ -44,7 +49,7 @@ matrix: - brew install pcre2 # use system PCRE2 - brew outdated xctool || brew upgrade xctool # for xcode... soon. env: - - CXXFLAGS="-g -fno-omit-frame-pointer -fsanitize=address -lstdc++" ASAN_OPTIONS=check_initialization_order=1:detect_stack_use_after_return=1:detect_leaks=1 + - CXXFLAGS="-g -lstdc++" fast_finish: true script: From d5ca88d42d8d9d40248f824295c74c2346351f51 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sun, 16 Oct 2016 07:17:25 -0700 Subject: [PATCH 35/42] Update CHANGELOG.md Make it clear we now force UTF-8 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c918f7c35..c5d1997e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - The clipboard integration has been revamped with explicit bindings. The killring commands no longer copy from, or paste to, the X11 clipboard - use the new copy (`C-x`) and paste (`C-v`) bindings instead. The clipboard is now available on OS X as well as systems using X11 (e.g. Linux). (#3061) - `history` uses subcommands (`history delete`) rather than options (`history --delete`) for its actions (#3367). New options have been added, including `--max=n` to limit the number of history entries and `--show-time` option to show timestamps (#3175, #3244). - Vi-style bindings no longer include all of the default emacs-style bindings; instead, they share some definitions (#3068). -- If there is no locale set in the environment, various known system configuration files will be checked for a default (#277). +- If there is no locale set in the environment, various known system configuration files will be checked for a default, otherwise forcing en_US-UTF.8 (#277). - A number followed by a caret (e.g. `5^`) is no longer treated as a redirection (#1873). - The `$version` special variable can be overwritten, so that it can be used for other purposes if required. From 4f397e86d7a3cd2023304a19b301c0c8a93715fc Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Sun, 16 Oct 2016 12:43:48 -0700 Subject: [PATCH 36/42] fix use after free bug Fixes #3466 --- src/env.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/env.cpp b/src/env.cpp index f34ee9c27..79a1e0f0c 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -191,7 +191,9 @@ static bool var_is_locale(const wcstring &key) { /// Properly sets all locale information. static void handle_locale(const wchar_t *env_var_name) { debug(2, L"handle_locale() called in response to '%ls' changing", env_var_name); - const char *old_msg_locale = setlocale(LC_MESSAGES, NULL); + // We have to make a copy because the subsequent setlocale() call to change the locale will + // invalidate the pointer from the this setlocale() call. + char *old_msg_locale = strdup(setlocale(LC_MESSAGES, NULL)); const env_var_t val = env_get_string(env_var_name, ENV_EXPORT); const std::string &value = wcs2string(val); const std::string &name = wcs2string(env_var_name); @@ -216,6 +218,7 @@ static void handle_locale(const wchar_t *env_var_name) { _nl_msg_cat_cntr++; } #endif + free(old_msg_locale); } /// Check if the specified variable is a locale variable. From dc6b538f56a61e49421b3544db23260e7eb0982b Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Fri, 14 Oct 2016 20:26:23 -0700 Subject: [PATCH 37/42] improve `set PATH` warning message This modifies the code path for `set PATH` and `set CDPATH` to emit an easier to understand warning when an entry in those vars is invalid. For example $ set PATH $PATH /tmp/arglebargle set: Warning: $PATH entry "/tmp/arglebargle": No such file or directory $ mkdir /tmp/d $ chmod 0 /tmp/d $ set PATH $PATH /tmp/d set: Warning: $PATH entry "/tmp/d": Permission denied $ touch /tmp/x $ set PATH $PATH /tmp/x set: Warning: $PATH entry "/tmp/x": Not a directory Fixes #3450 --- src/builtin_set.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/builtin_set.cpp b/src/builtin_set.cpp index a7f1ddb84..9eeea3172 100644 --- a/src/builtin_set.cpp +++ b/src/builtin_set.cpp @@ -26,7 +26,7 @@ class parser_t; // Error message for invalid path operations. -#define BUILTIN_SET_PATH_ERROR L"%ls: Warning: path component %ls may not be valid in %ls.\n" +#define BUILTIN_SET_PATH_ERROR L"%ls: Warning: $%ls entry \"%ls\" is not valid (%s)\n" // Hint for invalid path operation with a colon. #define BUILTIN_SET_PATH_HINT L"%ls: Did you mean 'set %ls $%ls %ls'?\n" @@ -72,24 +72,25 @@ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope, continue; } - bool show_perror = false; int show_hint = 0; bool error = false; - struct stat buff; - if (wstat(dir, &buff)) { + if (wstat(dir, &buff) == -1) { error = true; - show_perror = true; } - - if (!(S_ISDIR(buff.st_mode))) { + else if (!S_ISDIR(buff.st_mode)) { + error = true; + errno = ENOTDIR; + } + else if (waccess(dir, X_OK) == -1) { error = true; } if (!error) { any_success = true; } else { - streams.err.append_format(_(BUILTIN_SET_PATH_ERROR), L"set", dir.c_str(), key); + streams.err.append_format(_(BUILTIN_SET_PATH_ERROR), L"set", key, dir.c_str(), + strerror(errno)); const wchar_t *colon = wcschr(dir.c_str(), L':'); if (colon && *(colon + 1)) { @@ -97,10 +98,6 @@ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope, } } - if (show_perror) { - builtin_wperror(L"set", streams); - } - if (show_hint) { streams.err.append_format(_(BUILTIN_SET_PATH_HINT), L"set", key, key, wcschr(dir.c_str(), L':') + 1); From f490b563782e952afc5a12c19bcbb0772122ce02 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Fri, 23 Sep 2016 20:12:15 -0700 Subject: [PATCH 38/42] make history searching case insensitive by default Fixes #3236 --- doc_src/history.txt | 10 +++-- share/functions/history.fish | 21 +++++----- src/builtin.cpp | 23 ++++++++--- src/fish_tests.cpp | 74 +++++++++++++++++++++++++-------- src/history.cpp | 80 ++++++++++++++++++++++++++---------- src/history.h | 28 +++++++++---- tests/history.expect | 30 +++++++------- tests/history.expect.out | 3 +- 8 files changed, 186 insertions(+), 83 deletions(-) diff --git a/doc_src/history.txt b/doc_src/history.txt index a7456d837..855a160ee 100644 --- a/doc_src/history.txt +++ b/doc_src/history.txt @@ -2,8 +2,8 @@ \subsection history-synopsis Synopsis \fish{synopsis} -history search [ --show-time ] [ --exact | --prefix | --contains ] [ --max=n ] [ "search string"... ] -history delete [ --show-time ] [ --exact | --prefix | --contains ] "search string"... +history search [ --show-time ] [ --case-sensitive ] [ --exact | --prefix | --contains ] [ --max=n ] [ "search string"... ] +history delete [ --show-time ] [ --case-sensitive ] [ --exact | --prefix | --contains ] "search string"... history merge history save history clear @@ -20,7 +20,7 @@ The following operations (sub-commands) are available: - `search` returns history items matching the search string. If no search string is provided it returns all history items. This is the default operation if no other operation is specified. You only have to explicitly say `history search` if you wish to search for one of the subcommands. The `--contains` search option will be used if you don't specify a different search option. Entries are ordered newest to oldest. If stdout is attached to a tty the output will be piped through your pager by the history function. The history builtin simply writes the results to stdout. -- `delete` deletes history items. Without the `--prefix` or `--contains` options, the exact match will be deleted. With either of these options, a prompt will be displayed before any items are deleted asking you which entries are to be deleted. You can enter the word "all" to delete all matching entries. You can enter a single ID (the number in square brackets) to delete just that single entry. You can enter more than one ID separated by a space to delete multiple entries. Just press [enter] to not delete anything. Note that the interactive delete behavior is a feature of the history function. The history builtin only supports bulk deletion. +- `delete` deletes history items. Without the `--prefix` or `--contains` options, the exact match of the specified text will be deleted. If you don't specify `--exact` a prompt will be displayed before any items are deleted asking you which entries are to be deleted. You can enter the word "all" to delete all matching entries. You can enter a single ID (the number in square brackets) to delete just that single entry. You can enter more than one ID separated by a space to delete multiple entries. Just press [enter] to not delete anything. Note that the interactive delete behavior is a feature of the history function. The history builtin only supports `--exact --case-sensitive` deletion. - `merge` immediately incorporates history changes from other sessions. Ordinarily `fish` ignores history changes from sessions started after the current one. This command applies those changes immediately. @@ -32,9 +32,11 @@ The following options are available: These flags can appear before or immediately after one of the sub-commands listed above. +- `-C` or `--case-sensitive` does a case-sensitive search. The default is case-insensitive. Note that prior to fish 2.4.0 the default was case-sensitive. + - `-c` or `--contains` searches or deletes items in the history that contain the specified text string. This is the default for the `--search` flag. This is not currently supported by the `--delete` flag. -- `-e` or `--exact` searches or deletes items in the history that exactly match the specified text string. This is the default for the `--delete` flag. +- `-e` or `--exact` searches or deletes items in the history that exactly match the specified text string. This is the default for the `--delete` flag. Note that the match is case-insensitive by default. If you really want an exact match, including letter case, you must use the `-C` or `--case-sensitive` flag. - `-p` or `--prefix` searches or deletes items in the history that begin with the specified text string. This is not currently supported by the `--delete` flag. diff --git a/share/functions/history.fish b/share/functions/history.fish index 569fd6ef2..428ffe38f 100644 --- a/share/functions/history.fish +++ b/share/functions/history.fish @@ -35,6 +35,7 @@ function history --description "display or manipulate interactive command histor set -l search_mode set -l show_time set -l max_count + set -l case_sensitive # Check for a recognized subcommand as the first argument. if set -q argv[1] @@ -68,6 +69,8 @@ function history --description "display or manipulate interactive command histor case --merge __fish_set_hist_cmd merge or return + case -C --case_sensitive + set case_sensitive --case-sensitive case -h --help builtin history --help return @@ -121,14 +124,13 @@ function history --description "display or manipulate interactive command histor test -z "$search_mode" and set search_mode "--contains" - echo "builtin history search $search_mode $show_time $max_count -- $argv" >>/tmp/x if isatty stdout set -l pager less set -q PAGER and set pager $PAGER - builtin history search $search_mode $show_time $max_count -- $argv | eval $pager + builtin history search $search_mode $show_time $max_count $case_sensitive -- $argv | eval $pager else - builtin history search $search_mode $show_time $max_count -- $argv + builtin history search $search_mode $show_time $max_count $case_sensitive -- $argv end case delete # interactively delete history @@ -139,16 +141,16 @@ function history --description "display or manipulate interactive command histor end test -z "$search_mode" - and set search_mode "--exact" + and set search_mode "--contains" if test $search_mode = "--exact" - builtin history delete $search_mode $argv + builtin history delete $search_mode $case_sensitive $argv return end # TODO: Fix this so that requesting history entries with a timestamp works: # set -l found_items (builtin history search $search_mode $show_time -- $argv) - set -l found_items (builtin history search $search_mode -- $argv) + set -l found_items (builtin history search $search_mode $case_sensitive -- $argv) if set -q found_items[1] set -l found_items_count (count $found_items) for i in (seq $found_items_count) @@ -169,11 +171,8 @@ function history --description "display or manipulate interactive command histor if test "$choice" = "all" printf "Deleting all matching entries!\n" - # TODO: Use the following when the builtin is enhanced to support the - # --prefix and --contains options (at the moment it only supports --exact). - # builtin history delete $search_mode -- $argv for item in $found_items - builtin history delete --exact -- $item + builtin history delete --exact --case-sensitive -- $item end builtin history save return @@ -188,7 +187,7 @@ function history --description "display or manipulate interactive command histor end printf "Deleting history entry %s: \"%s\"\n" $i $found_items[$i] - builtin history delete "$found_items[$i]" + builtin history delete --exact --case-sensitive -- "$found_items[$i]" end builtin history save end diff --git a/src/builtin.cpp b/src/builtin.cpp index 4d8b09179..f23de8cca 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -2875,10 +2875,11 @@ static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **ar long max_items = LONG_MAX; bool history_search_type_defined = false; const wchar_t *show_time_format = NULL; + bool case_sensitive = false; // TODO: Remove the long options that correspond to subcommands (e.g., '--delete') on or after // 2017-10 (which will be a full year after these flags have been deprecated). - const wchar_t *short_options = L":mn:epcht"; + const wchar_t *short_options = L":Cmn:epcht"; const struct woption long_options[] = {{L"prefix", no_argument, NULL, 'p'}, {L"contains", no_argument, NULL, 'c'}, {L"help", no_argument, NULL, 'h'}, @@ -2886,6 +2887,7 @@ static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **ar {L"with-time", optional_argument, NULL, 't'}, {L"exact", no_argument, NULL, 'e'}, {L"max", required_argument, NULL, 'n'}, + {L"case-sensitive", no_argument, 0, 'C'}, {L"delete", no_argument, NULL, 1}, {L"search", no_argument, NULL, 2}, {L"save", no_argument, NULL, 3}, @@ -2932,6 +2934,10 @@ static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **ar } break; } + case 'C': { + case_sensitive = true; + break; + } case 'p': { search_type = HISTORY_SEARCH_TYPE_PREFIX; history_search_type_defined = true; @@ -3014,20 +3020,27 @@ static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **ar int status = STATUS_BUILTIN_OK; switch (hist_cmd) { case HIST_SEARCH: { - if (!history->search(search_type, args, show_time_format, max_items, streams)) { + if (!history->search(search_type, args, show_time_format, max_items, case_sensitive, + streams)) { status = STATUS_BUILTIN_ERROR; } break; } case HIST_DELETE: { - // TODO: Move this code to the history module and support the other search types. At - // this time we expect the non-exact deletions to be handled only by the history - // function's interactive delete feature. + // TODO: Move this code to the history module and support the other search types + // including case-insensitive matches. At this time we expect the non-exact deletions to + // be handled only by the history function's interactive delete feature. if (search_type != HISTORY_SEARCH_TYPE_EXACT) { streams.err.append_format(_(L"builtin history delete only supports --exact\n")); status = STATUS_BUILTIN_ERROR; break; } + if (!case_sensitive) { + streams.err.append_format( + _(L"builtin history delete only supports --case-sensitive\n")); + status = STATUS_BUILTIN_ERROR; + break; + } for (wcstring_list_t::const_iterator iter = args.begin(); iter != args.end(); ++iter) { wcstring delete_string = *iter; if (delete_string[0] == '"' && delete_string[delete_string.length() - 1] == '"') { diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 323570718..9b82ded00 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -161,6 +161,11 @@ static int chdir_set_pwd(const char *path) { if (!(e)) err(L"Test failed on line %lu: %s", __LINE__, #e); \ } while (0) +#define do_test_from(e, from_line) \ + do { \ + if (!(e)) err(L"Test failed on line %lu (from %lu): %s", __LINE__, from_line, #e); \ + } while (0) + #define do_test1(e, msg) \ do { \ if (!(e)) err(L"Test failed on line %lu: %ls", __LINE__, (msg)); \ @@ -2178,7 +2183,6 @@ static void perform_one_autosuggestion_should_ignore_test(const wcstring &comman static void test_autosuggestion_ignores() { say(L"Testing scenarios that should produce no autosuggestions"); - const wcstring wd = L"/tmp/autosuggest_test/"; // Do not do file autosuggestions immediately after certain statement terminators - see #1631. perform_one_autosuggestion_should_ignore_test(L"echo PIPE_TEST|", __LINE__); perform_one_autosuggestion_should_ignore_test(L"echo PIPE_TEST&", __LINE__); @@ -2201,18 +2205,20 @@ static void test_autosuggestion_combining() { do_test(combine_command_and_autosuggestion(L"alpha", L"ALPHA") == L"alpha"); } -static void test_history_matches(history_search_t &search, size_t matches) { +static void test_history_matches(history_search_t &search, size_t matches, unsigned from_line) { size_t i; for (i = 0; i < matches; i++) { do_test(search.go_backwards()); wcstring item = search.current_string(); } - do_test(!search.go_backwards()); + // do_test_from(!search.go_backwards(), from_line); + bool result = search.go_backwards(); + do_test_from(!result, from_line); for (i = 1; i < matches; i++) { - do_test(search.go_forwards()); + do_test_from(search.go_forwards(), from_line); } - do_test(!search.go_forwards()); + do_test_from(!search.go_forwards(), from_line); } static bool history_contains(history_t *history, const wcstring &txt) { @@ -2518,28 +2524,64 @@ static wcstring random_string(void) { } void history_tests_t::test_history(void) { + history_search_t searcher; say(L"Testing history"); history_t &history = history_t::history_with_name(L"test_history"); history.clear(); history.add(L"Gamma"); + history.add(L"beta"); + history.add(L"BetA"); history.add(L"Beta"); + history.add(L"alpha"); + history.add(L"AlphA"); history.add(L"Alpha"); + history.add(L"alph"); + history.add(L"ALPH"); + history.add(L"ZZZ"); - // All three items match "a". - history_search_t search1(history, L"a"); - test_history_matches(search1, 3); - do_test(search1.current_string() == L"Alpha"); + // Items matching "a", case-sensitive. + searcher = history_search_t(history, L"a"); + test_history_matches(searcher, 6, __LINE__); + do_test(searcher.current_string() == L"alph"); - // One item matches "et". - history_search_t search2(history, L"et"); - test_history_matches(search2, 1); - do_test(search2.current_string() == L"Beta"); + // Items matching "alpha", case-insensitive. Note that HISTORY_SEARCH_TYPE_CONTAINS but we have + // to explicitly specify it in order to be able to pass false for the case_sensitive parameter. + searcher = history_search_t(history, L"AlPhA", HISTORY_SEARCH_TYPE_CONTAINS, false); + test_history_matches(searcher, 3, __LINE__); + do_test(searcher.current_string() == L"Alpha"); - // Test item removal. + // Items matching "et", case-sensitive. + searcher = history_search_t(history, L"et"); + test_history_matches(searcher, 3, __LINE__); + do_test(searcher.current_string() == L"Beta"); + + // Items starting with "be", case-sensitive. + searcher = history_search_t(history, L"be", HISTORY_SEARCH_TYPE_PREFIX, true); + test_history_matches(searcher, 1, __LINE__); + do_test(searcher.current_string() == L"beta"); + + // Items starting with "be", case-insensitive. + searcher = history_search_t(history, L"be", HISTORY_SEARCH_TYPE_PREFIX, false); + test_history_matches(searcher, 3, __LINE__); + do_test(searcher.current_string() == L"Beta"); + + // Items exactly matchine "alph", case-sensitive. + searcher = history_search_t(history, L"alph", HISTORY_SEARCH_TYPE_EXACT, true); + test_history_matches(searcher, 1, __LINE__); + do_test(searcher.current_string() == L"alph"); + + // Items exactly matchine "alph", case-insensitive. + searcher = history_search_t(history, L"alph", HISTORY_SEARCH_TYPE_EXACT, false); + test_history_matches(searcher, 2, __LINE__); + do_test(searcher.current_string() == L"ALPH"); + + // Test item removal case-sensitive. + searcher = history_search_t(history, L"Alpha"); + test_history_matches(searcher, 1, __LINE__); history.remove(L"Alpha"); - history_search_t search3(history, L"Alpha"); - test_history_matches(search3, 0); + searcher = history_search_t(history, L"Alpha"); + test_history_matches(searcher, 0, __LINE__); // Test history escaping and unescaping, yaml, etc. history_item_list_t before, after; diff --git a/src/history.cpp b/src/history.cpp index fc09dbe0a..77f4ac600 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -428,27 +428,52 @@ bool history_item_t::merge(const history_item_t &item) { return result; } +#if 0 history_item_t::history_item_t(const wcstring &str) - : contents(str), creation_timestamp(time(NULL)), identifier(0) {} + : contents(str), contents_lower(L""), creation_timestamp(time(NULL)), identifier(0) { + for (wcstring::const_iterator it = str.begin(); it != str.end(); ++it) { + contents_lower.push_back(towlower(*it)); + } + } +#endif history_item_t::history_item_t(const wcstring &str, time_t when, history_identifier_t ident) - : contents(str), creation_timestamp(when), identifier(ident) {} + : contents(str), contents_lower(L""), creation_timestamp(when), identifier(ident) { + for (wcstring::const_iterator it = str.begin(); it != str.end(); ++it) { + contents_lower.push_back(towlower(*it)); + } +} -bool history_item_t::matches_search(const wcstring &term, enum history_search_type_t type) const { - switch (type) { - case HISTORY_SEARCH_TYPE_CONTAINS: { +bool history_item_t::matches_search(const wcstring &term, enum history_search_type_t type, + bool case_sensitive) const { + // We don't use a switch below because there are only three cases and if the strings are the + // same length we can use the faster HISTORY_SEARCH_TYPE_EXACT for the other two cases. + // + // Too, we consider equal strings to match a prefix search, so that autosuggest will allow + // suggesting what you've typed. + if (case_sensitive) { + if (type == HISTORY_SEARCH_TYPE_EXACT || term.size() == contents.size()) { + return term == contents; + } else if (type == HISTORY_SEARCH_TYPE_CONTAINS) { return contents.find(term) != wcstring::npos; - } - case HISTORY_SEARCH_TYPE_PREFIX: { - // We consider equal strings to match a prefix search, so that autosuggest will allow - // suggesting what you've typed. + } else if (type == HISTORY_SEARCH_TYPE_PREFIX) { return string_prefixes_string(term, contents); } - case HISTORY_SEARCH_TYPE_EXACT: { - return term == contents; + } else { + wcstring lterm(L""); + for (wcstring::const_iterator it = term.begin(); it != term.end(); ++it) { + lterm.push_back(towlower(*it)); + } + + if (type == HISTORY_SEARCH_TYPE_EXACT || lterm.size() == contents.size()) { + return lterm == contents_lower; + } else if (type == HISTORY_SEARCH_TYPE_CONTAINS) { + return contents_lower.find(lterm) != wcstring::npos; + } else if (type == HISTORY_SEARCH_TYPE_PREFIX) { + return string_prefixes_string(lterm, contents_lower); } - default: { DIE("unexpected history_search_type_t value"); } } + DIE("unexpected history_search_type_t value"); } /// Append our YAML history format to the provided vector at the given offset, updating the offset. @@ -765,16 +790,27 @@ void history_t::add(const wcstring &str, history_identifier_t ident, bool pendin this->add(history_item_t(str, when, ident), pending); } -void history_t::remove(const wcstring &str) { - // Add to our list of deleted items. - deleted_items.insert(str); +bool icompare_pred(wchar_t a, wchar_t b) { return std::tolower(a) == std::tolower(b); } + +bool icompare(wcstring const &a, wcstring const &b) { + if (a.length() == b.length()) { + return std::equal(b.begin(), b.end(), a.begin(), icompare_pred); + } else { + return false; + } +} + +// Remove matching history entries from our list of new items. This only supports literal, +// case-sensitive, matches. +void history_t::remove(const wcstring &str_to_remove) { + // Add to our list of deleted items. + deleted_items.insert(str_to_remove); - // Remove from our list of new items. size_t idx = new_items.size(); while (idx--) { - if (new_items.at(idx).str() == str) { + bool matched = new_items.at(idx).str() == str_to_remove; + if (matched) { new_items.erase(new_items.begin() + idx); - // If this index is before our first_unwritten_new_item_index, then subtract one from // that index so it stays pointing at the same item. If it is equal to or larger, then // we have not yet writen this item, so we don't have to adjust the index. @@ -1003,7 +1039,7 @@ bool history_search_t::go_backwards() { // Look for a term that matches and that we haven't seen before. const wcstring &str = item.str(); - if (item.matches_search(term, search_type) && !match_already_made(str) && + if (item.matches_search(term, search_type, case_sensitive) && !match_already_made(str) && !should_skip_match(str)) { prev_matches.push_back(prev_match_t(idx, item)); return true; @@ -1417,7 +1453,8 @@ static bool format_history_record(const history_item_t &item, const wchar_t *sho } bool history_t::search(history_search_type_t search_type, wcstring_list_t search_args, - const wchar_t *show_time_format, long max_items, io_streams_t &streams) { + const wchar_t *show_time_format, long max_items, bool case_sensitive, + io_streams_t &streams) { // scoped_lock locker(lock); if (search_args.empty()) { // Start at one because zero is the current command. @@ -1436,7 +1473,8 @@ bool history_t::search(history_search_type_t search_type, wcstring_list_t search streams.err.append_format(L"Searching for the empty string isn't allowed"); return false; } - history_search_t searcher = history_search_t(*this, search_string, search_type); + history_search_t searcher = + history_search_t(*this, search_string, search_type, case_sensitive); while (searcher.go_backwards()) { if (!format_history_record(searcher.current_item(), show_time_format, streams)) { return false; diff --git a/src/history.h b/src/history.h index db1e4615d..58a0f30a5 100644 --- a/src/history.h +++ b/src/history.h @@ -59,7 +59,8 @@ class history_item_t { bool merge(const history_item_t &item); // The actual contents of the entry. - wcstring contents; + wcstring contents; // value as entered by the user + wcstring contents_lower; // value normalized to all lowercase for case insensitive comparisons // Original creation time for the entry. time_t creation_timestamp; @@ -71,15 +72,16 @@ class history_item_t { path_list_t required_paths; public: - explicit history_item_t(const wcstring &str); - explicit history_item_t(const wcstring &, time_t, history_identifier_t ident = 0); + explicit history_item_t(const wcstring &str, time_t when = 0, history_identifier_t ident = 0); const wcstring &str() const { return contents; } + const wcstring &str_lower() const { return contents_lower; } bool empty() const { return contents.empty(); } // Whether our contents matches a search term. - bool matches_search(const wcstring &term, enum history_search_type_t type) const; + bool matches_search(const wcstring &term, enum history_search_type_t type, + bool case_sensitive) const; time_t timestamp() const { return creation_timestamp; } @@ -227,7 +229,8 @@ class history_t { // Searches history. bool search(history_search_type_t search_type, wcstring_list_t search_args, - const wchar_t *show_time_format, long max_items, io_streams_t &streams); + const wchar_t *show_time_format, long max_items, bool case_sensitive, + io_streams_t &streams); // Enable / disable automatic saving. Main thread only! void disable_automatic_saving(); @@ -264,6 +267,7 @@ class history_search_t { // Our type. enum history_search_type_t search_type; + bool case_sensitive; // Our list of previous matches as index, value. The end is the current match. typedef std::pair prev_match_t; @@ -310,11 +314,19 @@ class history_search_t { // Constructor. history_search_t(history_t &hist, const wcstring &str, - enum history_search_type_t type = HISTORY_SEARCH_TYPE_CONTAINS) - : history(&hist), search_type(type), term(str) {} + enum history_search_type_t type = HISTORY_SEARCH_TYPE_CONTAINS, + bool case_sensitive = true) + : history(&hist), term(str), search_type(type), case_sensitive(case_sensitive) { + if (!case_sensitive) { + term = wcstring(); + for (wcstring::const_iterator it = str.begin(); it != str.end(); ++it) { + term.push_back(towlower(*it)); + } + } + } // Default constructor. - history_search_t() : history(), search_type(HISTORY_SEARCH_TYPE_CONTAINS), term() {} + history_search_t() : history(), term() {} }; // Init history library. The history file won't actually be loaded until the first time a history diff --git a/tests/history.expect b/tests/history.expect index d8e4ebd1a..593691699 100644 --- a/tests/history.expect +++ b/tests/history.expect @@ -112,8 +112,10 @@ expect_prompt -re {history search --exact 'echo hell'\r\n} { # ========== # Delete a single command we recently ran. -send "history delete 'echo hello'\r" -expect_prompt -re {history delete 'echo hello'\r\n} { +send "history delete -e -C 'echo hello'\r" +expect -re {history delete -e -C 'echo hello'\r\n} +send "echo count hello (history search -e -C 'echo hello' | wc -l | string trim)\r" +expect -re {\r\ncount hello 0\r\n} { puts "history function explicit exact delete 'echo hello' succeeded" } unmatched { puts stderr "history function explicit exact delete 'echo hello' failed" @@ -130,24 +132,20 @@ expect -re {\[2\] echo hello again\r\n\r\n} expect -re {Enter nothing to cancel.*\r\nEnter "all" to delete all the matching entries\.\r\n} expect -re {Delete which entries\? >} send "1\r" -expect_prompt -re {Deleting history entry 1: "echo hello AGAIN"\r\n} { - puts "history function explicit prefix delete 'echo hello' succeeded" -} unmatched { - puts stderr "history function explicit prefix delete 'echo hello' failed" -} +expect -re {Deleting history entry 1: "echo hello AGAIN"\r\n} # Verify that the deleted history entry is gone and the other one that matched # the prefix search above is still there. -send "history search --exact 'echo hello again'\r" -expect_prompt -re {\r\necho hello again\r\n} { +send "echo count AGAIN (history search -e -C 'echo hello AGAIN' | wc -l | string trim)\r" +expect -re {\r\ncount AGAIN 0\r\n} { + puts "history function explicit prefix delete 'echo hello AGAIN' succeeded" +} unmatched { + puts stderr "history function explicit prefix delete 'echo hello AGAIN' failed" +} + +send "echo count again (history search -e -C 'echo hello again' | wc -l | string trim)\r" +expect -re {\r\ncount again 1\r\n} { puts "history function explicit exact search 'echo hello again' succeeded" } unmatched { puts stderr "history function explicit exact search 'echo hello again' failed" } - -send "history search --exact 'echo hello AGAIN'\r" -expect_prompt -re {\r\necho hello AGAIN\r\n} { - puts stderr "history function explicit exact search 'echo hello AGAIN' found the entry" -} unmatched { - puts "history function explicit exact search 'echo hello AGAIN' failed to find the entry" -} diff --git a/tests/history.expect.out b/tests/history.expect.out index a91045fdc..7fe87edd7 100644 --- a/tests/history.expect.out +++ b/tests/history.expect.out @@ -7,6 +7,5 @@ history function explicit exact search 'echo goodbye' succeeded history function explicit exact search 'echo hello' succeeded history function explicit exact search 'echo hell' succeeded history function explicit exact delete 'echo hello' succeeded -history function explicit prefix delete 'echo hello' succeeded +history function explicit prefix delete 'echo hello AGAIN' succeeded history function explicit exact search 'echo hello again' succeeded -history function explicit exact search 'echo hello AGAIN' failed to find the entry From bff6a6e66a3e9e03b196ec7bafd3c49453145dba Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Sun, 16 Oct 2016 21:15:40 -0700 Subject: [PATCH 39/42] eliminate compile warnings and augment changelog Update the CHANGELOG to more accurately reflect what will be included in the 2.4.0 release vis-a-vis the `history` command behavior. I noticed that the compiler was emitting some harmless warnings related to the history changes so deal with those as well. --- CHANGELOG.md | 4 +++- src/history.cpp | 1 + src/history.h | 10 +++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5d1997e1..1f7b0e16f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ ## Significant changes - The clipboard integration has been revamped with explicit bindings. The killring commands no longer copy from, or paste to, the X11 clipboard - use the new copy (`C-x`) and paste (`C-v`) bindings instead. The clipboard is now available on OS X as well as systems using X11 (e.g. Linux). (#3061) -- `history` uses subcommands (`history delete`) rather than options (`history --delete`) for its actions (#3367). New options have been added, including `--max=n` to limit the number of history entries and `--show-time` option to show timestamps (#3175, #3244). +- `history` uses subcommands (`history delete`) rather than options (`history --delete`) for its actions (#3367). You can no longer specify multiple actions via flags (e.g., `history --delete --save something`). +- New `history` options have been added, including `--max=n` to limit the number of history entries and `--show-time` option to show timestamps (#3175, #3244). +- `history search` is now case-insensitive by default (which also affects `history delete`). - Vi-style bindings no longer include all of the default emacs-style bindings; instead, they share some definitions (#3068). - If there is no locale set in the environment, various known system configuration files will be checked for a default, otherwise forcing en_US-UTF.8 (#277). - A number followed by a caret (e.g. `5^`) is no longer treated as a redirection (#1873). diff --git a/src/history.cpp b/src/history.cpp index 77f4ac600..82f41b26b 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -1,4 +1,5 @@ // History functions, part of the user interface. +// #include "config.h" // IWYU pragma: keep #include diff --git a/src/history.h b/src/history.h index 58a0f30a5..bd990c196 100644 --- a/src/history.h +++ b/src/history.h @@ -265,7 +265,10 @@ class history_search_t { // The history in which we are searching. history_t *history; - // Our type. + // The search term. + wcstring term; + + // Our search type. enum history_search_type_t search_type; bool case_sensitive; @@ -276,9 +279,6 @@ class history_search_t { // Returns yes if a given term is in prev_matches. bool match_already_made(const wcstring &match) const; - // The search term. - wcstring term; - // Additional strings to skip (sorted). wcstring_list_t external_skips; @@ -326,7 +326,7 @@ class history_search_t { } // Default constructor. - history_search_t() : history(), term() {} + history_search_t() : history(), term(), search_type(HISTORY_SEARCH_TYPE_CONTAINS), case_sensitive(true) {} }; // Init history library. The history file won't actually be loaded until the first time a history From a26f68d63fb3780a1eb0c092b31b99bc67290933 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Sun, 16 Oct 2016 20:33:33 -0700 Subject: [PATCH 40/42] handle multiline commands in history search output Fixes #31 --- doc_src/history.txt | 4 +++- share/functions/history.fish | 12 +++++++++--- src/builtin.cpp | 12 +++++++++--- src/history.cpp | 12 +++++++----- src/history.h | 2 +- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/doc_src/history.txt b/doc_src/history.txt index 855a160ee..388ded19a 100644 --- a/doc_src/history.txt +++ b/doc_src/history.txt @@ -2,7 +2,7 @@ \subsection history-synopsis Synopsis \fish{synopsis} -history search [ --show-time ] [ --case-sensitive ] [ --exact | --prefix | --contains ] [ --max=n ] [ "search string"... ] +history search [ --show-time ] [ --case-sensitive ] [ --exact | --prefix | --contains ] [ --max=n ] [ --null ] [ "search string"... ] history delete [ --show-time ] [ --case-sensitive ] [ --exact | --prefix | --contains ] "search string"... history merge history save @@ -42,6 +42,8 @@ These flags can appear before or immediately after one of the sub-commands liste - `-t` or `--show-time` prepends each history entry with the date and time the entry was recorded . By default it uses the strftime format `# %c%n`. You can specify another format; e.g., `--show-time='%Y-%m-%d %H:%M:%S '` or `--show-time='%a%I%p'`. The short option, `-t` doesn't accept a stftime format string; it only uses the default format. Any strftime format is allowed, including `%s` to get the raw UNIX seconds since the epoch. Note that `--with-time` is also allowed but is deprecated and will be removed at a future date. +- `-z` or `--null` causes history entries written by the search operations to be terminated by a NUL character rather than a newline. This allows the output to be processed by `read -z` to correctly handle multiline history entries. + - `-` `-n ` or `--max=` limits the matched history items to the first "n" matching entries. This is only valid for `history search`. - `-h` or `--help` display help for this command. diff --git a/share/functions/history.fish b/share/functions/history.fish index 428ffe38f..6e130fd76 100644 --- a/share/functions/history.fish +++ b/share/functions/history.fish @@ -36,6 +36,7 @@ function history --description "display or manipulate interactive command histor set -l show_time set -l max_count set -l case_sensitive + set -l null # Check for a recognized subcommand as the first argument. if set -q argv[1] @@ -82,6 +83,8 @@ function history --description "display or manipulate interactive command histor set search_mode --contains case -e --exact set search_mode --exact + case -z --null + set null --null case -n --max if string match -- '-n?*' $argv[1] or string match -- '--max=*' $argv[1] @@ -128,9 +131,9 @@ function history --description "display or manipulate interactive command histor set -l pager less set -q PAGER and set pager $PAGER - builtin history search $search_mode $show_time $max_count $case_sensitive -- $argv | eval $pager + builtin history search $search_mode $show_time $max_count $case_sensitive $null -- $argv | eval $pager else - builtin history search $search_mode $show_time $max_count $case_sensitive -- $argv + builtin history search $search_mode $show_time $max_count $case_sensitive $null -- $argv end case delete # interactively delete history @@ -150,7 +153,10 @@ function history --description "display or manipulate interactive command histor # TODO: Fix this so that requesting history entries with a timestamp works: # set -l found_items (builtin history search $search_mode $show_time -- $argv) - set -l found_items (builtin history search $search_mode $case_sensitive -- $argv) + set -l found_items + builtin history search $search_mode $case_sensitive --null -- $argv | while read -lz x + set found_items $found_items $x + end if set -q found_items[1] set -l found_items_count (count $found_items) for i in (seq $found_items_count) diff --git a/src/builtin.cpp b/src/builtin.cpp index f23de8cca..06944591b 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -2853,7 +2853,7 @@ static bool set_hist_cmd(wchar_t *const cmd, hist_cmd_t *hist_cmd, hist_cmd_t su } #define CHECK_FOR_UNEXPECTED_HIST_ARGS(hist_cmd) \ - if (history_search_type_defined || show_time_format) { \ + if (history_search_type_defined || show_time_format || null_terminate) { \ streams.err.append_format(_(L"%ls: you cannot use any options with the %ls command\n"), \ cmd, hist_cmd_to_string(hist_cmd).c_str()); \ status = STATUS_BUILTIN_ERROR; \ @@ -2876,10 +2876,11 @@ static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **ar bool history_search_type_defined = false; const wchar_t *show_time_format = NULL; bool case_sensitive = false; + bool null_terminate = false; // TODO: Remove the long options that correspond to subcommands (e.g., '--delete') on or after // 2017-10 (which will be a full year after these flags have been deprecated). - const wchar_t *short_options = L":Cmn:epcht"; + const wchar_t *short_options = L":Cmn:epchtz"; const struct woption long_options[] = {{L"prefix", no_argument, NULL, 'p'}, {L"contains", no_argument, NULL, 'c'}, {L"help", no_argument, NULL, 'h'}, @@ -2887,6 +2888,7 @@ static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **ar {L"with-time", optional_argument, NULL, 't'}, {L"exact", no_argument, NULL, 'e'}, {L"max", required_argument, NULL, 'n'}, + {L"null", no_argument, 0, 'z'}, {L"case-sensitive", no_argument, 0, 'C'}, {L"delete", no_argument, NULL, 1}, {L"search", no_argument, NULL, 2}, @@ -2967,6 +2969,10 @@ static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **ar } break; } + case 'z': { + null_terminate = true; + break; + } case 'h': { builtin_print_help(parser, streams, cmd, streams.out); return STATUS_BUILTIN_OK; @@ -3021,7 +3027,7 @@ static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **ar switch (hist_cmd) { case HIST_SEARCH: { if (!history->search(search_type, args, show_time_format, max_items, case_sensitive, - streams)) { + null_terminate, streams)) { status = STATUS_BUILTIN_ERROR; } break; diff --git a/src/history.cpp b/src/history.cpp index 82f41b26b..7c33166ef 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -1436,7 +1436,7 @@ void history_t::save(void) { // Formats a single history record, including a trailing newline. Returns true // if bytes were written to the output stream and false otherwise. static bool format_history_record(const history_item_t &item, const wchar_t *show_time_format, - io_streams_t &streams) { + bool null_terminate, io_streams_t &streams) { if (show_time_format) { const time_t seconds = item.timestamp(); struct tm timestamp; @@ -1449,18 +1449,19 @@ static bool format_history_record(const history_item_t &item, const wchar_t *sho streams.out.append(timestamp_string); } streams.out.append(item.str()); - streams.out.append(L"\n"); + streams.out.append(null_terminate ? L'\0' : L'\n'); return true; } bool history_t::search(history_search_type_t search_type, wcstring_list_t search_args, const wchar_t *show_time_format, long max_items, bool case_sensitive, - io_streams_t &streams) { + bool null_terminate, io_streams_t &streams) { // scoped_lock locker(lock); if (search_args.empty()) { // Start at one because zero is the current command. for (int i = 1; !this->item_at_index(i).empty() && max_items; ++i, --max_items) { - if (!format_history_record(this->item_at_index(i), show_time_format, streams)) { + if (!format_history_record(this->item_at_index(i), show_time_format, null_terminate, + streams)) { return false; } } @@ -1477,7 +1478,8 @@ bool history_t::search(history_search_type_t search_type, wcstring_list_t search history_search_t searcher = history_search_t(*this, search_string, search_type, case_sensitive); while (searcher.go_backwards()) { - if (!format_history_record(searcher.current_item(), show_time_format, streams)) { + if (!format_history_record(searcher.current_item(), show_time_format, null_terminate, + streams)) { return false; } if (--max_items == 0) return true; diff --git a/src/history.h b/src/history.h index bd990c196..a8aa51575 100644 --- a/src/history.h +++ b/src/history.h @@ -230,7 +230,7 @@ class history_t { // Searches history. bool search(history_search_type_t search_type, wcstring_list_t search_args, const wchar_t *show_time_format, long max_items, bool case_sensitive, - io_streams_t &streams); + bool null_terminate, io_streams_t &streams); // Enable / disable automatic saving. Main thread only! void disable_automatic_saving(); From 7e962d6f22d3ae0eeb9b1a2b06752a9554efde48 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Mon, 17 Oct 2016 08:25:50 -0700 Subject: [PATCH 41/42] update changelog with latest history changes --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f7b0e16f..a4911479a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,9 @@ ## Significant changes - The clipboard integration has been revamped with explicit bindings. The killring commands no longer copy from, or paste to, the X11 clipboard - use the new copy (`C-x`) and paste (`C-v`) bindings instead. The clipboard is now available on OS X as well as systems using X11 (e.g. Linux). (#3061) - `history` uses subcommands (`history delete`) rather than options (`history --delete`) for its actions (#3367). You can no longer specify multiple actions via flags (e.g., `history --delete --save something`). -- New `history` options have been added, including `--max=n` to limit the number of history entries and `--show-time` option to show timestamps (#3175, #3244). -- `history search` is now case-insensitive by default (which also affects `history delete`). +- New `history` options have been added, including `--max=n` to limit the number of history entries, `--show-time` option to show timestamps (#3175, #3244), and `--null` to null terminate history entries in the search output. +- `history search` is now case-insensitive by default (which also affects `history delete`) (#3236). +- `history delete` now correctly handles multiline commands (#31). - Vi-style bindings no longer include all of the default emacs-style bindings; instead, they share some definitions (#3068). - If there is no locale set in the environment, various known system configuration files will be checked for a default, otherwise forcing en_US-UTF.8 (#277). - A number followed by a caret (e.g. `5^`) is no longer treated as a redirection (#1873). From d474368ea5a2ca5c70f6a72431c2e40fe2e5d9b4 Mon Sep 17 00:00:00 2001 From: Hunsu Date: Mon, 17 Oct 2016 17:31:35 +0200 Subject: [PATCH 42/42] Add HTTPS and HSTS options to wget completions (#3470) --- share/completions/wget.fish | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/share/completions/wget.fish b/share/completions/wget.fish index bcf10ce95..24c44d349 100644 --- a/share/completions/wget.fish +++ b/share/completions/wget.fish @@ -77,6 +77,26 @@ complete -c wget -l post-data --description "Use POST as the method for all HTTP complete -c wget -l post-file --description "Use POST as the method for all HTTP requests and send the specified data in the request body" -r complete -c wget -l no-http-keep-alive --description "Turn off keep-alive for http downloads" +# HTTPS options + +complete -c wget -f -r -l secure-protocol -a 'auto SSLv2 SSLv3 TLSv1 PFS' --description "Choose secure protocol" +complete -c wget -f -l https-only --description "Only follow secure HTTPS links" +complete -c wget -f -l no-check-certificate --description "Don't validate the server's certificate" +complete -c wget -r -l certificate --description "Client certificate file" +complete -c wget -f -r -l certificate-type --arguments 'PEM DER' --description "Client certificate type" +complete -c wget -r -l private-key --description "Private key file" +complete -c wget -f -r -l private-key-type --arguments 'PEM DER' --description "Private key type" +complete -c wget -r -l ca-certificate --description "File with the bundle of CAs" +complete -c wget -r -l ca-directory --description "Directory where hash list of CAs is stored" +complete -c wget -r -l crl-file --description "File with bundle of CRLs" +complete -c wget -r -l random-file --description "File with random data for seeding the SSL PRNG" +complete -c wget -r -l egd-file --description "File naming the EGD socket with random data" + +# HSTS options + +complete -c wget -f -l no-hsts --description "Disable HSTS" +complete -c wget -l hsts-file --description "Path of HSTS database" + #FTP options complete -c wget -l no-remove-listing --description "Don't remove the temporary .listing files generated"