Add SearchProvider nav result inline autocompletion.
SearchProvider::NavigationToMatch authored by PKasting.
Consolidate URLPrefix code; add many unit test cases.
Trim |contents| and |fill_into_edit|'s http scheme if:
-the input does not contain "http:"
-and the input is not a leading substring of "http:".
TODO: Add file and chrome schemes as inlineable prefixes?
TBR=sky (chrome/browser/history OWNERS)
BUG=125871
TEST=Automated; manual with upcoming suggest experiments.
Review URL: https://chromiumcodereview.appspot.com/10396002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139964 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc
index efc5fb0..28a5d2b 100644
--- a/chrome/browser/autocomplete/search_provider.cc
+++ b/chrome/browser/autocomplete/search_provider.cc
@@ -15,11 +15,13 @@
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/string16.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete_classifier.h"
#include "chrome/browser/autocomplete/autocomplete_field_trial.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/autocomplete/keyword_provider.h"
+#include "chrome/browser/autocomplete/url_prefix.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/in_memory_database.h"
#include "chrome/browser/instant/instant_controller.h"
@@ -36,6 +38,7 @@
#include "grit/generated_resources.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
+#include "net/base/net_util.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request_status.h"
#include "ui/base/l10n/l10n_util.h"
@@ -963,31 +966,62 @@
AutocompleteMatch SearchProvider::NavigationToMatch(
const NavigationResult& navigation,
bool is_keyword) {
- const string16& input_text = is_keyword ? keyword_input_text_ : input_.text();
+ const string16& input = is_keyword ? keyword_input_text_ : input_.text();
AutocompleteMatch match(this, navigation.relevance(), false,
AutocompleteMatch::NAVSUGGEST);
match.destination_url = navigation.url();
- match.contents =
- StringForURLDisplay(navigation.url(), true, !HasHTTPScheme(input_text));
- AutocompleteMatch::ClassifyMatchInString(input_text, match.contents,
- ACMatchClassification::URL,
- &match.contents_class);
+
+ // First look for the user's input inside the fill_into_edit as it would be
+ // without trimming the scheme, so we can find matches at the beginning of the
+ // scheme.
+ const string16 untrimmed_fill_into_edit(
+ AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(),
+ StringForURLDisplay(navigation.url(), true, false)));
+ const URLPrefix* prefix =
+ URLPrefix::BestURLPrefix(untrimmed_fill_into_edit, input);
+ size_t match_start = (prefix == NULL) ?
+ untrimmed_fill_into_edit.find(input) : prefix->prefix.length();
+ size_t inline_autocomplete_offset = (prefix == NULL) ?
+ string16::npos : (match_start + input.length());
+ bool trim_http = !HasHTTPScheme(input) && (!prefix || (match_start != 0));
+
+ // Preserve the forced query '?' prefix in |match.fill_into_edit|.
+ // Otherwise, user edits to a suggestion would show non-Search results.
+ if (input_.type() == AutocompleteInput::FORCED_QUERY) {
+ match.fill_into_edit = ASCIIToUTF16("?");
+ if (inline_autocomplete_offset != string16::npos)
+ ++inline_autocomplete_offset;
+ }
+
+ const std::string languages(
+ profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
+ const net::FormatUrlTypes format_types =
+ net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP);
+ match.fill_into_edit +=
+ AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(),
+ net::FormatUrl(navigation.url(), languages, format_types,
+ net::UnescapeRule::SPACES, NULL, NULL,
+ &inline_autocomplete_offset));
+ if (!input_.prevent_inline_autocomplete())
+ match.inline_autocomplete_offset = inline_autocomplete_offset;
+ DCHECK((match.inline_autocomplete_offset == string16::npos) ||
+ (match.inline_autocomplete_offset <= match.fill_into_edit.length()));
+
+ match.contents = net::FormatUrl(navigation.url(), languages,
+ format_types, net::UnescapeRule::SPACES, NULL, NULL, &match_start);
+ // If the first match in the untrimmed string was inside a scheme that we
+ // trimmed, look for a subsequent match.
+ if (match_start == string16::npos)
+ match_start = match.contents.find(input);
+ // Safe if |match_start| is npos; also safe if the input is longer than the
+ // remaining contents after |match_start|.
+ AutocompleteMatch::ClassifyLocationInString(match_start, input.length(),
+ match.contents.length(), ACMatchClassification::URL,
+ &match.contents_class);
match.description = navigation.description();
- AutocompleteMatch::ClassifyMatchInString(input_text, match.description,
- ACMatchClassification::NONE,
- &match.description_class);
-
- // When the user forced a query, we need to make sure all the fill_into_edit
- // values preserve that property. Otherwise, if the user starts editing a
- // suggestion, non-Search results will suddenly appear.
- if (input_.type() == AutocompleteInput::FORCED_QUERY)
- match.fill_into_edit.assign(ASCIIToUTF16("?"));
- match.fill_into_edit.append(
- AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(),
- match.contents));
- // TODO(pkasting|msw): Inline-autocomplete nav results; see http://b/1112879.
-
+ AutocompleteMatch::ClassifyMatchInString(input, match.description,
+ ACMatchClassification::NONE, &match.description_class);
return match;
}