1 /// Prototypes for functions related to tab-completion.
2 ///
3 /// These functions are used for storing and retrieving tab-completion data, as well as for
4 /// performing tab-completion.
5 #ifndef FISH_COMPLETE_H
6 #define FISH_COMPLETE_H
7 
8 #include <stdint.h>
9 
10 #include <functional>
11 #include <vector>
12 
13 #include "common.h"
14 #include "enum_set.h"
15 #include "wcstringutil.h"
16 
17 struct completion_mode_t {
18     /// If set, skip file completions.
19     bool no_files{false};
20     bool force_files{false};
21 
22     /// If set, require a parameter after completion.
23     bool requires_param{false};
24 };
25 
26 /// Character that separates the completion and description on programmable completions.
27 #define PROG_COMPLETE_SEP L'\t'
28 
29 class environment_t;
30 
31 enum {
32     /// Do not insert space afterwards if this is the only completion. (The default is to try insert
33     /// a space).
34     COMPLETE_NO_SPACE = 1 << 0,
35     /// This is not the suffix of a token, but replaces it entirely.
36     COMPLETE_REPLACES_TOKEN = 1 << 2,
37     /// This completion may or may not want a space at the end - guess by checking the last
38     /// character of the completion.
39     COMPLETE_AUTO_SPACE = 1 << 3,
40     /// This completion should be inserted as-is, without escaping.
41     COMPLETE_DONT_ESCAPE = 1 << 4,
42     /// If you do escape, don't escape tildes.
43     COMPLETE_DONT_ESCAPE_TILDES = 1 << 5,
44     /// Do not sort supplied completions
45     COMPLETE_DONT_SORT = 1 << 6,
46     /// This completion looks to have the same string as an existing argument.
47     COMPLETE_DUPLICATES_ARGUMENT = 1 << 7
48 };
49 typedef int complete_flags_t;
50 
51 /// std::function which accepts a completion string and returns its description.
52 using description_func_t = std::function<wcstring(const wcstring &)>;
53 
54 /// Helper to return a description_func_t for a constant string.
55 description_func_t const_desc(const wcstring &s);
56 
57 class completion_t {
58    private:
59     // No public default constructor.
60     completion_t();
61 
62    public:
63     // Destructor. Not inlining it saves code size.
64     ~completion_t();
65 
66     /// The completion string.
67     wcstring completion;
68     /// The description for this completion.
69     wcstring description;
70     /// The type of fuzzy match.
71     string_fuzzy_match_t match;
72     /// Flags determining the completion behavior.
73     ///
74     /// Determines whether a space should be inserted after this completion if it is the only
75     /// possible completion using the COMPLETE_NO_SPACE flag. The COMPLETE_NO_CASE can be used to
76     /// signal that this completion is case insensitive.
77     complete_flags_t flags;
78 
79     // Construction.
80     explicit completion_t(wcstring comp, wcstring desc = wcstring(),
81                           string_fuzzy_match_t match = string_fuzzy_match_t::exact_match(),
82                           complete_flags_t flags_val = 0);
83     completion_t(const completion_t &);
84     completion_t &operator=(const completion_t &);
85 
86     // noexcepts are required for push_back to use the move ctor.
87     completion_t(completion_t &&) noexcept;
88     completion_t &operator=(completion_t &&) noexcept;
89 
90     // Compare two completions. No operating overlaoding to make this always explicit (there's
91     // potentially multiple ways to compare completions).
92     //
93     // "Naturally less than" means in a natural ordering, where digits are treated as numbers. For
94     // example, foo10 is naturally greater than foo2 (but alphabetically less than it).
95     static bool is_naturally_less_than(const completion_t &a, const completion_t &b);
96 
97     /// \return the completion's match rank. Lower ranks are better completions.
rank()98     uint32_t rank() const { return match.rank(); }
99 
100     // If this completion replaces the entire token, prepend a prefix. Otherwise do nothing.
101     void prepend_token_prefix(const wcstring &prefix);
102 };
103 
104 using completion_list_t = std::vector<completion_t>;
105 
106 enum class completion_request_t {
107     autosuggestion,  // indicates the completion is for an autosuggestion
108     descriptions,    // indicates that we want descriptions
109     fuzzy_match,     // indicates that we don't require a prefix match
110     COUNT
111 };
112 
113 template <>
114 struct enum_info_t<completion_request_t> {
115     static constexpr auto count = completion_request_t::COUNT;
116 };
117 
118 using completion_request_flags_t = enum_set_t<completion_request_t>;
119 
120 class completion_t;
121 using completion_list_t = std::vector<completion_t>;
122 
123 /// A completion receiver accepts completions. It is essentially a wrapper around std::vector with
124 /// some conveniences.
125 class completion_receiver_t {
126    public:
127     /// Construct as empty, with a limit.
128     explicit completion_receiver_t(size_t limit) : limit_(limit) {}
129 
130     /// Acquire an existing list, with a limit.
131     explicit completion_receiver_t(completion_list_t &&v, size_t limit)
132         : completions_(std::move(v)), limit_(limit) {}
133 
134     /// Add a completion.
135     /// \return true on success, false if this would overflow the limit.
136     __warn_unused bool add(completion_t &&comp);
137 
138     /// Add a completion with the given string, and default other properties.
139     /// \return true on success, false if this would overflow the limit.
140     __warn_unused bool add(wcstring &&comp);
141 
142     /// Add a completion with the given string, description, flags, and fuzzy match.
143     /// \return true on success, false if this would overflow the limit.
144     /// The 'desc' parameter is not && because if gettext is not enabled, then we end
145     /// up passing a 'const wcstring &' here.
146     __warn_unused bool add(wcstring &&comp, wcstring desc, complete_flags_t flags = 0,
147                            string_fuzzy_match_t match = string_fuzzy_match_t::exact_match());
148 
149     /// Add a list of completions.
150     /// \return true on success, false if this would overflow the limit.
151     __warn_unused bool add_list(completion_list_t &&lst);
152 
153     /// Swap our completions with a new list.
154     void swap(completion_list_t &lst) { std::swap(completions_, lst); }
155 
156     /// Clear the list of completions. This retains the storage inside completions_ which can be
157     /// useful to prevent allocations.
158     void clear() { completions_.clear(); }
159 
160     /// \return whether our completion list is empty.
161     bool empty() const { return completions_.empty(); }
162 
163     /// \return how many completions we have stored.
164     size_t size() const { return completions_.size(); }
165 
166     /// \return a completion at an index.
167     completion_t &at(size_t idx) { return completions_.at(idx); }
168     const completion_t &at(size_t idx) const { return completions_.at(idx); }
169 
170     /// \return the list of completions. Do not modify the size of the list via this function, as it
171     /// may exceed our completion limit.
172     const completion_list_t &get_list() const { return completions_; }
173     completion_list_t &get_list() { return completions_; }
174 
175     /// \return the list of completions, clearing it.
176     completion_list_t take();
177 
178     /// \return a new, empty receiver whose limit is our remaining capacity.
179     /// This is useful for e.g. recursive calls when you want to act on the result before adding it.
180     completion_receiver_t subreceiver() const;
181 
182    private:
183     // Our list of completions.
184     completion_list_t completions_;
185 
186     // The maximum number of completions to add. If our list length exceeds this, then new
187     // completions are not added. Note 0 has no special significance here - use
188     // numeric_limits<size_t>::max() instead.
189     const size_t limit_;
190 };
191 
192 enum complete_option_type_t {
193     option_type_args_only,    // no option
194     option_type_short,        // -x
195     option_type_single_long,  // -foo
196     option_type_double_long   // --foo
197 };
198 
199 /// Sorts and remove any duplicate completions in the completion list, then puts them in priority
200 /// order.
201 void completions_sort_and_prioritize(completion_list_t *comps,
202                                      completion_request_flags_t flags = {});
203 
204 /// Add a completion.
205 ///
206 /// All supplied values are copied, they should be freed by or otherwise disposed by the caller.
207 ///
208 /// Examples:
209 ///
210 /// The command 'gcc -o' requires that a file follows it, so the NO_COMMON option is suitable. This
211 /// can be done using the following line:
212 ///
213 /// complete -c gcc -s o -r
214 ///
215 /// The command 'grep -d' required that one of the strings 'read', 'skip' or 'recurse' is used. As
216 /// such, it is suitable to specify that a completion requires one of them. This can be done using
217 /// the following line:
218 ///
219 /// complete -c grep -s d -x -a "read skip recurse"
220 ///
221 /// \param cmd Command to complete.
222 /// \param cmd_is_path If cmd_is_path is true, cmd will be interpreted as the absolute
223 ///   path of the program (optionally containing wildcards), otherwise it
224 ///   will be interpreted as the command name.
225 /// \param option The name of an option.
226 /// \param option_type The type of option: can be option_type_short (-x),
227 ///        option_type_single_long (-foo), option_type_double_long (--bar).
228 /// \param result_mode Controls how to search further completions when this completion has been
229 /// successfully matched.
230 /// \param comp A space separated list of completions which may contain subshells.
231 /// \param desc A description of the completion.
232 /// \param condition a command to be run to check it this completion should be used. If \c condition
233 /// is empty, the completion is always used.
234 /// \param flags A set of completion flags
235 void complete_add(const wchar_t *cmd, bool cmd_is_path, const wcstring &option,
236                   complete_option_type_t option_type, completion_mode_t result_mode,
237                   const wchar_t *condition, const wchar_t *comp, const wchar_t *desc, int flags);
238 
239 /// Remove a previously defined completion.
240 void complete_remove(const wcstring &cmd, bool cmd_is_path, const wcstring &option,
241                      complete_option_type_t type);
242 
243 /// Removes all completions for a given command.
244 void complete_remove_all(const wcstring &cmd, bool cmd_is_path);
245 
246 /// \return all completions of the command cmd.
247 class operation_context_t;
248 completion_list_t complete(const wcstring &cmd, completion_request_flags_t flags,
249                            const operation_context_t &ctx);
250 
251 /// Return a list of all current completions.
252 wcstring complete_print(const wcstring &cmd = L"");
253 
254 /// Tests if the specified option is defined for the specified command.
255 int complete_is_valid_option(const wcstring &str, const wcstring &opt,
256                              wcstring_list_t *inErrorsOrNull, bool allow_autoload);
257 
258 /// Tests if the specified argument is valid for the specified option and command.
259 bool complete_is_valid_argument(const wcstring &str, const wcstring &opt, const wcstring &arg);
260 
261 /// Create a new completion entry.
262 ///
263 /// \param completions The array of completions to append to
264 /// \param comp The completion string
265 /// \param desc The description of the completion
266 /// \param flags completion flags
267 void append_completion(completion_list_t *completions, wcstring comp, wcstring desc = wcstring(),
268                        int flags = 0,
269                        string_fuzzy_match_t match = string_fuzzy_match_t::exact_match());
270 
271 /// Support for "wrap targets." A wrap target is a command that completes like another command.
272 bool complete_add_wrapper(const wcstring &command, const wcstring &new_target);
273 bool complete_remove_wrapper(const wcstring &command, const wcstring &target_to_remove);
274 
275 /// Returns a list of wrap targets for a given command.
276 wcstring_list_t complete_get_wrap_targets(const wcstring &command);
277 
278 // Observes that fish_complete_path has changed.
279 void complete_invalidate_path();
280 
281 #endif
282