Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 77 additions & 92 deletions src/xinspect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@

#include <filesystem>
#include <fstream>
#include <iostream>
#include <regex>
#include <string>
#include <utility>
#include <vector>

#include "xeus/xhelper.hpp"

#include "xinspect.hpp"

Expand Down Expand Up @@ -60,71 +64,59 @@ namespace xcpp
return false;
}

std::string find_type_slow(const std::string& expression)
namespace
{
static unsigned long long var_count = 0;

if (auto* type = Cpp::GetType(expression))
std::string find_type_slow(const std::string& expression)
{
return Cpp::GetQualifiedName(type);
}
static unsigned long long var_count = 0;

std::string id = "__Xeus_GetType_" + std::to_string(var_count++);
std::string using_clause = "using " + id + " = __typeof__(" + expression + ");\n";
if (auto* type = Cpp::GetType(expression))
{
return Cpp::GetQualifiedName(type);
}

if (!Cpp::Declare(using_clause.c_str(), false))
{
Cpp::TCppScope_t lookup = Cpp::GetNamed(id, nullptr);
Cpp::TCppType_t lookup_ty = Cpp::GetTypeFromScope(lookup);
return Cpp::GetQualifiedCompleteName(Cpp::GetCanonicalType(lookup_ty));
}
return "";
}
std::string id = "__Xeus_GetType_" + std::to_string(var_count++);
std::string using_clause = "using " + id + " = __typeof__(" + expression + ");\n";

nl::json read_tagconfs(const char* path)
{
nl::json result = nl::json::array();
for (const auto& entry : std::filesystem::directory_iterator(path))
{
if (entry.path().extension() != ".json")
if (!Cpp::Declare(using_clause.c_str(), false))
{
continue;
Cpp::TCppScope_t lookup = Cpp::GetNamed(id, nullptr);
Cpp::TCppType_t lookup_ty = Cpp::GetTypeFromScope(lookup);
return Cpp::GetQualifiedCompleteName(Cpp::GetCanonicalType(lookup_ty));
}
std::ifstream i(entry.path());
nl::json json_entry;
i >> json_entry;
result.emplace_back(std::move(json_entry));
return "";
}
return result;
}

std::pair<bool, std::smatch> is_inspect_request(const std::string& code, const std::regex& re)
{
std::smatch inspect;
if (std::regex_search(code, inspect, re))
nl::json read_tagconfs(const char* path)
{
return std::make_pair(true, inspect);
nl::json result = nl::json::array();
for (const auto& entry : std::filesystem::directory_iterator(path))
{
if (entry.path().extension() != ".json")
{
continue;
}
std::ifstream i(entry.path());
nl::json json_entry;
i >> json_entry;
result.emplace_back(std::move(json_entry));
}
return result;
}
return std::make_pair(false, inspect);
}

void inspect(const std::string& code, nl::json& kernel_res)
std::string inspect(const std::string& code)
{
std::string tagconf_dir = retrieve_tagconf_dir();
std::string tagfiles_dir = retrieve_tagfile_dir();

nl::json tagconfs = read_tagconfs(tagconf_dir.c_str());

std::vector<std::string> check{"class", "struct", "function"};

std::string url, tagfile;

std::regex re_expression(R"((((?:\w*(?:\:{2}|\<.*\>|\(.*\)|\[.*\])?)\.?)*))");

std::smatch inspect = is_inspect_request(code, re_expression).second;
std::smatch inspect;
std::regex_search(code, inspect, re_expression);

std::string inspect_result;

std::smatch method;
std::string to_inspect = inspect[1];

Expand All @@ -138,8 +130,8 @@ namespace xcpp
{
for (nl::json::const_iterator it = tagconfs.cbegin(); it != tagconfs.cend(); ++it)
{
url = it->at("url");
tagfile = it->at("tagfile");
std::string url = it->at("url");
std::string tagfile = it->at("tagfile");
std::string filename = tagfiles_dir + "/" + tagfile;
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(filename.c_str());
Expand Down Expand Up @@ -170,10 +162,11 @@ namespace xcpp
find_string = (type_name.empty()) ? to_inspect : type_name;
}

const std::vector<std::string> check{"class", "struct", "function"};
for (nl::json::const_iterator it = tagconfs.cbegin(); it != tagconfs.cend(); ++it)
{
url = it->at("url");
tagfile = it->at("tagfile");
std::string url = it->at("url");
std::string tagfile = it->at("tagfile");
std::string filename = tagfiles_dir + "/" + tagfile;
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(filename.c_str());
Expand All @@ -198,53 +191,33 @@ namespace xcpp
}
}
}
std::cout << std::flush;
return inspect_result;
}

if (inspect_result.empty())
{
std::cerr << "No documentation found for " << code << "\n";
std::cout << std::flush;
kernel_res["found"] = false;
kernel_res["status"] = "error";
kernel_res["ename"] = "No documentation found";
kernel_res["evalue"] = "";
kernel_res["traceback"] = nl::json::array();
nl::json build_inspect_data(const std::string& inspect_result)
{
// Format html content.
std::string html_content = R"(<style>
#pager-container {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
else
{
// Format html content.
std::string html_content = R"(<style>
#pager-container {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
.xcpp-iframe-pager {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
border: none;
}
</style>
<iframe class="xcpp-iframe-pager" src=")"
+ inspect_result + R"(?action=purge"></iframe>)";

// Note: Adding "?action=purge" suffix to force cppreference's
// Mediawiki to purge the HTTP cache.

kernel_res["payload"] = nl::json::array();
kernel_res["payload"][0] = nl::json::object(
{{"data", {{"text/plain", inspect_result}, {"text/html", html_content}}},
{"source", "page"},
{"start", 0}}
);
kernel_res["user_expressions"] = nl::json::object();

std::cout << std::flush;
kernel_res["found"] = true;
kernel_res["status"] = "ok";
.xcpp-iframe-pager {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
border: none;
}
</style>
<iframe class="xcpp-iframe-pager" src=")"
+ inspect_result + R"(?action=purge"></iframe>)";

auto data = nl::json::object({{"text/plain", inspect_result}, {"text/html", html_content}});
return data;
}

xintrospection::xintrospection()
Expand All @@ -257,7 +230,19 @@ namespace xcpp
std::regex re(spattern + R"((.*))");
std::smatch to_inspect;
std::regex_search(code, to_inspect, re);
inspect(to_inspect[1], kernel_res);
std::string result = inspect(to_inspect[1]);
if (result.empty())
{
kernel_res = xeus::create_error_reply("No documentation found");
}
else
{
auto payload = nl::json::array();
payload[0] = nl::json::object(
{{"data", build_inspect_data(result)}, {"source", "page"}, {"start", 0}}
);
kernel_res = xeus::create_successful_reply(payload);
}
}

std::unique_ptr<xpreamble> xintrospection::clone() const
Expand Down
11 changes: 4 additions & 7 deletions src/xinspect.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include <pugixml.hpp>

#include <nlohmann/json_fwd.hpp>

#include "xeus-cpp/xpreamble.hpp"
#include "xeus-cpp/xutils.hpp"

Expand All @@ -39,13 +41,8 @@ namespace xcpp
bool operator()(pugi::xml_node node) const;
};

XEUS_CPP_API std::string find_type_slow(const std::string& expression);

nl::json read_tagconfs(const char* path);

XEUS_CPP_API std::pair<bool, std::smatch> is_inspect_request(const std::string& code, const std::regex& re);

XEUS_CPP_API void inspect(const std::string& code, nl::json& kernel_res);
std::string inspect(const std::string& code);
nl::json build_inspect_data(const std::string& inspect_result);

class XEUS_CPP_API xintrospection : public xpreamble
{
Expand Down
19 changes: 13 additions & 6 deletions src/xinterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* The full license is in the file LICENSE, distributed with this software. *
************************************************************************************/

#include <regex>

#include "xeus/xhelper.hpp"
#include "xeus/xsystem.hpp"

Expand Down Expand Up @@ -264,15 +266,20 @@ __get_cxx_version ()

nl::json interpreter::inspect_request_impl(const std::string& code, int cursor_pos, int /*detail_level*/)
{
nl::json kernel_res;
std::string exp = R"(\w*(?:\:{2}|\<.*\>|\(.*\)|\[.*\])?)";
std::regex re(R"((\w*(?:\:{2}|\<.*\>|\(.*\)|\[.*\])?)(\.?)*$)");
auto inspect_request = is_inspect_request(code.substr(0, cursor_pos), re);
if (inspect_request.first)

std::smatch inspect_request;
std::string sub_code = code.substr(0, cursor_pos);
if (std::regex_search(sub_code, inspect_request, re))
{
inspect(inspect_request.second[0], kernel_res);
std::string result = inspect(inspect_request[0]);
if (result.empty())
{
return xeus::create_inspect_reply(false);
}
return xeus::create_inspect_reply(true, build_inspect_data(result));
}
return kernel_res;
return xeus::create_inspect_reply(false);
}

nl::json interpreter::is_complete_request_impl(const std::string& code)
Expand Down
23 changes: 3 additions & 20 deletions test/test_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,6 @@ TEST_SUITE("execute_request")
nl::json result = future.get();
REQUIRE(result["payload"][0]["data"]["text/plain"] == inspect_result);
REQUIRE(result["user_expressions"] == nl::json::object());
REQUIRE(result["found"] == true);
REQUIRE(result["status"] == "ok");
}

Expand Down Expand Up @@ -246,7 +245,6 @@ TEST_SUITE("execute_request")
nl::json result = future.get();
REQUIRE(result["payload"][0]["data"]["text/plain"] == inspect_result);
REQUIRE(result["user_expressions"] == nl::json::object());
REQUIRE(result["found"] == true);
REQUIRE(result["status"] == "ok");
}

Expand Down Expand Up @@ -286,13 +284,7 @@ TEST_SUITE("execute_request")

TEST_SUITE("inspect_request")
{
#if defined(__EMSCRIPTEN__)
TEST_CASE("good_status"
* doctest::should_fail(true)
* doctest::description("TODO: Currently fails for the Emscripten build"))
#else
TEST_CASE("good_status")
#endif
TEST_CASE("found_status")
{
std::vector<const char*> Args = {/*"-v", "resource-dir", "....."*/};
xcpp::interpreter interpreter((int)Args.size(), Args.data());
Expand All @@ -306,12 +298,11 @@ TEST_SUITE("inspect_request")
/*detail_level=*/0
);

REQUIRE(result["user_expressions"] == nl::json::object());
REQUIRE(result["found"] == true);
REQUIRE(result["status"] == "ok");
}

TEST_CASE("bad_status")
TEST_CASE("not_found_status")
{
std::vector<const char*> Args = {/*"-v", "resource-dir", "....."*/};
xcpp::interpreter interpreter((int)Args.size(), Args.data());
Expand All @@ -326,7 +317,7 @@ TEST_SUITE("inspect_request")
);

REQUIRE(result["found"] == false);
REQUIRE(result["status"] == "error");
REQUIRE(result["status"] == "ok");
}
}

Expand Down Expand Up @@ -953,14 +944,6 @@ TEST_SUITE("xinspect"){
cmp.child_value = "nonexistentMethod";
REQUIRE(cmp(node) == false);
}

TEST_CASE("is_inspect_request"){
std::string code = "vector";
std::regex re_expression(R"(non_matching_pattern)");
std::pair<bool, std::smatch> result = xcpp::is_inspect_request(code, re_expression);
REQUIRE(result.first == false);
}

}

#if !defined(__EMSCRIPTEN__)
Expand Down
Loading