openMSX
Completer.hh
Go to the documentation of this file.
1#ifndef COMPLETER_HH
2#define COMPLETER_HH
3
4#include "inline.hh"
5
6#include <concepts>
7#include <span>
8#include <string>
9#include <string_view>
10#include <vector>
11
12namespace openmsx {
13
14class FileContext;
15class Interpreter;
16class InterpreterOutput;
17class TclObject;
18
20{
21public:
22 Completer(const Completer&) = delete;
23 Completer& operator=(const Completer&) = delete;
24
25 [[nodiscard]] const std::string& getName() const { return theName; }
26
29 [[nodiscard]] virtual std::string help(std::span<const TclObject> tokens) const = 0;
30
36 virtual void tabCompletion(std::vector<std::string>& tokens) const = 0;
37
38 [[nodiscard]] virtual Interpreter& getInterpreter() const = 0;
39
40 template<typename ITER>
41 static void completeString(std::vector<std::string>& tokens,
42 ITER begin, ITER end,
43 bool caseSensitive = true);
44 template<typename RANGE>
45 static void completeString(std::vector<std::string>& tokens,
46 RANGE&& possibleValues,
47 bool caseSensitive = true);
48 template<typename RANGE>
49 static void completeFileName(std::vector<std::string>& tokens,
50 const FileContext& context,
51 const RANGE& extra);
52 static void completeFileName(std::vector<std::string>& tokens,
53 const FileContext& context);
54
55 static std::vector<std::string> formatListInColumns(
56 std::span<const std::string_view> input);
57
58 // helper functions to check the number of arguments
59 struct AtLeast { unsigned min; };
60 struct Between { unsigned min; unsigned max; };
61 struct Prefix { unsigned n; }; // how many items from 'tokens' to show in error
62 void checkNumArgs(std::span<const TclObject> tokens, unsigned exactly, const char* errMessage) const;
63 void checkNumArgs(std::span<const TclObject> tokens, AtLeast atLeast, const char* errMessage) const;
64 void checkNumArgs(std::span<const TclObject> tokens, Between between, const char* errMessage) const;
65 void checkNumArgs(std::span<const TclObject> tokens, unsigned exactly, Prefix prefix, const char* errMessage) const;
66 void checkNumArgs(std::span<const TclObject> tokens, AtLeast atLeast, Prefix prefix, const char* errMessage) const;
67 void checkNumArgs(std::span<const TclObject> tokens, Between between, Prefix prefix, const char* errMessage) const;
68
69 // should only be called by CommandConsole
70 static void setOutput(InterpreterOutput* output_) { output = output_; }
71
72protected:
73 template<typename String>
74 requires(!std::same_as<Completer, std::remove_cvref_t<String>>) // don't block copy-constructor
75 explicit Completer(String&& name_)
76 : theName(std::forward<String>(name_))
77 {
78 }
79
80 ~Completer() = default;
81
82private:
83 static bool equalHead(std::string_view s1, std::string_view s2, bool caseSensitive);
84 template<typename ITER>
85 static std::vector<std::string_view> filter(
86 std::string_view str, ITER begin, ITER end, bool caseSensitive);
87 template<typename RANGE>
88 static std::vector<std::string_view> filter(
89 std::string_view str, RANGE&& range, bool caseSensitive);
90 static bool completeImpl(std::string& str, std::vector<std::string_view> matches,
91 bool caseSensitive);
92 static void completeFileNameImpl(std::vector<std::string>& tokens,
93 const FileContext& context,
94 std::vector<std::string_view> matches);
95
96 const std::string theName;
97 static inline InterpreterOutput* output = nullptr;
98};
99
100
101template<typename ITER>
102NEVER_INLINE std::vector<std::string_view> Completer::filter(
103 std::string_view str, ITER begin, ITER end, bool caseSensitive)
104{
105 std::vector<std::string_view> result;
106 for (auto it = begin; it != end; ++it) {
107 if (equalHead(str, *it, caseSensitive)) {
108 result.push_back(*it);
109 }
110 }
111 return result;
112}
113
114template<typename RANGE>
115inline std::vector<std::string_view> Completer::filter(
116 std::string_view str, RANGE&& range, bool caseSensitive)
117{
118 return filter(str, std::begin(range), std::end(range), caseSensitive);
119}
120
121template<typename RANGE>
123 std::vector<std::string>& tokens,
124 RANGE&& possibleValues,
125 bool caseSensitive)
126{
127 auto& str = tokens.back();
128 if (completeImpl(str,
129 filter(str, std::forward<RANGE>(possibleValues), caseSensitive),
130 caseSensitive)) {
131 tokens.emplace_back();
132 }
133}
134
135template<typename ITER>
137 std::vector<std::string>& tokens,
138 ITER begin, ITER end,
139 bool caseSensitive)
140{
141 auto& str = tokens.back();
142 if (completeImpl(str,
143 filter(str, begin, end, caseSensitive),
144 caseSensitive)) {
145 tokens.emplace_back();
146 }
147}
148
149template<typename RANGE>
151 std::vector<std::string>& tokens,
152 const FileContext& context,
153 const RANGE& extra)
154{
155 completeFileNameImpl(tokens, context, filter(tokens.back(), extra, true));
156}
157
158} // namespace openmsx
159
160#endif
Completer(String &&name_)
Definition Completer.hh:75
static void completeFileName(std::vector< std::string > &tokens, const FileContext &context, const RANGE &extra)
Definition Completer.hh:150
static void setOutput(InterpreterOutput *output_)
Definition Completer.hh:70
virtual void tabCompletion(std::vector< std::string > &tokens) const =0
Attempt tab completion for this command.
static void completeString(std::vector< std::string > &tokens, ITER begin, ITER end, bool caseSensitive=true)
Definition Completer.hh:136
virtual std::string help(std::span< const TclObject > tokens) const =0
Print help for this command.
static std::vector< std::string > formatListInColumns(std::span< const std::string_view > input)
Definition Completer.cc:59
const std::string & getName() const
Definition Completer.hh:25
~Completer()=default
virtual Interpreter & getInterpreter() const =0
void checkNumArgs(std::span< const TclObject > tokens, unsigned exactly, const char *errMessage) const
Definition Completer.cc:181
Completer & operator=(const Completer &)=delete
Completer(const Completer &)=delete
#define NEVER_INLINE
Definition inline.hh:17
This file implemented 3 utility functions:
Definition Autofire.cc:11
bool matches(const Event &self, const Event &other)
Does this event 'match' the given event.
Definition Event.cc:210
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)