implement automatic completion popup and reformat on return

This commit is contained in:
Axel Kohlmeyer
2023-09-01 07:27:52 -04:00
parent 65866156dd
commit b2ba1bbe70
5 changed files with 75 additions and 5 deletions

View File

@ -3,6 +3,9 @@ LAMMPS-GUI TODO list:
# Short term goals # Short term goals
- add "syntax check" with enabled "-skiprun" flag - add "syntax check" with enabled "-skiprun" flag
- implement "static" completion for fix/compute/styles/region etc...
- implement "dynamic" completion for variable names, group names, molecule names, compute/dump/fix/region/group IDs
- implement indenting regions for (nested) loops?
# Long term ideas # Long term ideas
- rewrite entire application to build the App and its layout manually - rewrite entire application to build the App and its layout manually

View File

@ -290,9 +290,10 @@ void CodeEditor::setCommandList(const QStringList &words)
void CodeEditor::keyPressEvent(QKeyEvent *event) void CodeEditor::keyPressEvent(QKeyEvent *event)
{ {
const auto key = event->key();
if (command_completer && command_completer->popup()->isVisible()) { if (command_completer && command_completer->popup()->isVisible()) {
// The following keys are forwarded by the completer to the widget // The following keys are forwarded by the completer to the widget
switch (event->key()) { switch (key) {
case Qt::Key_Enter: case Qt::Key_Enter:
case Qt::Key_Return: case Qt::Key_Return:
case Qt::Key_Escape: case Qt::Key_Escape:
@ -304,15 +305,47 @@ void CodeEditor::keyPressEvent(QKeyEvent *event)
break; break;
} }
} }
if (event->key() == Qt::Key_Tab) {
// reformat current line and consume key event
if (key == Qt::Key_Tab) {
reformatCurrentLine(); reformatCurrentLine();
return; return;
} }
if (event->key() == Qt::Key_Backtab) {
// run command completion and consume key event
if (key == Qt::Key_Backtab) {
runCompletion(); runCompletion();
return; return;
} }
// automatically reformat when hitting the return or enter key
if (reformat_on_return && (key == Qt::Key_Return) || (key == Qt::Key_Enter)) {
reformatCurrentLine();
}
// pass key event on to parent class
QPlainTextEdit::keyPressEvent(event); QPlainTextEdit::keyPressEvent(event);
// pop up completion automatically after 3 characters
if (automatic_completion) {
auto cursor = textCursor();
auto line = cursor.block().text().trimmed();
if (!line.isEmpty()) {
auto words = split_line(line.toStdString());
cursor.select(QTextCursor::WordUnderCursor);
auto word = cursor.selectedText().trimmed();
if (command_completer) {
if (words[0] == word.toStdString()) {
if (word.length() > 2)
runCompletion();
else if (command_completer->popup()->isVisible())
command_completer->popup()->hide();
} else {
if (command_completer->popup()->isVisible()) command_completer->popup()->hide();
}
}
}
}
} }
void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */) void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
@ -475,6 +508,11 @@ void CodeEditor::runCompletion()
command_completer->setCompletionPrefix(words[0].c_str()); command_completer->setCompletionPrefix(words[0].c_str());
auto popup = command_completer->popup(); auto popup = command_completer->popup();
// if the command is already a complete command, remove existing popup
if (words[0] == command_completer->currentCompletion().toStdString()) {
if (popup->isVisible()) popup->hide();
return;
}
QRect cr = cursorRect(); QRect cr = cursorRect();
cr.setWidth(popup->sizeHintForColumn(0) + cr.setWidth(popup->sizeHintForColumn(0) +
popup->verticalScrollBar()->sizeHint().width()); popup->verticalScrollBar()->sizeHint().width());

View File

@ -33,6 +33,8 @@ public:
void setFont(const QFont &newfont); void setFont(const QFont &newfont);
void setCursor(int block); void setCursor(int block);
void setHighlight(int block, bool error); void setHighlight(int block, bool error);
void setReformatOnReturn(bool flag) { reformat_on_return = flag; }
void setAutoComplete(bool flag) { automatic_completion = flag; }
QString reformatLine(const QString &line); QString reformatLine(const QString &line);
void setCommandList(const QStringList &words); void setCommandList(const QStringList &words);
@ -61,6 +63,8 @@ private:
QShortcut *help_action; QShortcut *help_action;
QCompleter *command_completer; QCompleter *command_completer;
int highlight; int highlight;
bool reformat_on_return;
bool automatic_completion;
QMap<QString, QString> cmd_map; QMap<QString, QString> cmd_map;
QMap<QString, QString> fix_map; QMap<QString, QString> fix_map;

View File

@ -317,6 +317,10 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
} }
command_list.sort(); command_list.sort();
ui->textEdit->setCommandList(command_list); ui->textEdit->setCommandList(command_list);
settings.beginGroup("reformat");
ui->textEdit->setReformatOnReturn(settings.value("return", true).toBool());
ui->textEdit->setAutoComplete(settings.value("automatic", true).toBool());
settings.endGroup();
} }
LammpsGui::~LammpsGui() LammpsGui::~LammpsGui()
@ -1256,6 +1260,10 @@ void LammpsGui::preferences()
lammpsstatus->hide(); lammpsstatus->hide();
} }
if (imagewindow) imagewindow->createImage(); if (imagewindow) imagewindow->createImage();
settings.beginGroup("reformat");
ui->textEdit->setReformatOnReturn(settings.value("return", true).toBool());
ui->textEdit->setAutoComplete(settings.value("automatic", true).toBool());
settings.endGroup();
} }
} }

View File

@ -178,7 +178,7 @@ void Preferences::accept()
execl(path, arg0, (char *)NULL); execl(path, arg0, (char *)NULL);
} }
// reformattting settings // reformatting settings
settings->beginGroup("reformat"); settings->beginGroup("reformat");
auto spin = tabWidget->findChild<QSpinBox *>("cmdval"); auto spin = tabWidget->findChild<QSpinBox *>("cmdval");
@ -189,6 +189,10 @@ void Preferences::accept()
if (spin) settings->setValue("id", spin->value()); if (spin) settings->setValue("id", spin->value());
spin = tabWidget->findChild<QSpinBox *>("nameval"); spin = tabWidget->findChild<QSpinBox *>("nameval");
if (spin) settings->setValue("name", spin->value()); if (spin) settings->setValue("name", spin->value());
box = tabWidget->findChild<QCheckBox *>("retval");
if (box) settings->setValue("return", box->isChecked());
box = tabWidget->findChild<QCheckBox *>("autoval");
if (box) settings->setValue("automatic", box->isChecked());
settings->endGroup(); settings->endGroup();
QDialog::accept(); QDialog::accept();
@ -508,10 +512,14 @@ EditorTab::EditorTab(QSettings *_settings, QWidget *parent) : QWidget(parent), s
auto *typelbl = new QLabel("Type width:"); auto *typelbl = new QLabel("Type width:");
auto *idlbl = new QLabel("ID width:"); auto *idlbl = new QLabel("ID width:");
auto *namelbl = new QLabel("Name width:"); auto *namelbl = new QLabel("Name width:");
auto *retlbl = new QLabel("Reformat with 'Return':");
auto *autolbl = new QLabel("Automatic completion:");
auto *cmdval = new QSpinBox; auto *cmdval = new QSpinBox;
auto *typeval = new QSpinBox; auto *typeval = new QSpinBox;
auto *idval = new QSpinBox; auto *idval = new QSpinBox;
auto *nameval = new QSpinBox; auto *nameval = new QSpinBox;
auto *retval = new QCheckBox;
auto *autoval = new QCheckBox;
cmdval->setRange(1, 32); cmdval->setRange(1, 32);
cmdval->setValue(settings->value("command", "16").toInt()); cmdval->setValue(settings->value("command", "16").toInt());
cmdval->setObjectName("cmdval"); cmdval->setObjectName("cmdval");
@ -524,6 +532,11 @@ EditorTab::EditorTab(QSettings *_settings, QWidget *parent) : QWidget(parent), s
nameval->setRange(1, 32); nameval->setRange(1, 32);
nameval->setValue(settings->value("name", "8").toInt()); nameval->setValue(settings->value("name", "8").toInt());
nameval->setObjectName("nameval"); nameval->setObjectName("nameval");
retval->setCheckState(settings->value("return", true).toBool() ? Qt::Checked : Qt::Unchecked);
retval->setObjectName("retval");
autoval->setCheckState(settings->value("automatic", true).toBool() ? Qt::Checked
: Qt::Unchecked);
autoval->setObjectName("autoval");
settings->endGroup(); settings->endGroup();
int i = 0; int i = 0;
@ -536,6 +549,10 @@ EditorTab::EditorTab(QSettings *_settings, QWidget *parent) : QWidget(parent), s
grid->addWidget(idval, i++, 1, Qt::AlignTop); grid->addWidget(idval, i++, 1, Qt::AlignTop);
grid->addWidget(namelbl, i, 0, Qt::AlignTop); grid->addWidget(namelbl, i, 0, Qt::AlignTop);
grid->addWidget(nameval, i++, 1, Qt::AlignTop); grid->addWidget(nameval, i++, 1, Qt::AlignTop);
grid->addWidget(retlbl, i, 0, Qt::AlignTop);
grid->addWidget(retval, i++, 1, Qt::AlignVCenter);
grid->addWidget(autolbl, i, 0, Qt::AlignTop);
grid->addWidget(autoval, i++, 1, Qt::AlignVCenter);
grid->addItem(new QSpacerItem(100, 100, QSizePolicy::Minimum, QSizePolicy::Expanding), i, 0); grid->addItem(new QSpacerItem(100, 100, QSizePolicy::Minimum, QSizePolicy::Expanding), i, 0);
grid->addItem(new QSpacerItem(100, 100, QSizePolicy::Minimum, QSizePolicy::Expanding), i, 1); grid->addItem(new QSpacerItem(100, 100, QSizePolicy::Minimum, QSizePolicy::Expanding), i, 1);