[education/rkward] /: Fix handling of carriage returns in R Console window
Thomas Friedrichsmeier
null at kde.org
Sun Dec 25 10:31:54 GMT 2022
Git commit f84482ceee07e0af0a1ebb7e04ddd42bd07b993b by Thomas Friedrichsmeier.
Committed on 25/12/2022 at 10:31.
Pushed by tfry into branch 'master'.
Fix handling of carriage returns in R Console window
CCBUG: 463346
M +2 -1 ChangeLog
M +30 -16 rkward/rkconsole.cpp
M +2 -0 rkward/rkconsole.h
https://invent.kde.org/education/rkward/commit/f84482ceee07e0af0a1ebb7e04ddd42bd07b993b
diff --git a/ChangeLog b/ChangeLog
index f9a8561a..bcf76bde 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,5 @@
--- Fixed: Crash when renaming top level object from context menu
+- Fixed: Handling of carriage returns in R Console window (used in progress bars, importantly)
+- Fixed: Crash when renaming top level object from context menu
--- Version 0.7.5 - Oct-24-2022
- Fixed: Backend failed to start when installed in a path with spaces on Windows volumes without 8.3 support
diff --git a/rkward/rkconsole.cpp b/rkward/rkconsole.cpp
index c4697a93..5f97c527 100644
--- a/rkward/rkconsole.cpp
+++ b/rkward/rkconsole.cpp
@@ -486,6 +486,7 @@ void RKConsole::submitCommand () {
skip_command_display_lines = incomplete_command.count ('\n') + 1; // incomplete command, and first line have already been shown.
doc->insertLine (doc->lines (), QString ());
+ output_cursor = doc->documentEnd();
if (!command.isEmpty ()) {
current_command = new RCommand (command, RCommand::User | RCommand::Console);
connect(current_command->notifier(), &RCommandNotifier::commandOutput, this, &RKConsole::newOutput);
@@ -533,11 +534,30 @@ void RKConsole::commandsListDown (bool context_sensitive) {
else qApp->beep ();
}
+void RKConsole::rawWriteLine(const QString& line, QChar line_end) {
+ int existing_line_length = doc->lineLength(output_cursor.line());
+ if (output_cursor.column() < existing_line_length) {
+ int overwrite_end = qMin(existing_line_length, output_cursor.column() + line.length());
+ doc->removeText(KTextEditor::Range(output_cursor, KTextEditor::Cursor(output_cursor.line(), overwrite_end)));
+ }
+ doc->insertText(output_cursor, line);
+ output_cursor.setColumn(output_cursor.column() + line.length());
+ if (line_end == '\n') {
+ output_cursor.setColumn(doc->lineLength(output_cursor.line()));
+ doc->insertText(output_cursor, "\n");
+ output_cursor.setColumn(0);
+ output_cursor.setLine(output_cursor.line() + 1);
+ } else if (line_end == '\r') {
+ output_cursor.setColumn(0);
+ }
+}
+
void RKConsole::newOutput (RCommand *command, const ROutput *output) {
RK_TRACE (APP);
int first_line = doc->lines () -1;
QString popped_line;
+ // TODO: rewrite utilizing output_cursor;
if (!command) {
// spontanteous R output, to be inserted _above_ the current command
// as a shortcut, we pop the last line, and reinsert in, later
@@ -545,25 +565,19 @@ void RKConsole::newOutput (RCommand *command, const ROutput *output) {
doc->removeLine(doc->lines() - 1);
}
- // split by and handle carriage returns
- const QString outstr = output->output;
+ // split by and handle carriage returns (important for progress bars)
+ const QString out = output->output;
+ int string_pos = -1;
int start_pos = 0;
- int end_pos = outstr.size () - 1;
- QChar c;
- for (int pos = 0; pos <= end_pos; ++pos) {
- c = output->output.at (pos);
- if (c == '\r') {
- /* NOTE: My first approach was to split the whole string by newlines, and insert each line separately. This allowed for a minor
- * optimization when hitting a carriage return (the string before the '\r' could simply be ignored, then), however it caused
- * around 10% slowdown when printing large amounts of output.
- * Thus, instead, when hitting a CR, we first insert everything before that into the document, then reset the line. */
- doc->insertText (doc->documentEnd (), outstr.mid (start_pos, pos - start_pos));
- doc->removeLine (doc->lines () - 1);
- doc->insertLine (doc->lines (), QString ());
- start_pos = pos + 1;
+ int end_pos = out.length();
+ while (++string_pos < end_pos) {
+ auto c = out.at(string_pos);
+ if (c == '\n' || c == '\r') {
+ rawWriteLine(out.mid(start_pos, string_pos - start_pos), c);
+ start_pos = string_pos+1;
}
}
- if (start_pos <= end_pos) doc->insertText (doc->documentEnd (), outstr.mid (start_pos, end_pos - start_pos + 1));
+ if (start_pos < end_pos) rawWriteLine(out.mid(start_pos, string_pos - start_pos + 1), ' ');
int end_line = doc->lines () -1;
if (output->type != ROutput::Output || (!command)) {
diff --git a/rkward/rkconsole.h b/rkward/rkconsole.h
index 1753c3e9..a3f11e49 100644
--- a/rkward/rkconsole.h
+++ b/rkward/rkconsole.h
@@ -169,6 +169,8 @@ private:
int current_command_displayed_up_to;
int skip_command_display_lines;
bool previous_chunk_was_piped;
+ KTextEditor::Cursor output_cursor;
+ void rawWriteLine(const QString &line, QChar line_end);
};
/** A part interface to RKConsole. Provides the context-help functionality
More information about the rkward-tracker
mailing list