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// --- 31917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein 32c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Bash-style command line flag completion for C++ binaries 33c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 34c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// This module implements bash-style completions. It achieves this 35c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// goal in the following broad chunks: 36c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 37c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 1) Take a to-be-completed word, and examine it for search hints 38c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 2) Identify all potentially matching flags 39c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 2a) If there are no matching flags, do nothing. 40c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 2b) If all matching flags share a common prefix longer than the 41c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// completion word, output just that matching prefix 42c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 3) Categorize those flags to produce a rough ordering of relevence. 43c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 4) Potentially trim the set of flags returned to a smaller number 44c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// that bash is happier with 45c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 5) Output the matching flags in groups ordered by relevence. 46c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 5a) Force bash to place most-relevent groups at the top of the list 47c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 5b) Trim most flag's descriptions to fit on a single terminal line 48c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 495a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein#include <stdio.h> 50c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#include <stdlib.h> 515a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein#include <string.h> // for strlen 52c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 53c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#include <set> 54c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#include <string> 55c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#include <utility> 56c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein#include <vector> 57c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 5837e2867335a680f8478cb8bd811b598e069c56c1Andreas Schuh#include "config.h" 5937e2867335a680f8478cb8bd811b598e069c56c1Andreas Schuh#include "gflags/gflags.h" 6037e2867335a680f8478cb8bd811b598e069c56c1Andreas Schuh#include "gflags/gflags_completions.h" 61917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein#include "util.h" 62917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein 63917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silversteinusing std::set; 64917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silversteinusing std::string; 65917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silversteinusing std::vector; 66c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 67c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 68c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig SilversteinDEFINE_string(tab_completion_word, "", 69c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "If non-empty, HandleCommandLineCompletions() will hijack the " 70c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "process and attempt to do bash-style command line flag " 71c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "completion on this value."); 72c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig SilversteinDEFINE_int32(tab_completion_columns, 80, 73c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "Number of columns to use in output for tab completion"); 74c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 75392eb67dbf63cb96317eaef9d3370a824d7c4adeAndreas Schuh 76392eb67dbf63cb96317eaef9d3370a824d7c4adeAndreas Schuhnamespace GFLAGS_NAMESPACE { 77392eb67dbf63cb96317eaef9d3370a824d7c4adeAndreas Schuh 78c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 79c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinnamespace { 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( 1223e946c9ebcea6a4e30988dc26bcb07b94eb8d043dreamer.dead 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, 14867914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein size_t *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; 205e0b71e5758a240a52cbdfe8690ed31bf72f27906Craig Silverstein CompletionOptions options = { }; 206c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein CanonicalizeCursorWordAndSearchOptions( 207c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein cursor_word, 208c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &canonical_token, 209c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &options); 210c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 211917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(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); 216917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(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); 225917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(1) << "Identified " << matching_flags.size() << " matching flags"; 226917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(1) << "Identified " << longest_common_prefix 227917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig 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. 231917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(1) << "The common prefix '" << longest_common_prefix 232917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein << "' was longer than the token '" << canonical_token 233917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig 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()) { 238917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig 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); 245917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(1) << "Identified module: '" << module << "'"; 246917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(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); 255917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(2) << "Categorized matching flags:"; 256917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(2) << " perfect_match: " << notable_flags.perfect_match_flag.size(); 257917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(2) << " module: " << notable_flags.module_flags.size(); 258917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(2) << " package: " << notable_flags.package_flags.size(); 259917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(2) << " most common: " << notable_flags.most_common_flags.size(); 260917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(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 272917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(1) << "Finalized with " << completions.size() 273917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein << " chosen completions"; 274c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 275c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (vector<string>::const_iterator it = completions.begin(); 276c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it != completions.end(); 277c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++it) { 278917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(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 398917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein // TODO(user): 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) { 427917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(2) << "Examining match '" << (*it)->name << "'"; 428917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(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); 441917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(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); 445917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(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); 450917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(3) << "Result: package match"; 451c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } else if (false) { 452c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // In the list of the XXX most commonly supplied flags overall 453917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein // TODO(user): Compile this list. 454917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(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); 459917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(3) << "Result: subpackage match"; 460c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 461c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 462917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein DVLOG(3) << "Result: not special match"; 463c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 464c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 465c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 4665a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silversteinstatic void PushNameWithSuffix(vector<string>* suffixes, const char* suffix) { 467917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein suffixes->push_back( 468917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein StringPrintf("/%s%s", ProgramInvocationShortName(), suffix)); 4695a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein} 4705a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein 471c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void TryFindModuleAndPackageDir( 4723e946c9ebcea6a4e30988dc26bcb07b94eb8d043dreamer.dead const vector<CommandLineFlagInfo> &all_flags, 473c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string *module, 474c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string *package_dir) { 475c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein module->clear(); 476c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein package_dir->clear(); 477c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 478c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein vector<string> suffixes; 479917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein // TODO(user): There's some inherant ambiguity here - multiple directories 480c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // could share the same trailing folder and file structure (and even worse, 481c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // same file names), causing us to be unsure as to which of the two is the 482c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // actual package for this binary. In this case, we'll arbitrarily choose. 4835a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein PushNameWithSuffix(&suffixes, "."); 4845a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein PushNameWithSuffix(&suffixes, "-main."); 4855a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein PushNameWithSuffix(&suffixes, "_main."); 486c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // These four are new but probably merited? 4875a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein PushNameWithSuffix(&suffixes, "-test."); 4885a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein PushNameWithSuffix(&suffixes, "_test."); 4895a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein PushNameWithSuffix(&suffixes, "-unittest."); 4905a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein PushNameWithSuffix(&suffixes, "_unittest."); 491c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 492c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (vector<CommandLineFlagInfo>::const_iterator it = all_flags.begin(); 493c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it != all_flags.end(); 494c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++it) { 495c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (vector<string>::const_iterator suffix = suffixes.begin(); 496c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein suffix != suffixes.end(); 497c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++suffix) { 498917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein // TODO(user): Make sure the match is near the end of the string 499c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (it->filename.find(*suffix) != string::npos) { 500c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *module = it->filename; 501c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string::size_type sep = it->filename.rfind(PATH_SEPARATOR); 502c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *package_dir = it->filename.substr(0, (sep == string::npos) ? 0 : sep); 503c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return; 504c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 505c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 506c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 507c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 508c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 509c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// Can't specialize template type on a locally defined type. Silly C++... 510c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstruct DisplayInfoGroup { 5115a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein const char* header; 5125a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein const char* footer; 513c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein set<const CommandLineFlagInfo *> *group; 51467914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein 51567914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein int SizeInLines() const { 51667914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein int size_in_lines = static_cast<int>(group->size()) + 1; 5175a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein if (strlen(header) > 0) { 51867914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein size_in_lines++; 51967914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein } 5205a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein if (strlen(footer) > 0) { 52167914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein size_in_lines++; 52267914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein } 52367914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein return size_in_lines; 52467914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein } 525c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein}; 526c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 527c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein// 4) Finalize and trim output flag set 528c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void FinalizeCompletionOutput( 529c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const set<const CommandLineFlagInfo *> &matching_flags, 530c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein CompletionOptions *options, 531c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein NotableFlags *notable_flags, 532c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein vector<string> *completions) { 533c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 534c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // We want to output lines in groups. Each group needs to be indented 535c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // the same to keep its lines together. Unless otherwise required, 536c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // only 99 lines should be output to prevent bash from harassing the 537c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // user. 538c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 539c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // First, figure out which output groups we'll actually use. For each 540c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // nonempty group, there will be ~3 lines of header & footer, plus all 541c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // output lines themselves. 542c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int max_desired_lines = // "999999 flags should be enough for anyone. -dave" 543c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein (options->return_all_matching_flags ? 999999 : 98); 544c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int lines_so_far = 0; 545c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 546c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein vector<DisplayInfoGroup> output_groups; 547c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein bool perfect_match_found = false; 548c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (lines_so_far < max_desired_lines && 549c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein !notable_flags->perfect_match_flag.empty()) { 550c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein perfect_match_found = true; 551c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein DisplayInfoGroup group = 5525a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein { "", 55367914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein "==========", 55467914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein ¬able_flags->perfect_match_flag }; 55567914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein lines_so_far += group.SizeInLines(); 556c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.push_back(group); 557c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 558c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (lines_so_far < max_desired_lines && 559c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein !notable_flags->module_flags.empty()) { 560c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein DisplayInfoGroup group = { 561c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "-* Matching module flags *-", 562c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "===========================", 563c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ¬able_flags->module_flags }; 56467914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein lines_so_far += group.SizeInLines(); 565c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.push_back(group); 566c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 567c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (lines_so_far < max_desired_lines && 568c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein !notable_flags->package_flags.empty()) { 569c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein DisplayInfoGroup group = { 570c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "-* Matching package flags *-", 571c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "============================", 572c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ¬able_flags->package_flags }; 57367914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein lines_so_far += group.SizeInLines(); 574c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.push_back(group); 575c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 576c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (lines_so_far < max_desired_lines && 577c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein !notable_flags->most_common_flags.empty()) { 578c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein DisplayInfoGroup group = { 579c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "-* Commonly used flags *-", 580c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "=========================", 581c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ¬able_flags->most_common_flags }; 58267914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein lines_so_far += group.SizeInLines(); 583c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.push_back(group); 584c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 585c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (lines_so_far < max_desired_lines && 586c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein !notable_flags->subpackage_flags.empty()) { 587c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein DisplayInfoGroup group = { 588c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "-* Matching sub-package flags *-", 589c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "================================", 590c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ¬able_flags->subpackage_flags }; 59167914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein lines_so_far += group.SizeInLines(); 592c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.push_back(group); 593c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 594c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 595c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein set<const CommandLineFlagInfo *> obscure_flags; // flags not notable 596c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (lines_so_far < max_desired_lines) { 597c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein RetrieveUnusedFlags(matching_flags, *notable_flags, &obscure_flags); 598c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (!obscure_flags.empty()) { 599c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein DisplayInfoGroup group = { 600c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "-* Other flags *-", 6015a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein "", 602c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &obscure_flags }; 60367914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein lines_so_far += group.SizeInLines(); 604c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.push_back(group); 605c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 606c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 607c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 608c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Second, go through each of the chosen output groups and output 609c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // as many of those flags as we can, while remaining below our limit 610c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int remaining_lines = max_desired_lines; 61167914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein size_t completions_output = 0; 61267914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein int indent = static_cast<int>(output_groups.size()) - 1; 613c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (vector<DisplayInfoGroup>::const_iterator it = 614c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output_groups.begin(); 615c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it != output_groups.end(); 616c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++it, --indent) { 617c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein OutputSingleGroupWithLimit( 618c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *it->group, // group 619c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string(indent, ' '), // line indentation 6205a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein string(it->header), // header 6215a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein string(it->footer), // footer 622c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein perfect_match_found, // long format 623c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &remaining_lines, // line limit - reduces this by number printed 624c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein &completions_output, // completions (not lines) added 625c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions); // produced completions 626c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein perfect_match_found = false; 627c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 628c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 629c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (completions_output != matching_flags.size()) { 630c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein options->force_no_update = false; 631c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions->push_back("~ (Remaining flags hidden) ~"); 632c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } else { 633c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein options->force_no_update = true; 634c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 635c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 636c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 637c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void RetrieveUnusedFlags( 638c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const set<const CommandLineFlagInfo *> &matching_flags, 639c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const NotableFlags ¬able_flags, 640c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein set<const CommandLineFlagInfo *> *unused_flags) { 641c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Remove from 'matching_flags' set all members of the sets of 642c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // flags we've already printed (specifically, those in notable_flags) 643c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (set<const CommandLineFlagInfo *>::const_iterator it = 644c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein matching_flags.begin(); 645c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it != matching_flags.end(); 646c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++it) { 647c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (notable_flags.perfect_match_flag.count(*it) || 648c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags.module_flags.count(*it) || 649c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags.package_flags.count(*it) || 650c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags.most_common_flags.count(*it) || 651c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein notable_flags.subpackage_flags.count(*it)) 652c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein continue; 653c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein unused_flags->insert(*it); 654c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 655c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 656c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 6575a3c7f8598d98b9554d3ddb1eb1069c22bb47caaCraig Silverstein// 5) Output matches (and helper methods) 658c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 659c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic void OutputSingleGroupWithLimit( 660c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const set<const CommandLineFlagInfo *> &group, 661c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &line_indentation, 662c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &header, 663c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &footer, 664c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein bool long_output_format, 665c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int *remaining_line_limit, 66667914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein size_t *completion_elements_output, 667c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein vector<string> *completions) { 668c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (group.empty()) return; 669c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (!header.empty()) { 670c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (*remaining_line_limit < 2) return; 671c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein *remaining_line_limit -= 2; 672c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions->push_back(line_indentation + header); 673c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions->push_back(line_indentation + string(header.size(), '-')); 674c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 675c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (set<const CommandLineFlagInfo *>::const_iterator it = group.begin(); 676c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein it != group.end() && *remaining_line_limit > 0; 677c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++it) { 678c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein --*remaining_line_limit; 679c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ++*completion_elements_output; 680c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions->push_back( 681c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein (long_output_format 682c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein ? GetLongFlagLine(line_indentation, **it) 683c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein : GetShortFlagLine(line_indentation, **it))); 684c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 685c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (!footer.empty()) { 686c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (*remaining_line_limit < 1) return; 687c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein --*remaining_line_limit; 688c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein completions->push_back(line_indentation + footer); 689c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 690c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 691c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 692c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic string GetShortFlagLine( 693c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &line_indentation, 694c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const CommandLineFlagInfo &info) { 695917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein string prefix; 696917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein bool is_string = (info.type == "string"); 697917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein SStringPrintf(&prefix, "%s--%s [%s%s%s] ", 698917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein line_indentation.c_str(), 699917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein info.name.c_str(), 700917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein (is_string ? "'" : ""), 701917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein info.default_value.c_str(), 702917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein (is_string ? "'" : "")); 70367914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein int remainder = 70467914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein FLAGS_tab_completion_columns - static_cast<int>(prefix.size()); 70567914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein string suffix; 706c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (remainder > 0) 707c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein suffix = 70867914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein (static_cast<int>(info.description.size()) > remainder ? 709c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein (info.description.substr(0, remainder - 3) + "...").c_str() : 710c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein info.description.c_str()); 711c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return prefix + suffix; 712c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 713c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 714c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinstatic string GetLongFlagLine( 715c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const string &line_indentation, 716c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein const CommandLineFlagInfo &info) { 717c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 718c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string output = DescribeOneFlag(info); 719c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 720c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Replace '-' with '--', and remove trailing newline before appending 721c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // the module definition location. 722c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein string old_flagname = "-" + info.name; 723c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output.replace( 724c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output.find(old_flagname), 725c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein old_flagname.size(), 726c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein "-" + old_flagname); 727c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Stick a newline and indentation in front of the type and default 728c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // portions of DescribeOneFlag()s description 729c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein static const char kNewlineWithIndent[] = "\n "; 730c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output.replace(output.find(" type:"), 1, string(kNewlineWithIndent)); 731c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output.replace(output.find(" default:"), 1, string(kNewlineWithIndent)); 732917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein output = StringPrintf("%s Details for '--%s':\n" 733917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein "%s defined: %s", 734917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein line_indentation.c_str(), 735917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein info.name.c_str(), 736917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein output.c_str(), 737917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein info.filename.c_str()); 738c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 739c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Eliminate any doubled newlines that crept in. Specifically, if 740c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // DescribeOneFlag() decided to break the line just before "type" 741c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // or "default", we don't want to introduce an extra blank line 742c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein static const string line_of_spaces(FLAGS_tab_completion_columns, ' '); 743c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein static const char kDoubledNewlines[] = "\n \n"; 744c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (string::size_type newlines = output.find(kDoubledNewlines); 745c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein newlines != string::npos; 746c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein newlines = output.find(kDoubledNewlines)) 747c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein // Replace each 'doubled newline' with a single newline 748c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output.replace(newlines, sizeof(kDoubledNewlines) - 1, string("\n")); 749c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 750c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein for (string::size_type newline = output.find('\n'); 751c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein newline != string::npos; 752c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein newline = output.find('\n')) { 75367914687b84909782695da9acd04c1324e9e4b0fCraig Silverstein int newline_pos = static_cast<int>(newline) % FLAGS_tab_completion_columns; 754c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein int missing_spaces = FLAGS_tab_completion_columns - newline_pos; 755c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein output.replace(newline, 1, line_of_spaces, 1, missing_spaces); 756c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein } 757c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein return output; 758c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 759c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} // anonymous 760c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 761c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silversteinvoid HandleCommandLineCompletions(void) { 762c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein if (FLAGS_tab_completion_word.empty()) return; 763c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein PrintFlagCompletionInfo(); 764917f4e7bf3c36b4c56a77faca639758d3aca2a92Craig Silverstein gflags_exitfunc(0); 765c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein} 766c79c32d98c4dc705ecc2fea2d7e8712afb6938fbCraig Silverstein 767392eb67dbf63cb96317eaef9d3370a824d7c4adeAndreas Schuh 768392eb67dbf63cb96317eaef9d3370a824d7c4adeAndreas Schuh} // namespace GFLAGS_NAMESPACE 769