diff --git a/tools/lammps-gui/CMakeLists.txt b/tools/lammps-gui/CMakeLists.txt index 4195c21406..37fe455d39 100644 --- a/tools/lammps-gui/CMakeLists.txt +++ b/tools/lammps-gui/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(lammps-gui VERSION 1.4.1 LANGUAGES CXX) +project(lammps-gui VERSION 1.5.0 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) diff --git a/tools/lammps-gui/codeeditor.cpp b/tools/lammps-gui/codeeditor.cpp index b438e51319..823233b7b2 100644 --- a/tools/lammps-gui/codeeditor.cpp +++ b/tools/lammps-gui/codeeditor.cpp @@ -28,6 +28,92 @@ #include #include +#include +#include + +// Convert string into words on whitespace while handling single and double +// quotes. Adapted from LAMMPS_NS::utils::split_words() to preserve quotes. + +static std::vector split_line(const std::string &text) +{ + std::vector list; + const char *buf = text.c_str(); + std::size_t beg = 0; + std::size_t len = 0; + std::size_t add = 0; + char c = *buf; + + while (c) { // leading whitespace + if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f') { + c = *++buf; + ++beg; + continue; + }; + len = 0; + + // handle escaped/quoted text. + quoted: + + if (c == '\'') { // handle single quote + add = 0; + len = 1; + c = *++buf; + while (((c != '\'') && (c != '\0')) || ((c == '\\') && (buf[1] == '\''))) { + if ((c == '\\') && (buf[1] == '\'')) { + ++buf; + ++len; + } + c = *++buf; + ++len; + } + ++len; + c = *++buf; + + // handle triple double quotation marks + } else if ((c == '"') && (buf[1] == '"') && (buf[2] == '"') && (buf[3] != '"')) { + len = 3; + add = 1; + buf += 3; + c = *buf; + + } else if (c == '"') { // handle double quote + add = 0; + len = 1; + c = *++buf; + while (((c != '"') && (c != '\0')) || ((c == '\\') && (buf[1] == '"'))) { + if ((c == '\\') && (buf[1] == '"')) { + ++buf; + ++len; + } + c = *++buf; + ++len; + } + ++len; + c = *++buf; + } + + while (true) { // unquoted + if ((c == '\'') || (c == '"')) goto quoted; + // skip escaped quote + if ((c == '\\') && ((buf[1] == '\'') || (buf[1] == '"'))) { + ++buf; + ++len; + c = *++buf; + ++len; + } + if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n') || (c == '\f') || + (c == '\0')) { + list.push_back(text.substr(beg, len)); + beg += len + add; + break; + } + c = *++buf; + ++len; + } + } + return list; +} + CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent), highlight(NO_HIGHLIGHT) { help_action = new QShortcut(QKeySequence::fromString("Ctrl+?"), parent); @@ -120,6 +206,57 @@ void CodeEditor::setHighlight(int block, bool error) repaint(); } + +// reformat line + +QString CodeEditor::reformatLine(const QString &line) +{ + auto words = split_line(line.toStdString()); + QString newtext; + + if (words.size()) { + // commented line. do nothing + if (words[0][0] == '#') return line; + + // append LAMMPS command padded to 16 chars to the next work + newtext += words[0].c_str(); + if (words.size() > 1) + for (int i = 0; i < (15 - words[0].size()); ++i) + newtext += ' '; + + // append remaining words with just a single blank added. + for (int i = 1; i < words.size(); ++i) { + newtext += ' '; + newtext += words[i].c_str(); + } + } + return newtext; +} + +void CodeEditor::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Tab) { + auto cursor = textCursor(); + auto text = cursor.block().text(); + auto newtext = reformatLine(text); + + // perform edit but only if text has changed + if (QString::compare(text, newtext)) { + cursor.beginEditBlock(); + cursor.movePosition(QTextCursor::StartOfLine); + cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor, 1); + cursor.insertText(newtext); + cursor.endEditBlock(); + } + return; + } + if (event->key() == Qt::Key_Backtab) { + fprintf(stderr, "Shift + Tab key hit\n"); + return; + } + QPlainTextEdit::keyPressEvent(event); +} + void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */) { setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); diff --git a/tools/lammps-gui/codeeditor.h b/tools/lammps-gui/codeeditor.h index 0b372f1bfb..fb32de17f5 100644 --- a/tools/lammps-gui/codeeditor.h +++ b/tools/lammps-gui/codeeditor.h @@ -31,6 +31,7 @@ public: void setFont(const QFont &newfont); void setCursor(int block); void setHighlight(int block, bool error); + QString reformatLine(const QString &line); static constexpr int NO_HIGHLIGHT = 1 << 30; @@ -40,6 +41,7 @@ protected: bool canInsertFromMimeData(const QMimeData *source) const override; void dropEvent(QDropEvent *event) override; void contextMenuEvent(QContextMenuEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; private slots: void updateLineNumberAreaWidth(int newBlockCount);