From 887be68011bb910e5be7b7552327420dd88b1c13 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ibrahim=20Numanagic=CC=81?= <ibrahimpasa@gmail.com>
Date: Mon, 6 Dec 2021 01:59:32 -0800
Subject: [PATCH] Add Jupyter plugin support

---
 .gitignore                  |  2 +-
 codon/app/main.cpp          | 13 ++++++++++---
 extra/jupyter/src/codon.cpp | 22 +++++++++++++++++++---
 extra/jupyter/src/codon.h   |  7 +++++--
 4 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/.gitignore b/.gitignore
index ff18d965..84b29947 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,4 +53,4 @@ Thumbs.db
 .vscode
 
 extra/jupyter/share/jupyter/kernels/codon/kernel.json
-scratch.seq
+scratch.*
diff --git a/codon/app/main.cpp b/codon/app/main.cpp
index 0d8d652f..ae830ccf 100644
--- a/codon/app/main.cpp
+++ b/codon/app/main.cpp
@@ -310,13 +310,20 @@ int buildMode(const std::vector<const char *> &args) {
 
 #ifdef CODON_JUPYTER
 namespace codon {
-int startJupyterKernel(const std::string &argv0, const std::string &configPath);
+int startJupyterKernel(const std::string &argv0,
+                       const std::vector<std::string> &plugins,
+                       const std::string &configPath);
 }
 #endif
 int jupyterMode(const std::vector<const char *> &args) {
 #ifdef CODON_JUPYTER
-  int code = codon::startJupyterKernel(args[0], args.size() > 1 ? std::string(args[1])
-                                                                : "connection.json");
+  llvm::cl::list<std::string> plugins("plugin",
+                                      llvm::cl::desc("Load specified plugin"));
+  llvm::cl::opt<std::string> input(llvm::cl::Positional,
+                                   llvm::cl::desc("<connection file>"),
+                                   llvm::cl::init("connection.json"));
+  llvm::cl::ParseCommandLineOptions(args.size(), args.data());
+  int code = codon::startJupyterKernel(args[0], plugins, input);
   return code;
 #else
   fmt::print("Jupyter support not included. Please recompile with "
diff --git a/extra/jupyter/src/codon.cpp b/extra/jupyter/src/codon.cpp
index fa960ca0..9f788b6d 100644
--- a/extra/jupyter/src/codon.cpp
+++ b/extra/jupyter/src/codon.cpp
@@ -23,7 +23,9 @@ using std::string;
 namespace nl = nlohmann;
 namespace codon {
 
-CodonJupyter::CodonJupyter(const std::string &argv0) : argv0(argv0) {}
+CodonJupyter::CodonJupyter(const std::string &argv0,
+                           const std::vector<std::string> &plugins)
+    : argv0(argv0), plugins(plugins) {}
 
 nl::json CodonJupyter::execute_request_impl(int execution_counter, const string &code,
                                             bool silent, bool store_history,
@@ -62,6 +64,18 @@ nl::json CodonJupyter::execute_request_impl(int execution_counter, const string
 
 void CodonJupyter::configure_impl() {
   jit = std::make_unique<codon::jit::JIT>(argv0, "jupyter");
+
+  for (const auto &plugin : plugins) {
+    // TODO: error handling on plugin init
+    bool failed = false;
+    llvm::handleAllErrors(jit->getCompiler()->load(plugin),
+                          [&failed](const codon::error::PluginErrorInfo &e) {
+                            codon::compilationError(e.getMessage(), /*file=*/"",
+                                                    /*line=*/0, /*col=*/0,
+                                                    /*terminate=*/false);
+                            failed = true;
+                          });
+  }
   llvm::cantFail(jit->init());
 }
 
@@ -86,11 +100,13 @@ nl::json CodonJupyter::kernel_info_request_impl() {
 
 void CodonJupyter::shutdown_request_impl() {}
 
-int startJupyterKernel(const std::string &argv0, const std::string &configPath) {
+int startJupyterKernel(const std::string &argv0,
+                       const std::vector<std::string> &plugins,
+                       const std::string &configPath) {
   xeus::xconfiguration config = xeus::load_configuration(configPath);
 
   auto context = xeus::make_context<zmq::context_t>();
-  auto interpreter = std::make_unique<CodonJupyter>(argv0);
+  auto interpreter = std::make_unique<CodonJupyter>(argv0, plugins);
   xeus::xkernel kernel(config, xeus::get_user_name(), move(context), move(interpreter),
                        xeus::make_xserver_zmq);
   kernel.start();
diff --git a/extra/jupyter/src/codon.h b/extra/jupyter/src/codon.h
index ccf8b135..e9d4651b 100644
--- a/extra/jupyter/src/codon.h
+++ b/extra/jupyter/src/codon.h
@@ -11,9 +11,10 @@ namespace codon {
 class CodonJupyter : public xinterpreter {
   std::unique_ptr<codon::jit::JIT> jit;
   std::string argv0;
+  std::vector<std::string> plugins;
 
 public:
-  CodonJupyter(const std::string &argv0);
+  CodonJupyter(const std::string &argv0, const std::vector<std::string> &plugins);
 
 private:
   void configure_impl() override;
@@ -34,7 +35,9 @@ private:
   void shutdown_request_impl() override;
 };
 
-int startJupyterKernel(const std::string &argv0, const std::string &configPath);
+int startJupyterKernel(const std::string &argv0,
+                       const std::vector<std::string> &plugins,
+                       const std::string &configPath);
 
 } // namespace codon
 #endif
\ No newline at end of file