-
Notifications
You must be signed in to change notification settings - Fork 55
Support more than one line in the Python Console & Refactor #665
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| connect( | ||
| m_history_edit->document(), | ||
| &QTextDocument::contentsChanged, | ||
| this, | ||
| [this]() | ||
| { | ||
| const int newHeight = calcHeightToFitContents(m_history_edit); | ||
| m_history_edit->setMinimumHeight(newHeight); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set minHeight to history editor so that it would fill all free space in scrollArea if there's some
| connect( | ||
| m_command_edit->document(), | ||
| &QTextDocument::contentsChanged, | ||
| this, | ||
| [this, commandEditMinHeight]() | ||
| { | ||
| const int newHeight = std::max(calcHeightToFitContents(m_command_edit), commandEditMinHeight); | ||
| m_command_edit->setFixedHeight(newHeight); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set fixedHeight to commandEdit so that it is big enough to contain all the text, but doesn't stretch if scrollArea has free space
| std::string const command = m_command_edit->toPlainText().trimmed().toStdString(); | ||
|
|
||
| if (command.length() == 0) | ||
| { | ||
| return; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added trimmed(), so that user wouldn't execute empty command
| printCommandStdout(m_python_redirect.stdout_string()); | ||
| printCommandStderr(m_python_redirect.stderr_string()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
printCommandStderr and printCommandStdout were duplicates of writeToHistory so I removed them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I think we should keep them into two functions or a single function with different arguments to distinguish stdout and stderr, which is helpful when we give different color for them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. Sending the log through a unified API is good. But it's bad to combine stdout and stderr.
It's hard to decide, so we should not change it right now. Please keep the old code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I can bring these functions back. But how about I mark output of stderr with red color?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I've tried to mark stderr with red color and here's what I got:

I have added stdout: and stderr: strings to distinguish outputs of printCommandStdout and printCommandStderr.
As you can see when an exception occurs both stdout and stderr have something to output.
Should we mark both of them with red color or only stderr? Or should we just postpone this and keep the old behavior?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I think I will keep the old behavior for now
| QTextCursor cursor = m_history_edit->textCursor(); | ||
| cursor.movePosition(QTextCursor::End); | ||
| m_history_edit->setTextCursor(cursor); | ||
| m_history_edit->insertPlainText(QString::fromStdString(data)); | ||
| cursor.movePosition(QTextCursor::End); | ||
| m_history_edit->setTextCursor(cursor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we just need to set cursor before we write to the editor since it's read-only editor
| setCommand(QString::fromStdString(command_to_show)); | ||
| } | ||
|
|
||
| void RPythonConsoleDockWidget::navigateCommand(int offset) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function contained a bug, when not yet executed command couldn't be restored after navigating to past commands and back to the not yet executed command. So I have fixed the bug and simplified the function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. I didn't notice it behaved incorrectly that way.
| const auto formatted_command = std::format("[{}] {}\n\n", m_last_command_serial, command); | ||
| writeToHistory(formatted_command); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is an equivalent replacement of printCommandHistory() function
| const bool is_first_line_focused = cursor.blockNumber() == 0; | ||
| const bool is_last_line_focused = cursor.blockNumber() == document()->blockCount() - 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need this so that navigation between lines of a past command is possible
tigercosmos
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's recommended to write something in the PR description. Attaching some screenshots is also helpful as it's a GUI change.
| execute(); | ||
| if (event->modifiers() & Qt::ShiftModifier) | ||
| { | ||
| this->insertPlainText("\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: what happens on Windows?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. @Tucchhaa , if you don't have time/environment to test for the behaviors on Windows, make a guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have Windows environment. But I'm pretty sure it behaves the same as on MacOS, since Qt is not OS specific.
I asked chatgpt about it and told the same thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to know that the code is based a guess. Line ending on Windows, Mac, and Linux are \r\n (CR LF), \r (CR), and \n (LF). That is a concern. But I agree that if \n works on Mac. We can have the fingers cross before some nice people point out issues on Windows.
Let's avoid using AI tools as a reference. They do not have credibility. (Using them and studying yourself is fine.)
| } | ||
| } | ||
| else if (Qt::Key_Up == event->key()) | ||
| else if (Qt::Key_Up == event->key() && is_first_line_focused) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you describe what is the behaviour difference before and after and is the difference expected?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A quick description suffices.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is needed to make navigation in multiline command more convenient in case when there are previous commands.
Suppose we don't have is_first_line_focused, here's what will happen in a simple user case:
-
User executes any command, e.g.:
a = 9 -
Then user writes this multiline command, but he doesn't executes it yet:
b = 10
c = 11
print(a + b + c)-
Since user just typed it, the focus is on the last line. Then user realizes that the value of
cis incorrect and he wants to change it to12 -
So user presses arrow up to focus the second line
c = 11, but instead of moving focus up,navigatefunction will be called which will change the value of command editor to previous command, which isa = 9
With is_first_line_focused this behavior is prevented. And so pilot's command editor behaves just like any other terminal. The similar reason why we need is_last_line_focused
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you. Very clear elaboration.
| printCommandStdout(m_python_redirect.stdout_string()); | ||
| printCommandStderr(m_python_redirect.stderr_string()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I think we should keep them into two functions or a single function with different arguments to distinguish stdout and stderr, which is helpful when we give different color for them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work. Some comments:
- Add summary in the opening PR comment block. (Just edit it.) Include some screenshots of the new UI. It would be good to also include screenshots of the old UI to make a comparison.
- Keep the old
printCommandStdoutandprintCommandStderrbefore we have a better idea for how to handle the text logging.
After the discussion converges and the code can be finalized, commits should be squashed because the overall change is straight-forward. Formatting should not use distinct commits.
Refactoring may use distinct commits, although for this PR, it does not matter. Do what you like.
But before the PR is close to merging, feel free to stack commits.
| execute(); | ||
| if (event->modifiers() & Qt::ShiftModifier) | ||
| { | ||
| this->insertPlainText("\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. @Tucchhaa , if you don't have time/environment to test for the behaviors on Windows, make a guess.
| } | ||
| } | ||
| else if (Qt::Key_Up == event->key()) | ||
| else if (Qt::Key_Up == event->key() && is_first_line_focused) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A quick description suffices.
| { | ||
| setWidget(new QWidget); | ||
| widget()->setLayout(new QVBoxLayout); | ||
| m_scroll_area->setWidgetResizable(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the use of a scroll area. @Tucchhaa do you think it stands a chance to be extended to be a rich-text editor (in the future)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depends on what you consider a rich-text editor :)
For me, I think we would need to add the following features:
-
Syntax highlighting for command editor and history editor. it can be implemented using
QSyntaxHighlighterand it seems not too difficult to implement. -
Suggestion popup-list in command editor that will be shown when user types a variable or function name. This can be challenging to implement but still possible in my opinion.
With these features pilot's console will be very similar to browser's console and pretty convenient to use.
However we can go further and implement jupyter notebook-like editor. Since QTextEdit supports HTML (tables, hyperlinks even images can be inserted into the editor), it seems that this feature is feasible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making it like a terminal (emulator) or jupyter notebook like editor will be fantastic. We can talk more about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I could create an issue with the action plan of step-by-step development of rich-text editor?
Like :
Step 1: implement syntax highlighting in command editor and history editor
Step 2: implement suggestion popup-list
Step 3: Research possibility of jupyter-notebook like implementation.
And each step with some implementation details (like usage of QSyntaxHighlighter)
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I could create an issue with the action plan of step-by-step development of rich-text editor?
Like :
Step 1: implement syntax highlighting in command editor and history editor
Step 2: implement suggestion popup-list
Step 3: Research possibility of jupyter-notebook like implementation.And each step with some implementation details (like usage of
QSyntaxHighlighter)What do you think?
It will be fantastic. Please go ahead.
A discussion topic (in https://github.com/solvcon/modmesh/discussions) may be more suitable than an issue at the moment. It's up to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I will do that in a week or so
| printCommandStdout(m_python_redirect.stdout_string()); | ||
| printCommandStderr(m_python_redirect.stderr_string()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. Sending the log through a unified API is good. But it's bad to combine stdout and stderr.
It's hard to decide, so we should not change it right now. Please keep the old code.
| setCommand(QString::fromStdString(command_to_show)); | ||
| } | ||
|
|
||
| void RPythonConsoleDockWidget::navigateCommand(int offset) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. I didn't notice it behaved incorrectly that way.
yungyuc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leave a global comment to request for a next review. No need to press the ready for review button. We do not pay attention to it.
| } | ||
| } | ||
| else if (Qt::Key_Up == event->key()) | ||
| else if (Qt::Key_Up == event->key() && is_first_line_focused) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you. Very clear elaboration.
| { | ||
| setWidget(new QWidget); | ||
| widget()->setLayout(new QVBoxLayout); | ||
| m_scroll_area->setWidgetResizable(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making it like a terminal (emulator) or jupyter notebook like editor will be fantastic. We can talk more about it.
| execute(); | ||
| if (event->modifiers() & Qt::ShiftModifier) | ||
| { | ||
| this->insertPlainText("\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to know that the code is based a guess. Line ending on Windows, Mac, and Linux are \r\n (CR LF), \r (CR), and \n (LF). That is a concern. But I agree that if \n works on Mac. We can have the fingers cross before some nice people point out issues on Windows.
Let's avoid using AI tools as a reference. They do not have credibility. (Using them and studying yourself is fine.)
|
@yungyuc @tigercosmos I have brought back Should I squash and force push commits to this PR? Or will the PR be squashed and merged? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@yungyuc @tigercosmos I have brought back
printCommandStdoutandprintCommandStderr. Can you review again, please?
Thank you. This is a good summary. Requesting for a next review with a good summary like this benefits both the contributor and the reviewers. It helps the contributor to pro-actively pre-review before requesting, and the reviewers to know what to read.
All PRs should be carried out in this way. I did not document it in this repository but I should.
Should I squash and force push commits to this PR? Or will the PR be squashed and merged?
Yes, please squash and make a new commit or commits, because it's close to be merged. For a small PR like this (around 100 LoC), using one commit suffices, but might not hurt to use 2 or 3.
Do notify with a global comment after it's squashed and ready for the next review.
e91666d to
46ae19b
Compare
yungyuc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have rebased my PR
CI is clean. Good to merge.
| { | ||
| setWidget(new QWidget); | ||
| widget()->setLayout(new QVBoxLayout); | ||
| m_scroll_area->setWidgetResizable(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I could create an issue with the action plan of step-by-step development of rich-text editor?
Like :
Step 1: implement syntax highlighting in command editor and history editor
Step 2: implement suggestion popup-list
Step 3: Research possibility of jupyter-notebook like implementation.And each step with some implementation details (like usage of
QSyntaxHighlighter)What do you think?
It will be fantastic. Please go ahead.
A discussion topic (in https://github.com/solvcon/modmesh/discussions) may be more suitable than an issue at the moment. It's up to you.
|
@Tucchhaa I forgot to ask you to update the commit with a summary of the change, but it's already merged. Please add good summary to each of your future commits. Do not use conventional/semantic commit messages, which are not suitable for the computing code. |
This PR changes to the layout of Python Console in pilot.
How it looked before:

How it looks now:

Multiline commands support:
