diff --git a/tools/lammps-gui/TODO.md b/tools/lammps-gui/TODO.md index 1250ab02a1..e2ff9cb42f 100644 --- a/tools/lammps-gui/TODO.md +++ b/tools/lammps-gui/TODO.md @@ -3,6 +3,9 @@ LAMMPS-GUI TODO list: # Short term goals - 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 - rewrite entire application to build the App and its layout manually diff --git a/tools/lammps-gui/codeeditor.cpp b/tools/lammps-gui/codeeditor.cpp index a5ab758d52..ac79562e33 100644 --- a/tools/lammps-gui/codeeditor.cpp +++ b/tools/lammps-gui/codeeditor.cpp @@ -290,9 +290,10 @@ void CodeEditor::setCommandList(const QStringList &words) void CodeEditor::keyPressEvent(QKeyEvent *event) { + const auto key = event->key(); if (command_completer && command_completer->popup()->isVisible()) { // The following keys are forwarded by the completer to the widget - switch (event->key()) { + switch (key) { case Qt::Key_Enter: case Qt::Key_Return: case Qt::Key_Escape: @@ -304,15 +305,47 @@ void CodeEditor::keyPressEvent(QKeyEvent *event) break; } } - if (event->key() == Qt::Key_Tab) { + + // reformat current line and consume key event + if (key == Qt::Key_Tab) { reformatCurrentLine(); return; } - if (event->key() == Qt::Key_Backtab) { + + // run command completion and consume key event + if (key == Qt::Key_Backtab) { runCompletion(); 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); + + // 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 */) @@ -475,7 +508,12 @@ void CodeEditor::runCompletion() command_completer->setCompletionPrefix(words[0].c_str()); auto popup = command_completer->popup(); - QRect cr = cursorRect(); + // 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(); cr.setWidth(popup->sizeHintForColumn(0) + popup->verticalScrollBar()->sizeHint().width()); popup->setAlternatingRowColors(true); diff --git a/tools/lammps-gui/codeeditor.h b/tools/lammps-gui/codeeditor.h index 24b4b9a30f..bd2522de8e 100644 --- a/tools/lammps-gui/codeeditor.h +++ b/tools/lammps-gui/codeeditor.h @@ -33,6 +33,8 @@ public: void setFont(const QFont &newfont); void setCursor(int block); 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); void setCommandList(const QStringList &words); @@ -61,6 +63,8 @@ private: QShortcut *help_action; QCompleter *command_completer; int highlight; + bool reformat_on_return; + bool automatic_completion; QMap cmd_map; QMap fix_map; diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index 893252ef6d..da2898c834 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -317,6 +317,10 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) : } command_list.sort(); 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() @@ -1256,6 +1260,10 @@ void LammpsGui::preferences() lammpsstatus->hide(); } 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(); } } diff --git a/tools/lammps-gui/preferences.cpp b/tools/lammps-gui/preferences.cpp index fa584fc289..8d625ca648 100644 --- a/tools/lammps-gui/preferences.cpp +++ b/tools/lammps-gui/preferences.cpp @@ -178,7 +178,7 @@ void Preferences::accept() execl(path, arg0, (char *)NULL); } - // reformattting settings + // reformatting settings settings->beginGroup("reformat"); auto spin = tabWidget->findChild("cmdval"); @@ -189,6 +189,10 @@ void Preferences::accept() if (spin) settings->setValue("id", spin->value()); spin = tabWidget->findChild("nameval"); if (spin) settings->setValue("name", spin->value()); + box = tabWidget->findChild("retval"); + if (box) settings->setValue("return", box->isChecked()); + box = tabWidget->findChild("autoval"); + if (box) settings->setValue("automatic", box->isChecked()); settings->endGroup(); QDialog::accept(); @@ -508,10 +512,14 @@ EditorTab::EditorTab(QSettings *_settings, QWidget *parent) : QWidget(parent), s auto *typelbl = new QLabel("Type width:"); auto *idlbl = new QLabel("ID 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 *typeval = new QSpinBox; auto *idval = new QSpinBox; auto *nameval = new QSpinBox; + auto *retval = new QCheckBox; + auto *autoval = new QCheckBox; cmdval->setRange(1, 32); cmdval->setValue(settings->value("command", "16").toInt()); cmdval->setObjectName("cmdval"); @@ -524,6 +532,11 @@ EditorTab::EditorTab(QSettings *_settings, QWidget *parent) : QWidget(parent), s nameval->setRange(1, 32); nameval->setValue(settings->value("name", "8").toInt()); 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(); 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(namelbl, i, 0, 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, 1);