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