summaryrefslogtreecommitdiff
path: root/elpa/irony-20220110.849/server/src/Command.cpp
diff options
context:
space:
mode:
authormattkae <mattkae@protonmail.com>2022-05-11 09:23:58 -0400
committermattkae <mattkae@protonmail.com>2022-05-11 09:23:58 -0400
commit3f4a0d5370ae6c34afe180df96add3b8522f4af1 (patch)
treeae901409e02bde8ee278475f8cf6818f8f680a60 /elpa/irony-20220110.849/server/src/Command.cpp
initial commit
Diffstat (limited to 'elpa/irony-20220110.849/server/src/Command.cpp')
-rw-r--r--elpa/irony-20220110.849/server/src/Command.cpp278
1 files changed, 278 insertions, 0 deletions
diff --git a/elpa/irony-20220110.849/server/src/Command.cpp b/elpa/irony-20220110.849/server/src/Command.cpp
new file mode 100644
index 0000000..363b6cb
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/Command.cpp
@@ -0,0 +1,278 @@
+/**
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * \brief Command parser definitions.
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#include "Command.h"
+
+#include "support/CommandLineParser.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <limits>
+#include <map>
+
+
+namespace {
+
+struct StringConverter {
+ StringConverter(std::string *dest) : dest_(dest) {
+ }
+
+ bool operator()(const std::string &str) {
+ *dest_ = str;
+ return true;
+ }
+
+private:
+ std::string *dest_;
+};
+
+struct UnsignedIntConverter {
+ UnsignedIntConverter(unsigned *dest) : dest_(dest) {
+ }
+
+ bool operator()(const std::string &str) {
+ char *end;
+ long num = std::strtol(str.c_str(), &end, 10);
+
+ if (end != (str.c_str() + str.size()))
+ return false;
+
+ if (errno == ERANGE)
+ return false;
+
+ if (num < 0)
+ return false;
+
+ unsigned long unum = static_cast<unsigned long>(num);
+ if (unum > std::numeric_limits<unsigned>::max())
+ return false;
+
+ *dest_ = unum;
+ return true;
+ }
+
+private:
+ unsigned *dest_;
+};
+
+/// Convert "on" and "off" to a boolean
+struct OptionConverter {
+ OptionConverter(bool *dest) : dest_(dest) {
+ }
+
+ bool operator()(const std::string &str) {
+ if (str == "on") {
+ *dest_ = true;
+ } else if (str == "off") {
+ *dest_ = false;
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+private:
+ bool *dest_;
+};
+
+const std::map<std::string, PrefixMatchStyle> PREFIX_MATCH_STYLE_MAP = {
+ { "exact", PrefixMatchStyle::Exact },
+ { "case-insensitive", PrefixMatchStyle::CaseInsensitive },
+ { "smart-case", PrefixMatchStyle::SmartCase},
+};
+
+/// Convert style to a PrefixMatchStyle
+struct PrefixMatchStyleConverter {
+ PrefixMatchStyleConverter(PrefixMatchStyle *dest) : dest_(dest) {
+ }
+
+ bool operator()(const std::string &str) {
+ auto res = PREFIX_MATCH_STYLE_MAP.find(str);
+
+ if (res == PREFIX_MATCH_STYLE_MAP.cend()) {
+ return false;
+ }
+ *dest_ = res->second;
+ return true;
+ }
+
+private:
+ PrefixMatchStyle *dest_;
+};
+
+std::ostream &operator<<(std::ostream &os, PrefixMatchStyle style) {
+ for (auto it : PREFIX_MATCH_STYLE_MAP) {
+ if (it.second == style) {
+ os << it.first;
+ return os;
+ }
+ }
+ os << "UnknownStyle";
+ return os;
+}
+
+
+} // unnamed namespace
+
+std::ostream &operator<<(std::ostream &os, const Command::Action &action) {
+ os << "Command::";
+
+ switch (action) {
+#define X(sym, str, help) \
+ case Command::sym: \
+ os << #sym; \
+ break;
+#include "Commands.def"
+ }
+ return os;
+}
+
+std::ostream &operator<<(std::ostream &os, const Command &command) {
+ os << "Command{action=" << command.action << ", "
+ << "file='" << command.file << "', "
+ << "unsavedFile='" << command.unsavedFile << "', "
+ << "dir='" << command.dir << "', "
+ << "line=" << command.line << ", "
+ << "column=" << command.column << ", "
+ << "prefix='" << command.prefix << "', "
+ << "caseStyle='" << command.style << "', "
+ << "flags=[";
+ bool first = true;
+ for (const std::string &flag : command.flags) {
+ if (!first)
+ os << ", ";
+ os << "'" << flag << "'";
+ first = false;
+ }
+ os << "], "
+ << "opt=" << (command.opt ? "on" : "off");
+
+ return os << "}";
+}
+
+static Command::Action actionFromString(const std::string &actionStr) {
+#define X(sym, str, help) \
+ if (actionStr == str) \
+ return Command::sym;
+
+#include "Commands.def"
+
+ return Command::Unknown;
+}
+
+CommandParser::CommandParser() : tempFile_("irony-server") {
+}
+
+Command *CommandParser::parse(const std::vector<std::string> &argv) {
+ command_.clear();
+
+ if (argv.begin() == argv.end()) {
+ std::clog << "error: no command specified.\n"
+ "See 'irony-server help' to list available commands\n";
+ return 0;
+ }
+
+ const std::string &actionStr = argv[0];
+
+ command_.action = actionFromString(actionStr);
+
+ bool readCompileOptions = false;
+ std::vector<std::function<bool(const std::string &)>> positionalArgs;
+
+ switch (command_.action) {
+ case Command::SetDebug:
+ positionalArgs.push_back(OptionConverter(&command_.opt));
+ break;
+
+ case Command::Parse:
+ positionalArgs.push_back(StringConverter(&command_.file));
+ readCompileOptions = true;
+ break;
+
+ case Command::Complete:
+ positionalArgs.push_back(StringConverter(&command_.file));
+ positionalArgs.push_back(UnsignedIntConverter(&command_.line));
+ positionalArgs.push_back(UnsignedIntConverter(&command_.column));
+ readCompileOptions = true;
+ break;
+
+ case Command::GetType:
+ positionalArgs.push_back(UnsignedIntConverter(&command_.line));
+ positionalArgs.push_back(UnsignedIntConverter(&command_.column));
+ break;
+
+ case Command::SetUnsaved:
+ positionalArgs.push_back(StringConverter(&command_.file));
+ positionalArgs.push_back(StringConverter(&command_.unsavedFile));
+ break;
+
+ case Command::ResetUnsaved:
+ positionalArgs.push_back(StringConverter(&command_.file));
+ break;
+
+ case Command::Candidates:
+ positionalArgs.push_back(StringConverter(&command_.prefix));
+ positionalArgs.push_back(PrefixMatchStyleConverter(&command_.style));
+ break;
+ case Command::CompletionDiagnostics:
+ case Command::Diagnostics:
+ case Command::Help:
+ case Command::Exit:
+ // no-arguments commands
+ break;
+
+ case Command::GetCompileOptions:
+ positionalArgs.push_back(StringConverter(&command_.dir));
+ positionalArgs.push_back(StringConverter(&command_.file));
+ break;
+
+ case Command::Unknown:
+ std::clog << "error: invalid command specified: " << actionStr << "\n";
+ return 0;
+ }
+
+ auto argsBegin = argv.begin() + 1;
+ const auto argsEnd = std::find(argsBegin, argv.end(), "--");
+ const int argCount = std::distance(argsBegin, argsEnd);
+
+ // compile options are provided after '--'
+ if (readCompileOptions && argsEnd != argv.end()) {
+ command_.flags.assign(std::next(argsEnd), argv.end());
+ }
+
+ if (argCount != static_cast<int>(positionalArgs.size())) {
+ std::clog << "error: invalid number of arguments for '" << actionStr
+ << "' (requires " << positionalArgs.size() << " got " << argCount
+ << ")\n";
+ return 0;
+ }
+
+ for (auto fn : positionalArgs) {
+ if (!fn(*argsBegin)) {
+ std::clog << "error: parsing command '" << actionStr
+ << "': invalid argument '" << *argsBegin << "'\n";
+ return 0;
+ }
+ ++argsBegin;
+ }
+
+ // '-' is used as a special file to inform that the buffer hasn't been saved
+ // on disk and only the buffer content is available. libclang needs a file, so
+ // this is treated as a special value for irony-server to create a temporary
+ // file for this. note that libclang will gladly accept '-' as a filename but
+ // we don't want to let this happen since irony already reads stdin.
+ if (command_.file == "-") {
+ command_.file = tempFile_.getPath();
+ }
+
+ return &command_;
+}