openMSX
Completer.cc
Go to the documentation of this file.
1#include "Completer.hh"
2#include "Interpreter.hh"
4#include "FileContext.hh"
5#include "FileOperations.hh"
6#include "foreach_file.hh"
7#include "ranges.hh"
8#include "stl.hh"
9#include "strCat.hh"
10#include "stringsp.hh"
11#include "TclObject.hh"
12#include "utf8_unchecked.hh"
13#include "xrange.hh"
14
15using std::vector;
16using std::string;
17using std::string_view;
18
19namespace openmsx {
20
21static bool formatHelper(std::span<const string_view> input, size_t columnLimit,
22 vector<string>& result)
23{
24 size_t column = 0;
25 auto it = begin(input);
26 do {
27 size_t maxcolumn = column;
28 for (size_t i = 0; (i < result.size()) && (it != end(input));
29 ++i, ++it) {
30 auto curSize = utf8::unchecked::size(result[i]);
31 strAppend(result[i], spaces(column - curSize), *it);
32 maxcolumn = std::max(maxcolumn,
33 utf8::unchecked::size(result[i]));
34 if (maxcolumn > columnLimit) return false;
35 }
36 column = maxcolumn + 2;
37 } while (it != end(input));
38 return true;
39}
40
41static vector<string> format(std::span<const string_view> input, size_t columnLimit)
42{
43 vector<string> result;
44 for (auto lines : xrange(1u, input.size())) {
45 result.assign(lines, string());
46 if (formatHelper(input, columnLimit, result)) {
47 return result;
48 }
49 }
50 append(result, input);
51 return result;
52}
53
54vector<string> Completer::formatListInColumns(std::span<const string_view> input)
55{
56 return format(input, output->getOutputColumns() - 1);
57}
58
59bool Completer::equalHead(string_view s1, string_view s2, bool caseSensitive)
60{
61 if (s2.size() < s1.size()) return false;
62 if (caseSensitive) {
63 return memcmp(s1.data(), s2.data(), s1.size()) == 0;
64 } else {
65 return strncasecmp(s1.data(), s2.data(), s1.size()) == 0;
66 }
67}
68
69bool Completer::completeImpl(string& str, vector<string_view> matches,
70 bool caseSensitive)
71{
72 assert(ranges::all_of(matches, [&](auto& m) {
73 return equalHead(str, m, caseSensitive);
74 }));
75
76 if (matches.empty()) {
77 // no matching values
78 return false;
79 }
80 if (matches.size() == 1) {
81 // only one match
82 str = matches.front();
83 return true;
84 }
85
86 // Sort and remove duplicates.
87 // For efficiency it's best if the list doesn't contain duplicates to
88 // start with. Though sometimes this is hard to avoid. E.g. when doing
89 // filename completion + some extra allowed strings and one of these
90 // extra strings is the same as one of the filenames.
93
94 bool expanded = false;
95 while (true) {
96 auto it = begin(matches);
97 if (str.size() == it->size()) {
98 // match is as long as first word
99 goto out; // TODO rewrite this
100 }
101 // expand with one char and check all strings
102 auto b = begin(*it);
103 auto e = b + str.size();
104 utf8::unchecked::next(e); // one more utf8 char
105 string_view string2(&*b, e - b);
106 for (; it != end(matches); ++it) {
107 if (!equalHead(string2, *it, caseSensitive)) {
108 goto out; // TODO rewrite this
109 }
110 }
111 // no conflict found
112 str = string2;
113 expanded = true;
114 }
115 out:
116 if (!expanded && output) {
117 // print all possibilities
118 for (auto& line : formatListInColumns(matches)) {
119 output->output(line);
120 }
121 }
122 return false;
123}
124
125void Completer::completeFileName(vector<string>& tokens,
126 const FileContext& context)
127{
128 completeFileNameImpl(tokens, context, vector<string_view>());
129}
130
131void Completer::completeFileNameImpl(vector<string>& tokens,
132 const FileContext& context,
133 vector<string_view> matches)
134{
135 string& filename = tokens.back();
138 string_view dirname1 = FileOperations::getDirName(filename);
139
140 std::span<const string> paths;
142 static const string EMPTY[1] = {""};
143 paths = EMPTY;
144 } else {
145 paths = context.getPaths();
146 }
147
148 vector<string> filenames;
149 for (const auto& p : paths) {
150 auto pLen = p.size();
151 if (!p.empty() && (p.back() != '/')) ++pLen;
152 auto fileAction = [&](const string& path) {
154 path.substr(pLen));
155 if (equalHead(filename, nm, true)) {
156 filenames.push_back(nm);
157 }
158 };
159 auto dirAction = [&](string& path) {
160 path += '/';
161 fileAction(path);
162 path.pop_back();
163 };
165 FileOperations::join(p, dirname1),
166 fileAction, dirAction);
167 }
168 append(matches, filenames);
169 bool t = completeImpl(filename, matches, true);
170 if (t && !filename.empty() && (filename.back() != '/')) {
171 // completed filename, start new token
172 tokens.emplace_back();
173 }
174}
175
176void Completer::checkNumArgs(std::span<const TclObject> tokens, unsigned exactly, const char* errMessage) const
177{
178 checkNumArgs(tokens, exactly, Prefix{exactly - 1}, errMessage);
179}
180
181void Completer::checkNumArgs(std::span<const TclObject> tokens, AtLeast atLeast, const char* errMessage) const
182{
183 checkNumArgs(tokens, atLeast, Prefix{atLeast.min - 1}, errMessage);
184}
185
186void Completer::checkNumArgs(std::span<const TclObject> tokens, Between between, const char* errMessage) const
187{
188 checkNumArgs(tokens, between, Prefix{between.min - 1}, errMessage);
189}
190
191void Completer::checkNumArgs(std::span<const TclObject> tokens, unsigned exactly, Prefix prefix, const char* errMessage) const
192{
193 if (tokens.size() == exactly) return;
194 getInterpreter().wrongNumArgs(prefix.n, tokens, errMessage);
195}
196
197void Completer::checkNumArgs(std::span<const TclObject> tokens, AtLeast atLeast, Prefix prefix, const char* errMessage) const
198{
199 if (tokens.size() >= atLeast.min) return;
200 getInterpreter().wrongNumArgs(prefix.n, tokens, errMessage);
201}
202
203void Completer::checkNumArgs(std::span<const TclObject> tokens, Between between, Prefix prefix, const char* errMessage) const
204{
205 if (tokens.size() >= between.min && tokens.size() <= between.max) return;
206 getInterpreter().wrongNumArgs(prefix.n, tokens, errMessage);
207}
208
209} // namespace openmsx
TclObject t
static void completeFileName(std::vector< std::string > &tokens, const FileContext &context, const RANGE &extra)
Definition: Completer.hh:147
static std::vector< std::string > formatListInColumns(std::span< const std::string_view > input)
Definition: Completer.cc:54
virtual Interpreter & getInterpreter() const =0
void checkNumArgs(std::span< const TclObject > tokens, unsigned exactly, const char *errMessage) const
Definition: Completer.cc:176
virtual unsigned getOutputColumns() const =0
virtual void output(std::string_view text)=0
void wrongNumArgs(unsigned argc, std::span< const TclObject > tokens, const char *message)
Definition: Interpreter.cc:461
constexpr double e
Definition: Math.hh:18
void append(Result &)
Definition: stl.hh:290
std::optional< Context > context
Definition: GLContext.cc:9
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:283
string expandTilde(string path)
Expand the '~' character to the users home directory.
string_view getDirName(string_view path)
Returns the directory portion of a path.
const std::string & expandCurrentDirFromDrive(const std::string &path)
Get the current directory of the specified drive Linux: return the given string unchanged.
bool isAbsolutePath(string_view path)
Checks whether it's a absolute path or not.
const std::string & getConventionalPath(const std::string &path)
Returns the path in conventional path-delimiter.
string join(string_view part1, string_view part2)
Join two paths.
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:216
constexpr const char *const filename
bool foreach_file_and_directory(std::string path, FileAction fileAction, DirAction dirAction)
auto unique(ForwardRange &&range)
Definition: ranges.hh:181
bool all_of(InputRange &&range, UnaryPredicate pred)
Definition: ranges.hh:163
constexpr void sort(RandomAccessRange &&range)
Definition: ranges.hh:33
size_t size(std::string_view utf8)
uint32_t next(octet_iterator &it)
strCatImpl::ConcatSpaces spaces(size_t n)
Definition: strCat.hh:658
void strAppend(std::string &result, Ts &&...ts)
Definition: strCat.hh:627
constexpr auto xrange(T e)
Definition: xrange.hh:133
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)