Skip to content

Commit c11ced4

Browse files
author
Kasper Peeters
committed
Unify handling of multi-line input between cadabra2-gtk and cadabra2-cli by using the CdbPython.cc code also for the latter. Cleanup.
1 parent 89d3512 commit c11ced4

File tree

2 files changed

+43
-48
lines changed

2 files changed

+43
-48
lines changed

core/cadabra2-cli.cc

Lines changed: 42 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Shell::Shell(Flags flags)
5353
colour_info = no_colour ? "" : "\033[36m";
5454
colour_success = no_colour ? "" : "\033[32m";
5555
colour_reset = no_colour ? "" : "\033[0m";
56+
colour_bold = no_colour ? "" : "\033[1m";
5657

5758
if (!(flags & Flags::NoReadline)) {
5859
set_histfile();
@@ -94,8 +95,9 @@ void Shell::interact()
9495

9596
// Print startup info banner
9697
if (!(flags & Flags::NoBanner)) {
97-
write_stdout("Cadabra " CADABRA_VERSION_FULL " (build " CADABRA_VERSION_BUILD
98-
" dated " CADABRA_VERSION_DATE ")");
98+
write_stdout(colour_bold + std::string("Cadabra ") + std::string(CADABRA_VERSION_FULL) + colour_reset
99+
+ " (build " + std::string(CADABRA_VERSION_BUILD) +
100+
" dated " + std::string(CADABRA_VERSION_DATE) + ")");
99101
write_stdout("Copyright (C) " COPYRIGHT_YEARS " Kasper Peeters <[email protected]>");
100102
write_stdout("Info at https://cadabra.science/");
101103
write_stdout("Available under the terms of the GNU GPL v3.");
@@ -126,7 +128,10 @@ void Shell::interact()
126128
using namespace std::placeholders;
127129
if (!(flags & Flags::NoReadline))
128130
SetCompletionCallback(std::bind(&Shell::set_completion_callback, this, _1, _2));
131+
132+
129133
if (collect.empty()) {
134+
curline.clear();
130135
if (get_input(get_ps1(), curline)) {
131136
PyErr_SetNone(PyExc_KeyboardInterrupt);
132137
handle_error();
@@ -371,66 +376,53 @@ void Shell::process_ps1(const std::string& line)
371376
{
372377
// Convert cadabra to python
373378
bool display = !(flags & Flags::IgnoreSemicolons);
379+
380+
// In contrast to notebook cell processing, what we do here is
381+
// simpler. We just convert this first line. If it is complete
382+
// python code, we can execute it. If not, we just take this
383+
// line together with future lines until an empty line is
384+
// input, and then we convert & execute the whole block.
385+
// So we don't really do anything with ConvertData nor with
386+
// the result of `convert_line`.
374387
cadabra::ConvertData cv;
375388
std::pair<std::string, std::string> res = cadabra::convert_line(line, cv, display);
376-
// FIXME: we need to process res.first
377389
const std::string& output = res.second;
378390
if (output == "::empty") {
379-
// Cadabra continuation line, add to collect
380-
collect += line + "\n";
391+
// Cadabra continuation line, add the unprocessed line to collect
392+
collect = line + "\n";
381393
return;
382394
}
383395

384-
try {
385-
py::object res = evaluate(output);
386-
if (!res.is_none()) {
387-
write_stdout(str(res));
388-
globals["_"] = res;
389-
}
390-
}
391-
catch (py::error_already_set& eval_err) {
392-
if (eval_err.matches(PyExc_SyntaxError)) {
393-
// Might have valid Python, but needs to be executed not evaluated.
394-
try {
395-
execute(output);
396-
}
397-
catch (py::error_already_set& exec_err) {
398-
bool need_more = false;
399-
// Check if we need more input. The approach taken is from the Python codeop library:
400-
// https://github.com/python/cpython/blob/8c93a63c03ddc789040a6ad50a18af1df7764884/Lib/codeop.py#L19
401-
// First compile with a newline appended. If it compiles, then we need more input.
402-
std::string output_with_nl = output + "\n";
403-
auto co_with_nl = py::reinterpret_steal<py::object>(
404-
Py_CompileString(output_with_nl.c_str(), "<internal>", Py_file_input));
405-
if (co_with_nl) {
406-
need_more = true;
407-
}
408-
else {
409-
// Recompile with two newlines appended. Compare the error generated by the two compilations:
410-
// if they are different then we need more, otherwise it is a genuine error
411-
py::error_already_set err1; // Save&clear error from co_with_nl
412-
std::string output_with_nlnl = output + "\n\n";
413-
auto co_with_nlnl = py::reinterpret_steal<py::object>(
414-
Py_CompileString(output_with_nlnl.c_str(), "<internal>", Py_file_input));
415-
py::error_already_set err2; // Save&clear error from co_with_nlnl
416-
need_more = (repr(err1.type()) != repr(err2.type()) || repr(err1.value()) != repr(err2.value()));
417-
}
418-
419-
if (need_more)
420-
collect += "\n";
421-
else
422-
handle_error(exec_err);
396+
std::string error;
397+
int status = cadabra::is_python_code_complete(output, error);
398+
switch(status) {
399+
case 0:
400+
// std::cerr << "seting collect to\n|" << res.first + res.second << "|" << std::endl;
401+
collect = res.first + res.second + "\n";
402+
break;
403+
case 1: {
404+
std::string tmp = res.first + res.second;
405+
collect.clear();
406+
if(tmp.size()>0) {
407+
// std::cerr << "executing ps1\n|" << tmp << "|" << std::endl;
408+
execute(tmp);
423409
}
410+
break;
424411
}
425-
else {
426-
handle_error(eval_err);
427-
}
412+
case -1:
413+
collect.clear();
414+
throw ParseException(error);
415+
case -2:
416+
collect.clear();
417+
throw ParseException(error);
418+
default:
419+
throw InternalError("Code completion check returned invalid response.");
428420
}
429421
}
430422

431423
void Shell::process_ps2(const std::string& line)
432424
{
433-
if (!line.empty()) {
425+
if(!line.empty()) {
434426
collect += line + "\n";
435427
return;
436428
}
@@ -439,6 +431,7 @@ void Shell::process_ps2(const std::string& line)
439431
std::string error;
440432
std::string code = cadabra::cdb2python_string(collect, display, error);
441433
collect.clear();
434+
// std::cerr << "executing ps2\n|" << code << "|" << std::endl;
442435
execute(code);
443436
}
444437

@@ -480,6 +473,7 @@ std::string Shell::get_ps2()
480473

481474
void Shell::handle_error()
482475
{
476+
collect.clear();
483477
if (PyErr_Occurred()) {
484478
py::error_already_set err;
485479
handle_error(err);

core/cadabra2-cli.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class Shell : public pybind11::scoped_interpreter {
7070
const char* colour_info;
7171
const char* colour_success;
7272
const char* colour_reset;
73+
const char* colour_bold;
7374
Flags flags;
7475
};
7576

0 commit comments

Comments
 (0)