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  const std::string& getName() const { return name; }
21 
24  virtual std::string help(const std::vector<std::string>& tokens) const = 0;
25 
31  virtual void tabCompletion(std::vector<std::string>& tokens) const = 0;
32 
33  virtual Interpreter& getInterpreter() const = 0;
34 
35  template<typename ITER>
36  static void completeString(std::vector<std::string>& tokens,
37  ITER begin, ITER end,
38  bool caseSensitive = true);
39  template<typename RANGE>
40  static void completeString(std::vector<std::string>& tokens,
41  const RANGE& possibleValues,
42  bool caseSensitive = true);
43  template<typename RANGE>
44  static void completeFileName(std::vector<std::string>& tokens,
45  const FileContext& context,
46  const RANGE& extra);
47  static void completeFileName(std::vector<std::string>& tokens,
48  const FileContext& context);
49 
50  static std::vector<std::string> formatListInColumns(
51  const std::vector<std::string_view>& input);
52 
53  // helper functions to check the number of arguments
54  struct AtLeast { unsigned min; };
55  struct Between { unsigned min; unsigned max; };
56  struct Prefix { unsigned n; }; // how many items from 'tokens' to show in error
57  void checkNumArgs(span<const TclObject> tokens, unsigned exactly, const char* errMessage) const;
58  void checkNumArgs(span<const TclObject> tokens, AtLeast atLeast, const char* errMessage) const;
59  void checkNumArgs(span<const TclObject> tokens, Between between, const char* errMessage) const;
60  void checkNumArgs(span<const TclObject> tokens, unsigned exactly, Prefix prefix, const char* errMessage) const;
61  void checkNumArgs(span<const TclObject> tokens, AtLeast atLeast, Prefix prefix, const char* errMessage) const;
62  void checkNumArgs(span<const TclObject> tokens, Between between, Prefix prefix, const char* errMessage) const;
63 
64  // should only be called by CommandConsole
65  static void setOutput(InterpreterOutput* output_) { output = output_; }
66 
67 protected:
68  explicit Completer(std::string_view name);
69  ~Completer() = default;
70 
71 private:
72  static bool equalHead(std::string_view s1, std::string_view s2, bool caseSensitive);
73  template<typename ITER>
74  static std::vector<std::string_view> filter(
75  std::string_view str, ITER begin, ITER end, bool caseSensitive);
76  template<typename RANGE>
77  static std::vector<std::string_view> filter(
78  std::string_view str, const RANGE& range, bool caseSensitive);
79  static bool completeImpl(std::string& str, std::vector<std::string_view> matches,
80  bool caseSensitive);
81  static void completeFileNameImpl(std::vector<std::string>& tokens,
82  const FileContext& context,
83  std::vector<std::string_view> matches);
84 
85  const std::string name;
86  static inline InterpreterOutput* output = nullptr;
87 };
88 
89 
90 template<typename ITER>
91 NEVER_INLINE std::vector<std::string_view> Completer::filter(
92  std::string_view str, ITER begin, ITER end, bool caseSensitive)
93 {
94  std::vector<std::string_view> result;
95  for (auto it = begin; it != end; ++it) {
96  if (equalHead(str, *it, caseSensitive)) {
97  result.push_back(*it);
98  }
99  }
100  return result;
101 }
102 
103 template<typename RANGE>
104 inline std::vector<std::string_view> Completer::filter(
105  std::string_view str, const RANGE& range, bool caseSensitive)
106 {
107  return filter(str, std::begin(range), std::end(range), caseSensitive);
108 }
109 
110 template<typename RANGE>
112  std::vector<std::string>& tokens,
113  const RANGE& possibleValues,
114  bool caseSensitive)
115 {
116  auto& str = tokens.back();
117  if (completeImpl(str,
118  filter(str, possibleValues, caseSensitive),
119  caseSensitive)) {
120  tokens.emplace_back();
121  }
122 }
123 
124 template<typename ITER>
126  std::vector<std::string>& tokens,
127  ITER begin, ITER end,
128  bool caseSensitive)
129 {
130  auto& str = tokens.back();
131  if (completeImpl(str,
132  filter(str, begin, end, caseSensitive),
133  caseSensitive)) {
134  tokens.emplace_back();
135  }
136 }
137 
138 template<typename RANGE>
140  std::vector<std::string>& tokens,
141  const FileContext& context,
142  const RANGE& extra)
143 {
144  completeFileNameImpl(tokens, context, filter(tokens.back(), extra, true));
145 }
146 
147 } // namespace openmsx
148 
149 #endif
virtual void tabCompletion(std::vector< std::string > &tokens) const =0
Attempt tab completion for this command.
#define NEVER_INLINE
Definition: inline.hh:17
Definition: span.hh:34
void checkNumArgs(span< const TclObject > tokens, unsigned exactly, const char *errMessage) const
Definition: Completer.cc:178
vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:287
const std::string & getName() const
Definition: Completer.hh:20
~Completer()=default
static void completeFileName(std::vector< std::string > &tokens, const FileContext &context, const RANGE &extra)
Definition: Completer.hh:139
static std::vector< std::string > formatListInColumns(const std::vector< std::string_view > &input)
Definition: Completer.cc:59
std::unique_ptr< Context > context
Definition: GLContext.cc:9
static void setOutput(InterpreterOutput *output_)
Definition: Completer.hh:65
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
Completer(std::string_view name)
Definition: Completer.cc:21
static void completeString(std::vector< std::string > &tokens, ITER begin, ITER end, bool caseSensitive=true)
Definition: Completer.hh:125
virtual std::string help(const std::vector< std::string > &tokens) const =0
Print help for this command.
virtual Interpreter & getInterpreter() const =0