diff --git a/src/xinterpreter.cpp b/src/xinterpreter.cpp index b1913461..0b02aaa2 100644 --- a/src/xinterpreter.cpp +++ b/src/xinterpreter.cpp @@ -298,7 +298,7 @@ namespace xcpp void interpreter::execute_request_impl( send_reply_callback cb, - int /*execution_count*/, + int execution_count, const std::string& code, xeus::execute_request_config config, nl::json /*user_expressions*/ @@ -330,12 +330,13 @@ namespace xcpp SilentStreamRedirectRAII silent_guard(config.silent); std::string err; + Cpp::Box output; // Attempt normal evaluation try { StreamRedirectRAII R(err); - compilation_result = Cpp::Process(code.c_str()); + compilation_result = Cpp::Evaluate(code.c_str(), output); } catch (std::exception& e) { @@ -384,15 +385,24 @@ namespace xcpp } else { - /* - // Publish a mime bundle for the last return value if - // the semicolon was omitted. - if (!config.silent && output.hasValue() && trim(code).back() != ';') - { - nl::json pub_data = mime_repr(output); - publish_execution_result(execution_counter, std::move(pub_data), nl::json::object()); - } - */ + // Match an interactive C++ shell: publish the last value when the + // input did not suppress display with a trailing semicolon. + const std::size_t last = code.find_last_not_of(" \t\r\n"); + if (!config.silent + && output.getKind() != Cpp::Box::K_Unspecified + && output.getKind() != Cpp::Box::K_Void + && last != std::string::npos + && code[last] != ';') + { + nl::json pub_data = { + {"text/plain", Cpp::GetValueAsString(output)} + }; + publish_execution_result( + execution_count, + std::move(pub_data), + nl::json::object() + ); + } // Compose execute_reply message. kernel_res = xeus::create_successful_reply(); } diff --git a/test/test_interpreter.cpp b/test/test_interpreter.cpp index a1a11f57..d6e4ae5f 100644 --- a/test/test_interpreter.cpp +++ b/test/test_interpreter.cpp @@ -68,6 +68,50 @@ class StreamRedirectRAII { TEST_SUITE("execute_request") { + TEST_CASE("publishes the last expression value") + { + std::vector args = {}; + xcpp::interpreter interpreter(static_cast(args.size()), args.data()); + + std::string published_type; + nl::json published_content; + interpreter.register_publisher( + [&published_type, &published_content]( + xeus::xrequest_context, + const std::string& message_type, + nl::json, + nl::json content, + xeus::buffer_sequence) + { + if (message_type == "execute_result") + { + published_type = message_type; + published_content = std::move(content); + } + } + ); + + xeus::execute_request_config config; + config.silent = false; + config.store_history = false; + config.allow_stdin = false; + xeus::xrequest_context context(nl::json::object(), {}); + + std::promise promise; + std::future future = promise.get_future(); + interpreter.execute_request( + std::move(context), + [&promise](nl::json result) { promise.set_value(std::move(result)); }, + "5", + config, + nl::json::object() + ); + + REQUIRE(future.get()["status"] == "ok"); + REQUIRE(published_type == "execute_result"); + REQUIRE(published_content["data"]["text/plain"] == "(int) 5"); + } + TEST_CASE("stl") { std::vector Args = { @@ -1266,4 +1310,4 @@ TEST_CASE("Silent mode restores std::cout and std::cerr buffers") REQUIRE(std::cout.rdbuf() == cout_before); REQUIRE(std::cerr.rdbuf() == cerr_before); } -#endif \ No newline at end of file +#endif