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 &notable_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      &notable_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      &notable_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          &notable_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        &notable_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        &notable_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        &notable_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        &notable_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 &notable_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