gflags_completions.cc revision c79c32d98c4dc705ecc2fea2d7e8712afb6938fb
1c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Copyright (c) 2008, Google Inc. 2c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// All rights reserved. 3c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 4c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Redistribution and use in source and binary forms, with or without 5c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// modification, are permitted provided that the following conditions are 6c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// met: 7c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 8c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// * Redistributions of source code must retain the above copyright 9c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// notice, this list of conditions and the following disclaimer. 10c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// * Redistributions in binary form must reproduce the above 11c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// copyright notice, this list of conditions and the following disclaimer 12c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// in the documentation and/or other materials provided with the 13c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// distribution. 14c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// * Neither the name of Google Inc. nor the names of its 15c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// contributors may be used to endorse or promote products derived from 16c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// this software without specific prior written permission. 17c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 18c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 30c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// --- 31c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Author: Dave Nicponski 32c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 33c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Bash-style command line flag completion for C++ binaries 34c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 35c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// This module implements bash-style completions. It achieves this 36c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// goal in the following broad chunks: 37c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 38c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 1) Take a to-be-completed word, and examine it for search hints 39c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 2) Identify all potentially matching flags 40c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 2a) If there are no matching flags, do nothing. 41c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 2b) If all matching flags share a common prefix longer than the 42c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// completion word, output just that matching prefix 43c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 3) Categorize those flags to produce a rough ordering of relevence. 44c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 4) Potentially trim the set of flags returned to a smaller number 45c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// that bash is happier with 46c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 5) Output the matching flags in groups ordered by relevence. 47c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 5a) Force bash to place most-relevent groups at the top of the list 48c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 5b) Trim most flag's descriptions to fit on a single terminal line 49c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 50c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 51c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#include "config.h" 52c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#include <stdlib.h> 53c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 54c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#include <set> 55c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#include <string> 56c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#include <utility> 57c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#include <vector> 58c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 59c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#include "google/gflags.h" 60c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 61c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinusing std::set; 62c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinusing std::string; 63c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinusing std::vector; 64c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 65c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#ifndef PATH_SEPARATOR 66c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#define PATH_SEPARATOR '/' 67c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#endif 68c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 69c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig SilversteinDEFINE_string(tab_completion_word, "", 70c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "If non-empty, HandleCommandLineCompletions() will hijack the " 71c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "process and attempt to do bash-style command line flag " 72c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "completion on this value."); 73c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig SilversteinDEFINE_int32(tab_completion_columns, 80, 74c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "Number of columns to use in output for tab completion"); 75c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 76c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein_START_GOOGLE_NAMESPACE_ 77c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 78c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinnamespace { 79c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 80c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Function prototypes and Type forward declarations. Code may be 81c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// more easily understood if it is roughly ordered according to 82c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// control flow, rather than by C's "declare before use" ordering 83c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstruct CompletionOptions; 84c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstruct NotableFlags; 85c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 86c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// The entry point if flag completion is to be used. 87c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void PrintFlagCompletionInfo(void); 88c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 89c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 90c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 1) Examine search word 91c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void CanonicalizeCursorWordAndSearchOptions( 92c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &cursor_word, 93c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string *canonical_search_token, 94c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein CompletionOptions *options); 95c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 96c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic bool RemoveTrailingChar(string *str, char c); 97c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 98c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 99c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 2) Find all matches 100c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void FindMatchingFlags( 101c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const vector<CommandLineFlagInfo> &all_flags, 102c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const CompletionOptions &options, 103c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &match_token, 104c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein set<const CommandLineFlagInfo *> *all_matches, 105c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string *longest_common_prefix); 106c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 107c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic bool DoesSingleFlagMatch( 108c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const CommandLineFlagInfo &flag, 109c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const CompletionOptions &options, 110c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &match_token); 111c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 112c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 113c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 3) Categorize matches 114c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void CategorizeAllMatchingFlags( 115c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const set<const CommandLineFlagInfo *> &all_matches, 116c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &search_token, 117c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &module, 118c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &package_dir, 119c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein NotableFlags *notable_flags); 120c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 121c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void TryFindModuleAndPackageDir( 122c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const vector<CommandLineFlagInfo> all_flags, 123c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string *module, 124c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string *package_dir); 125c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 126c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 127c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 4) Decide which flags to use 128c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void FinalizeCompletionOutput( 129c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const set<const CommandLineFlagInfo *> &matching_flags, 130c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein CompletionOptions *options, 131c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein NotableFlags *notable_flags, 132c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein vector<string> *completions); 133c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 134c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void RetrieveUnusedFlags( 135c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const set<const CommandLineFlagInfo *> &matching_flags, 136c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const NotableFlags ¬able_flags, 137c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein set<const CommandLineFlagInfo *> *unused_flags); 138c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 139c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 140c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 5) Output matches 141c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void OutputSingleGroupWithLimit( 142c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const set<const CommandLineFlagInfo *> &group, 143c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &line_indentation, 144c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &header, 145c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &footer, 146c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein bool long_output_format, 147c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int *remaining_line_limit, 148c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int *completion_elements_added, 149c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein vector<string> *completions); 150c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 151c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// (helpers for #5) 152c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic string GetShortFlagLine( 153c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &line_indentation, 154c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const CommandLineFlagInfo &info); 155c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 156c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic string GetLongFlagLine( 157c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &line_indentation, 158c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const CommandLineFlagInfo &info); 159c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 160c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 161c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 162c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Useful types 163c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 164c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Try to deduce the intentions behind this completion attempt. Return the 165c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// canonical search term in 'canonical_search_token'. Binary search options 166c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// are returned in the various booleans, which should all have intuitive 167c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// semantics, possibly except: 168c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// - return_all_matching_flags: Generally, we'll trim the number of 169c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// returned candidates to some small number, showing those that are 170c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// most likely to be useful first. If this is set, however, the user 171c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// really does want us to return every single flag as an option. 172c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// - force_no_update: Any time we output lines, all of which share a 173c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// common prefix, bash will 'helpfully' not even bother to show the 174c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// output, instead changing the current word to be that common prefix. 175c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// If it's clear this shouldn't happen, we'll set this boolean 176c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstruct CompletionOptions { 177c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein bool flag_name_substring_search; 178c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein bool flag_location_substring_search; 179c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein bool flag_description_substring_search; 180c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein bool return_all_matching_flags; 181c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein bool force_no_update; 182c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein}; 183c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 184c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Notable flags are flags that are special or preferred for some 185c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// reason. For example, flags that are defined in the binary's module 186c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// are expected to be much more relevent than flags defined in some 187c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// other random location. These sets are specified roughly in precedence 188c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// order. Once a flag is placed in one of these 'higher' sets, it won't 189c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// be placed in any of the 'lower' sets. 190c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstruct NotableFlags { 191c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein typedef set<const CommandLineFlagInfo *> FlagSet; 192c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein FlagSet perfect_match_flag; 193c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein FlagSet module_flags; // Found in module file 194c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein FlagSet package_flags; // Found in same directory as module file 195c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein FlagSet most_common_flags; // One of the XXX most commonly supplied flags 196c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein FlagSet subpackage_flags; // Found in subdirectories of package 197c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein}; 198c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 199c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 200c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 201c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Tab completion implementation - entry point 202c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void PrintFlagCompletionInfo(void) { 203c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string cursor_word = FLAGS_tab_completion_word; 204c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string canonical_token; 205c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein CompletionOptions options; 206c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein CanonicalizeCursorWordAndSearchOptions( 207c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein cursor_word, 208c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &canonical_token, 209c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &options); 210c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 211c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(1) << "Identified canonical_token: '" << canonical_token << "'"; 212c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 213c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein vector<CommandLineFlagInfo> all_flags; 214c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein set<const CommandLineFlagInfo *> matching_flags; 215c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein GetAllFlags(&all_flags); 216c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(2) << "Found " << all_flags.size() << " flags overall"; 217c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 218c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string longest_common_prefix; 219c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein FindMatchingFlags( 220c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein all_flags, 221c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein options, 222c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein canonical_token, 223c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &matching_flags, 224c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &longest_common_prefix); 225c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(1) << "Identified " << matching_flags.size() << " matching flags"; 226c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(1) << "Identified " << longest_common_prefix 227c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // << " as longest common prefix."; 228c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (longest_common_prefix.size() > canonical_token.size()) { 229c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // There's actually a shared common prefix to all matching flags, 230c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // so may as well output that and quit quickly. 231c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(1) << "The common prefix '" << longest_common_prefix 232c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // << "' was longer than the token '" << canonical_token 233c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // << "'. Returning just this prefix for completion."; 234c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein fprintf(stdout, "--%s", longest_common_prefix.c_str()); 235c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return; 236c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 237c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (matching_flags.empty()) { 238c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(1) << "There were no matching flags, returning nothing."; 239c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return; 240c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 241c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 242c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string module; 243c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string package_dir; 244c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein TryFindModuleAndPackageDir(all_flags, &module, &package_dir); 245c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(1) << "Identified module: '" << module << "'"; 246c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(1) << "Identified package_dir: '" << package_dir << "'"; 247c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 248c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein NotableFlags notable_flags; 249c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein CategorizeAllMatchingFlags( 250c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein matching_flags, 251c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein canonical_token, 252c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein module, 253c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein package_dir, 254c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ¬able_flags); 255c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(2) << "Categorized matching flags:"; 256c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(2) << " perfect_match: " << notable_flags.perfect_match_flag.size(); 257c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(2) << " module: " << notable_flags.module_flags.size(); 258c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(2) << " package: " << notable_flags.package_flags.size(); 259c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(2) << " most common: " << notable_flags.most_common_flags.size(); 260c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(2) << " subpackage: " << notable_flags.subpackage_flags.size(); 261c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 262c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein vector<string> completions; 263c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein FinalizeCompletionOutput( 264c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein matching_flags, 265c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &options, 266c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ¬able_flags, 267c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &completions); 268c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 269c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (options.force_no_update) 270c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions.push_back("~"); 271c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 272c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(1) << "Finalized with " << completions.size() 273c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // << " chosen completions"; 274c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 275c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (vector<string>::const_iterator it = completions.begin(); 276c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it != completions.end(); 277c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++it) { 278c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(9) << " Completion entry: '" << *it << "'"; 279c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein fprintf(stdout, "%s\n", it->c_str()); 280c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 281c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 282c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 283c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 284c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 1) Examine search word (and helper method) 285c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void CanonicalizeCursorWordAndSearchOptions( 286c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &cursor_word, 287c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string *canonical_search_token, 288c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein CompletionOptions *options) { 289c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *canonical_search_token = cursor_word; 290c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (canonical_search_token->empty()) return; 291c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 292c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Get rid of leading quotes and dashes in the search term 293c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if ((*canonical_search_token)[0] == '"') 294c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *canonical_search_token = canonical_search_token->substr(1); 295c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein while ((*canonical_search_token)[0] == '-') 296c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *canonical_search_token = canonical_search_token->substr(1); 297c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 298c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein options->flag_name_substring_search = false; 299c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein options->flag_location_substring_search = false; 300c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein options->flag_description_substring_search = false; 301c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein options->return_all_matching_flags = false; 302c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein options->force_no_update = false; 303c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 304c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Look for all search options we can deduce now. Do this by walking 305c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // backwards through the term, looking for up to three '?' and up to 306c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // one '+' as suffixed characters. Consume them if found, and remove 307c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // them from the canonical search token. 308c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int found_question_marks = 0; 309c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int found_plusses = 0; 310c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein while (true) { 311c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (found_question_marks < 3 && 312c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein RemoveTrailingChar(canonical_search_token, '?')) { 313c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++found_question_marks; 314c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein continue; 315c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 316c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (found_plusses < 1 && 317c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein RemoveTrailingChar(canonical_search_token, '+')) { 318c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++found_plusses; 319c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein continue; 320c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 321c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein break; 322c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 323c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 324c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein switch (found_question_marks) { // all fallthroughs 325c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein case 3: options->flag_description_substring_search = true; 326c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein case 2: options->flag_location_substring_search = true; 327c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein case 1: options->flag_name_substring_search = true; 328c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein }; 329c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 330c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein options->return_all_matching_flags = (found_plusses > 0); 331c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 332c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 333c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Returns true if a char was removed 334c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic bool RemoveTrailingChar(string *str, char c) { 335c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (str->empty()) return false; 336c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if ((*str)[str->size() - 1] == c) { 337c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *str = str->substr(0, str->size() - 1); 338c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return true; 339c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 340c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return false; 341c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 342c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 343c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 344c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 2) Find all matches (and helper methods) 345c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void FindMatchingFlags( 346c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const vector<CommandLineFlagInfo> &all_flags, 347c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const CompletionOptions &options, 348c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &match_token, 349c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein set<const CommandLineFlagInfo *> *all_matches, 350c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string *longest_common_prefix) { 351c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein all_matches->clear(); 352c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein bool first_match = true; 353c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (vector<CommandLineFlagInfo>::const_iterator it = all_flags.begin(); 354c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it != all_flags.end(); 355c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++it) { 356c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (DoesSingleFlagMatch(*it, options, match_token)) { 357c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein all_matches->insert(&*it); 358c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (first_match) { 359c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein first_match = false; 360c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *longest_common_prefix = it->name; 361c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } else { 362c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (longest_common_prefix->empty() || it->name.empty()) { 363c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein longest_common_prefix->clear(); 364c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein continue; 365c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 366c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string::size_type pos = 0; 367c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein while (pos < longest_common_prefix->size() && 368c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein pos < it->name.size() && 369c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein (*longest_common_prefix)[pos] == it->name[pos]) 370c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++pos; 371c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein longest_common_prefix->erase(pos); 372c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 373c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 374c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 375c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 376c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 377c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Given the set of all flags, the parsed match options, and the 378c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// canonical search token, produce the set of all candidate matching 379c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// flags for subsequent analysis or filtering. 380c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic bool DoesSingleFlagMatch( 381c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const CommandLineFlagInfo &flag, 382c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const CompletionOptions &options, 383c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &match_token) { 384c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Is there a prefix match? 385c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string::size_type pos = flag.name.find(match_token); 386c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (pos == 0) return true; 387c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 388c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Is there a substring match if we want it? 389c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (options.flag_name_substring_search && 390c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein pos != string::npos) 391c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return true; 392c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 393c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Is there a location match if we want it? 394c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (options.flag_location_substring_search && 395c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein flag.filename.find(match_token) != string::npos) 396c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return true; 397c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 398c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // TODO(daven): All searches should probably be case-insensitive 399c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // (especially this one...) 400c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (options.flag_description_substring_search && 401c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein flag.description.find(match_token) != string::npos) 402c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return true; 403c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 404c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return false; 405c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 406c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 407c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 3) Categorize matches (and helper method) 408c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 409c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Given a set of matching flags, categorize them by 410c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// likely relevence to this specific binary 411c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void CategorizeAllMatchingFlags( 412c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const set<const CommandLineFlagInfo *> &all_matches, 413c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &search_token, 414c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &module, // empty if we couldn't find any 415c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &package_dir, // empty if we couldn't find any 416c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein NotableFlags *notable_flags) { 417c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags->perfect_match_flag.clear(); 418c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags->module_flags.clear(); 419c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags->package_flags.clear(); 420c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags->most_common_flags.clear(); 421c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags->subpackage_flags.clear(); 422c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 423c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (set<const CommandLineFlagInfo *>::const_iterator it = 424c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein all_matches.begin(); 425c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it != all_matches.end(); 426c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++it) { 427c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(2) << "Examinging match '" << (*it)->name << "'"; 428c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(7) << " filename: '" << (*it)->filename << "'"; 429c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string::size_type pos = string::npos; 430c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (!package_dir.empty()) 431c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein pos = (*it)->filename.find(package_dir); 432c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string::size_type slash = string::npos; 433c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (pos != string::npos) // candidate for package or subpackage match 434c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein slash = (*it)->filename.find( 435c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein PATH_SEPARATOR, 436c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein pos + package_dir.size() + 1); 437c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 438c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if ((*it)->name == search_token) { 439c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Exact match on some flag's name 440c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags->perfect_match_flag.insert(*it); 441c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(3) << "Result: perfect match"; 442c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } else if (!module.empty() && (*it)->filename == module) { 443c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Exact match on module filename 444c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags->module_flags.insert(*it); 445c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(3) << "Result: module match"; 446c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } else if (!package_dir.empty() && 447c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein pos != string::npos && slash == string::npos) { 448c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // In the package, since there was no slash after the package portion 449c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags->package_flags.insert(*it); 450c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(3) << "Result: package match"; 451c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } else if (false) { 452c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // In the list of the XXX most commonly supplied flags overall 453c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // TODO(daven): Compile this list. 454c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(3) << "Result: most-common match"; 455c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } else if (!package_dir.empty() && 456c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein pos != string::npos && slash != string::npos) { 457c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // In a subdirectory of the package 458c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags->subpackage_flags.insert(*it); 459c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(3) << "Result: subpackage match"; 460c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 461c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 462c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein //VLOG(3) << "Result: not special match"; 463c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 464c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 465c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 466c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void TryFindModuleAndPackageDir( 467c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const vector<CommandLineFlagInfo> all_flags, 468c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string *module, 469c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string *package_dir) { 470c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein module->clear(); 471c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein package_dir->clear(); 472c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 473c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein vector<string> suffixes; 474c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // TODO(daven): There's some inherant ambiguity here - multiple directories 475c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // could share the same trailing folder and file structure (and even worse, 476c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // same file names), causing us to be unsure as to which of the two is the 477c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // actual package for this binary. In this case, we'll arbitrarily choose. 478c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string progname(ProgramInvocationShortName()); 479c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein suffixes.push_back("/" + progname + "."); 480c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein suffixes.push_back("/" + progname + "-main."); 481c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein suffixes.push_back("/" + progname + "_main."); 482c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // These four are new but probably merited? 483c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein suffixes.push_back("/" + progname + "_test."); 484c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein suffixes.push_back("/" + progname + "-test."); 485c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein suffixes.push_back("/" + progname + "_unittest."); 486c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein suffixes.push_back("/" + progname + "-unittest."); 487c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 488c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (vector<CommandLineFlagInfo>::const_iterator it = all_flags.begin(); 489c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it != all_flags.end(); 490c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++it) { 491c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (vector<string>::const_iterator suffix = suffixes.begin(); 492c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein suffix != suffixes.end(); 493c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++suffix) { 494c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // TODO(daven): Make sure the match is near the end of the string 495c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (it->filename.find(*suffix) != string::npos) { 496c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *module = it->filename; 497c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string::size_type sep = it->filename.rfind(PATH_SEPARATOR); 498c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *package_dir = it->filename.substr(0, (sep == string::npos) ? 0 : sep); 499c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return; 500c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 501c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 502c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 503c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 504c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 505c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Can't specialize template type on a locally defined type. Silly C++... 506c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstruct DisplayInfoGroup { 507c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string header; 508c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string footer; 509c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein set<const CommandLineFlagInfo *> *group; 510c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein}; 511c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 512c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 4) Finalize and trim output flag set 513c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void FinalizeCompletionOutput( 514c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const set<const CommandLineFlagInfo *> &matching_flags, 515c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein CompletionOptions *options, 516c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein NotableFlags *notable_flags, 517c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein vector<string> *completions) { 518c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 519c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // We want to output lines in groups. Each group needs to be indented 520c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // the same to keep its lines together. Unless otherwise required, 521c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // only 99 lines should be output to prevent bash from harassing the 522c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // user. 523c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 524c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // First, figure out which output groups we'll actually use. For each 525c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // nonempty group, there will be ~3 lines of header & footer, plus all 526c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // output lines themselves. 527c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int max_desired_lines = // "999999 flags should be enough for anyone. -dave" 528c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein (options->return_all_matching_flags ? 999999 : 98); 529c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int lines_so_far = 0; 530c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 531c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein vector<DisplayInfoGroup> output_groups; 532c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein bool perfect_match_found = false; 533c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (lines_so_far < max_desired_lines && 534c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein !notable_flags->perfect_match_flag.empty()) { 535c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein perfect_match_found = true; 536c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein lines_so_far += notable_flags->perfect_match_flag.size() + 2; // no header 537c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein DisplayInfoGroup group = 538c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein { "", "==========", ¬able_flags->perfect_match_flag }; 539c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.push_back(group); 540c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 541c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (lines_so_far < max_desired_lines && 542c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein !notable_flags->module_flags.empty()) { 543c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein lines_so_far += notable_flags->module_flags.size() + 3; 544c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein DisplayInfoGroup group = { 545c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "-* Matching module flags *-", 546c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "===========================", 547c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ¬able_flags->module_flags }; 548c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.push_back(group); 549c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 550c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (lines_so_far < max_desired_lines && 551c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein !notable_flags->package_flags.empty()) { 552c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein lines_so_far += notable_flags->package_flags.size() + 3; 553c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein DisplayInfoGroup group = { 554c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "-* Matching package flags *-", 555c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "============================", 556c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ¬able_flags->package_flags }; 557c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.push_back(group); 558c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 559c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (lines_so_far < max_desired_lines && 560c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein !notable_flags->most_common_flags.empty()) { 561c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein lines_so_far += notable_flags->most_common_flags.size() + 3; 562c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein DisplayInfoGroup group = { 563c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "-* Commonly used flags *-", 564c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "=========================", 565c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ¬able_flags->most_common_flags }; 566c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.push_back(group); 567c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 568c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (lines_so_far < max_desired_lines && 569c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein !notable_flags->subpackage_flags.empty()) { 570c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein lines_so_far += notable_flags->subpackage_flags.size() + 3; 571c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein DisplayInfoGroup group = { 572c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "-* Matching sub-package flags *-", 573c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "================================", 574c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ¬able_flags->subpackage_flags }; 575c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.push_back(group); 576c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 577c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 578c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein set<const CommandLineFlagInfo *> obscure_flags; // flags not notable 579c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (lines_so_far < max_desired_lines) { 580c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein RetrieveUnusedFlags(matching_flags, *notable_flags, &obscure_flags); 581c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (!obscure_flags.empty()) { 582c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein lines_so_far += obscure_flags.size() + 2; // no footer 583c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein DisplayInfoGroup group = { 584c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "-* Other flags *-", 585c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "", 586c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &obscure_flags }; 587c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.push_back(group); 588c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 589c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 590c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 591c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Second, go through each of the chosen output groups and output 592c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // as many of those flags as we can, while remaining below our limit 593c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int remaining_lines = max_desired_lines; 594c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int completions_output = 0; 595c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int indent = output_groups.size() - 1; 596c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (vector<DisplayInfoGroup>::const_iterator it = 597c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.begin(); 598c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it != output_groups.end(); 599c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++it, --indent) { 600c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein OutputSingleGroupWithLimit( 601c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *it->group, // group 602c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string(indent, ' '), // line indentation 603c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it->header, // header 604c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it->footer, // footer 605c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein perfect_match_found, // long format 606c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &remaining_lines, // line limit - reduces this by number printed 607c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &completions_output, // completions (not lines) added 608c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions); // produced completions 609c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein perfect_match_found = false; 610c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 611c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 612c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (completions_output != matching_flags.size()) { 613c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein options->force_no_update = false; 614c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions->push_back("~ (Remaining flags hidden) ~"); 615c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } else { 616c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein options->force_no_update = true; 617c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 618c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 619c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 620c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void RetrieveUnusedFlags( 621c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const set<const CommandLineFlagInfo *> &matching_flags, 622c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const NotableFlags ¬able_flags, 623c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein set<const CommandLineFlagInfo *> *unused_flags) { 624c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Remove from 'matching_flags' set all members of the sets of 625c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // flags we've already printed (specifically, those in notable_flags) 626c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (set<const CommandLineFlagInfo *>::const_iterator it = 627c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein matching_flags.begin(); 628c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it != matching_flags.end(); 629c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++it) { 630c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (notable_flags.perfect_match_flag.count(*it) || 631c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags.module_flags.count(*it) || 632c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags.package_flags.count(*it) || 633c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags.most_common_flags.count(*it) || 634c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags.subpackage_flags.count(*it)) 635c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein continue; 636c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein unused_flags->insert(*it); 637c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 638c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 639c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 640c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 5) Output matches (and helpfer methods) 641c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 642c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void OutputSingleGroupWithLimit( 643c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const set<const CommandLineFlagInfo *> &group, 644c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &line_indentation, 645c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &header, 646c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &footer, 647c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein bool long_output_format, 648c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int *remaining_line_limit, 649c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int *completion_elements_output, 650c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein vector<string> *completions) { 651c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (group.empty()) return; 652c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (!header.empty()) { 653c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (*remaining_line_limit < 2) return; 654c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *remaining_line_limit -= 2; 655c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions->push_back(line_indentation + header); 656c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions->push_back(line_indentation + string(header.size(), '-')); 657c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 658c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (set<const CommandLineFlagInfo *>::const_iterator it = group.begin(); 659c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it != group.end() && *remaining_line_limit > 0; 660c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++it) { 661c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein --*remaining_line_limit; 662c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++*completion_elements_output; 663c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions->push_back( 664c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein (long_output_format 665c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ? GetLongFlagLine(line_indentation, **it) 666c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein : GetShortFlagLine(line_indentation, **it))); 667c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 668c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (!footer.empty()) { 669c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (*remaining_line_limit < 1) return; 670c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein --*remaining_line_limit; 671c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions->push_back(line_indentation + footer); 672c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 673c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 674c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 675c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic string GetShortFlagLine( 676c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &line_indentation, 677c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const CommandLineFlagInfo &info) { 678c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string prefix = 679c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein line_indentation + "--" + info.name + " [" + 680c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein (info.type == "string" ? 681c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ("'" + info.default_value + "'") : 682c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein info.default_value) 683c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein + "] "; 684c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int remainder = FLAGS_tab_completion_columns - prefix.size(); 685c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string suffix = ""; 686c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (remainder > 0) 687c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein suffix = 688c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein (info.description.size() > remainder ? 689c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein (info.description.substr(0, remainder - 3) + "...").c_str() : 690c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein info.description.c_str()); 691c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return prefix + suffix; 692c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 693c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 694c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic string GetLongFlagLine( 695c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &line_indentation, 696c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const CommandLineFlagInfo &info) { 697c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 698c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string output = DescribeOneFlag(info); 699c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 700c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Replace '-' with '--', and remove trailing newline before appending 701c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // the module definition location. 702c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string old_flagname = "-" + info.name; 703c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output.replace( 704c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output.find(old_flagname), 705c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein old_flagname.size(), 706c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "-" + old_flagname); 707c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Stick a newline and indentation in front of the type and default 708c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // portions of DescribeOneFlag()s description 709c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein static const char kNewlineWithIndent[] = "\n "; 710c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output.replace(output.find(" type:"), 1, string(kNewlineWithIndent)); 711c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output.replace(output.find(" default:"), 1, string(kNewlineWithIndent)); 712c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output = line_indentation + " Details for '--" + info.name + "':\n" + 713c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output + " defined: " + info.filename; 714c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 715c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Eliminate any doubled newlines that crept in. Specifically, if 716c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // DescribeOneFlag() decided to break the line just before "type" 717c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // or "default", we don't want to introduce an extra blank line 718c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein static const string line_of_spaces(FLAGS_tab_completion_columns, ' '); 719c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein static const char kDoubledNewlines[] = "\n \n"; 720c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (string::size_type newlines = output.find(kDoubledNewlines); 721c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein newlines != string::npos; 722c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein newlines = output.find(kDoubledNewlines)) 723c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Replace each 'doubled newline' with a single newline 724c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output.replace(newlines, sizeof(kDoubledNewlines) - 1, string("\n")); 725c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 726c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (string::size_type newline = output.find('\n'); 727c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein newline != string::npos; 728c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein newline = output.find('\n')) { 729c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int newline_pos = newline % FLAGS_tab_completion_columns; 730c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int missing_spaces = FLAGS_tab_completion_columns - newline_pos; 731c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output.replace(newline, 1, line_of_spaces, 1, missing_spaces); 732c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 733c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return output; 734c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 735c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} // anonymous 736c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 737c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinvoid HandleCommandLineCompletions(void) { 738c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (FLAGS_tab_completion_word.empty()) return; 739c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein PrintFlagCompletionInfo(); 740c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein exit(0); 741c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 742c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 743c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein_END_GOOGLE_NAMESPACE_ 744