From 85fdf587c055a912b6051abbf676724e233ebecf Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sat, 5 Jan 2013 15:21:42 -0800 Subject: [PATCH] When the user input contains capital letters, use its case rather than the autosuggestion's case Fixes https://github.com/fish-shell/fish-shell/issues/335 --- fish_tests.cpp | 13 +++++++++++++ reader.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++++++-- reader.h | 3 +++ screen.h | 10 ---------- 4 files changed, 67 insertions(+), 12 deletions(-) diff --git a/fish_tests.cpp b/fish_tests.cpp index 0653c5957..6f1b6887a 100644 --- a/fish_tests.cpp +++ b/fish_tests.cpp @@ -1022,6 +1022,18 @@ static void test_autosuggest_suggest_special() system("rm -Rf ~/test_autosuggest_suggest_special/"); } +static void test_autosuggestion_combining() +{ + say(L"Testing autosuggestion combining"); + assert(combine_command_and_autosuggestion(L"alpha", L"alphabeta") == L"alphabeta"); + + // when the last token contains no capital letters, we use the case of the autosuggestion + assert(combine_command_and_autosuggestion(L"alpha", L"ALPHABETA") == L"ALPHABETA"); + + // when the last token contains capital letters, we use its case + assert(combine_command_and_autosuggestion(L"alPha", L"alphabeTa") == L"alPhabeTa"); +} + /** Test speed of completion calculations @@ -1625,6 +1637,7 @@ int main(int argc, char **argv) test_word_motion(); test_is_potential_path(); test_colors(); + test_autosuggestion_combining(); test_autosuggest_suggest_special(); history_tests_t::test_history(); history_tests_t::test_history_merge(); diff --git a/reader.cpp b/reader.cpp index 229254b5a..8b18287e3 100644 --- a/reader.cpp +++ b/reader.cpp @@ -449,6 +449,53 @@ int reader_exit_forced() return exit_forced; } +/* Given a command line and an autosuggestion, return the string that gets shown to the user */ +wcstring combine_command_and_autosuggestion(const wcstring &cmdline, const wcstring &autosuggestion) +{ + // We want to compute the full line, containing the command line and the autosuggestion + // They may disagree on whether characters are uppercase or lowercase + // Here we do something funny: if the last token of the command line contains any uppercase characters, we use its case + // Otherwise we use the case of the autosuggestion + // This is an idea from https://github.com/fish-shell/fish-shell/issues/335 + wcstring full_line; + if (autosuggestion.size() <= cmdline.size() || cmdline.empty()) + { + // No or useless autosuggestion, or no command line + full_line = cmdline; + } + else if (string_prefixes_string(cmdline, autosuggestion)) + { + // No case disagreements, or no extra characters in the autosuggestion + full_line = autosuggestion; + } + else + { + // We have an autosuggestion which is not a prefix of the command line, i.e. a case disagreement + // Decide whose case we want to use + const wchar_t *begin = NULL, *cmd = cmdline.c_str(); + parse_util_token_extent(cmd, cmdline.size() - 1, &begin, NULL, NULL, NULL); + bool last_token_contains_uppercase = false; + if (begin) + { + const wchar_t *end = begin + wcslen(begin); + last_token_contains_uppercase = (std::find_if(begin, end, iswupper) != end); + } + if (! last_token_contains_uppercase) + { + // Use the autosuggestion's case + full_line = autosuggestion; + } + else + { + // Use the command line case for its characters, then append the remaining characters in the autosuggestion + // Note that we know that autosuggestion.size() > cmdline.size() due to the first test above + full_line = cmdline; + full_line.append(autosuggestion, cmdline.size(), autosuggestion.size() - cmdline.size()); + } + } + return full_line; +} + /** Repaint the entire commandline. This means reset and clear the commandline, write the prompt, perform syntax highlighting, write @@ -457,10 +504,12 @@ int reader_exit_forced() static void reader_repaint() { - //Update the indentation + // Update the indentation parser_t::principal_parser().test(data->command_line.c_str(), &data->indents[0], 0, 0); - wcstring full_line = (data->autosuggestion.empty() ? data->command_line : data->autosuggestion); + // Combine the command and autosuggestion into one string + wcstring full_line = combine_command_and_autosuggestion(data->command_line, data->autosuggestion); + size_t len = full_line.size(); if (len < 1) len = 1; diff --git a/reader.h b/reader.h index 923f07d8c..ba024e865 100644 --- a/reader.h +++ b/reader.h @@ -214,5 +214,8 @@ int reader_shell_test(const wchar_t *b); */ int reader_search_mode(); +/* Given a command line and an autosuggestion, return the string that gets shown to the user. Exposed for testing purposes only. */ +wcstring combine_command_and_autosuggestion(const wcstring &cmdline, const wcstring &autosuggestion); + #endif diff --git a/screen.h b/screen.h index dd87b60c6..a5fad9c82 100644 --- a/screen.h +++ b/screen.h @@ -179,16 +179,6 @@ public: \param indent the indent to use for the command line \param cursor_pos where the cursor is */ -void s_write(screen_t *s, - const wchar_t *left_prompt, - const wchar_t *right_prompt, - const wchar_t *commandline, - size_t explicit_len, - const int *colors, - const int *indent, - size_t cursor_pos); - - void s_write(screen_t *s, const wcstring &left_prompt, const wcstring &right_prompt,