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