implement command completion popup
This commit is contained in:
@ -15,6 +15,7 @@
|
||||
#include "lammpsgui.h"
|
||||
#include "linenumberarea.h"
|
||||
|
||||
#include <QAbstractItemView>
|
||||
#include <QAction>
|
||||
#include <QDesktopServices>
|
||||
#include <QDragEnterEvent>
|
||||
@ -25,7 +26,9 @@
|
||||
#include <QMimeData>
|
||||
#include <QPainter>
|
||||
#include <QRegularExpression>
|
||||
#include <QScrollBar>
|
||||
#include <QSettings>
|
||||
#include <QStringListModel>
|
||||
#include <QTextBlock>
|
||||
#include <QUrl>
|
||||
|
||||
@ -42,8 +45,8 @@ static std::vector<std::string> split_line(const std::string &text)
|
||||
std::size_t beg = 0;
|
||||
std::size_t len = 0;
|
||||
std::size_t add = 0;
|
||||
char c = *buf;
|
||||
|
||||
char c = *buf;
|
||||
while (c) { // leading whitespace
|
||||
if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f') {
|
||||
c = *++buf;
|
||||
@ -115,7 +118,8 @@ static std::vector<std::string> split_line(const std::string &text)
|
||||
return list;
|
||||
}
|
||||
|
||||
CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent), highlight(NO_HIGHLIGHT)
|
||||
CodeEditor::CodeEditor(QWidget *parent) :
|
||||
QPlainTextEdit(parent), command_completer(nullptr), highlight(NO_HIGHLIGHT)
|
||||
{
|
||||
help_action = new QShortcut(QKeySequence::fromString("Ctrl+?"), parent);
|
||||
connect(help_action, &QShortcut::activated, this, &CodeEditor::get_help);
|
||||
@ -269,14 +273,64 @@ QString CodeEditor::reformatLine(const QString &line)
|
||||
return newtext;
|
||||
}
|
||||
|
||||
void CodeEditor::setCommandList(const QStringList &words)
|
||||
{
|
||||
delete command_completer;
|
||||
command_completer = new QCompleter(this);
|
||||
command_completer->setModel(new QStringListModel(words, command_completer));
|
||||
command_completer->setCompletionMode(QCompleter::PopupCompletion);
|
||||
command_completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
|
||||
command_completer->setWidget(this);
|
||||
command_completer->setWrapAround(false);
|
||||
|
||||
QObject::connect(command_completer, QOverload<const QString &>::of(&QCompleter::activated),
|
||||
this, &CodeEditor::insertCompletedCommand);
|
||||
reformatCurrentLine();
|
||||
}
|
||||
|
||||
void CodeEditor::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (command_completer && command_completer->popup()->isVisible()) {
|
||||
// The following keys are forwarded by the completer to the widget
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Enter:
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Escape:
|
||||
case Qt::Key_Tab:
|
||||
case Qt::Key_Backtab:
|
||||
event->ignore();
|
||||
return; // let the completer do default behavior
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (event->key() == Qt::Key_Tab) {
|
||||
reformatCurrentLine();
|
||||
return;
|
||||
}
|
||||
if (event->key() == Qt::Key_Backtab) {
|
||||
fprintf(stderr, "Shift + Tab key hit\n");
|
||||
if (command_completer) {
|
||||
auto cursor = textCursor();
|
||||
auto line = cursor.block().text().trimmed();
|
||||
if (line.isEmpty()) return;
|
||||
|
||||
auto words = split_line(line.toStdString());
|
||||
cursor.select(QTextCursor::WordUnderCursor);
|
||||
|
||||
// if on first word, try to complete command
|
||||
if ((words.size() > 0) && (words[0] == cursor.selectedText().toStdString())) {
|
||||
// no completion on comment lines
|
||||
if (words[0][0] == '#') return;
|
||||
command_completer->setCompletionPrefix(words[0].c_str());
|
||||
auto popup = command_completer->popup();
|
||||
QRect cr = cursorRect();
|
||||
cr.setWidth(popup->sizeHintForColumn(0) +
|
||||
popup->verticalScrollBar()->sizeHint().width());
|
||||
popup->setAlternatingRowColors(true);
|
||||
command_completer->setCurrentRow(0);
|
||||
command_completer->complete(cr);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
QPlainTextEdit::keyPressEvent(event);
|
||||
@ -425,6 +479,17 @@ void CodeEditor::reformatCurrentLine()
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEditor::insertCompletedCommand(const QString &completion)
|
||||
{
|
||||
if (command_completer->widget() != this) return;
|
||||
auto cursor = textCursor();
|
||||
int extra = completion.length() - command_completer->completionPrefix().length();
|
||||
cursor.movePosition(QTextCursor::Left);
|
||||
cursor.movePosition(QTextCursor::EndOfWord);
|
||||
cursor.insertText(completion.right(extra));
|
||||
setTextCursor(cursor);
|
||||
}
|
||||
|
||||
void CodeEditor::get_help()
|
||||
{
|
||||
QString page, help;
|
||||
|
||||
@ -14,11 +14,13 @@
|
||||
#ifndef CODEEDITOR_H
|
||||
#define CODEEDITOR_H
|
||||
|
||||
#include <QCompleter>
|
||||
#include <QFont>
|
||||
#include <QMap>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QShortcut>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class CodeEditor : public QPlainTextEdit {
|
||||
Q_OBJECT
|
||||
@ -32,6 +34,7 @@ public:
|
||||
void setCursor(int block);
|
||||
void setHighlight(int block, bool error);
|
||||
QString reformatLine(const QString &line);
|
||||
void setCommandList(const QStringList &words);
|
||||
|
||||
static constexpr int NO_HIGHLIGHT = 1 << 30;
|
||||
|
||||
@ -50,10 +53,12 @@ private slots:
|
||||
void find_help(QString &page, QString &help);
|
||||
void open_help();
|
||||
void reformatCurrentLine();
|
||||
void insertCompletedCommand(const QString &completion);
|
||||
|
||||
private:
|
||||
QWidget *lineNumberArea;
|
||||
QShortcut *help_action;
|
||||
QCompleter *command_completer;
|
||||
int highlight;
|
||||
|
||||
QMap<QString, QString> cmd_map;
|
||||
|
||||
70
tools/lammps-gui/lammps_internal_commands.txt
Normal file
70
tools/lammps-gui/lammps_internal_commands.txt
Normal file
@ -0,0 +1,70 @@
|
||||
clear
|
||||
echo
|
||||
if
|
||||
include
|
||||
jump
|
||||
label
|
||||
log
|
||||
next
|
||||
partition
|
||||
print
|
||||
python
|
||||
quit
|
||||
shell
|
||||
variable
|
||||
angle_coeff
|
||||
angle_style
|
||||
atom_modify
|
||||
atom_style
|
||||
bond_coeff
|
||||
bond_style
|
||||
bond_write
|
||||
boundary
|
||||
comm_modify
|
||||
comm_style
|
||||
compute
|
||||
compute_modify
|
||||
dielectric
|
||||
dihedral_coeff
|
||||
dihedral_style
|
||||
dimension
|
||||
dump
|
||||
dump_modify
|
||||
fix
|
||||
fix_modify
|
||||
group
|
||||
improper_coeff
|
||||
improper_style
|
||||
kspace_modify
|
||||
kspace_style
|
||||
labelmap
|
||||
lattice
|
||||
mass
|
||||
min_modify
|
||||
min_style
|
||||
molecule
|
||||
neigh_modify
|
||||
neighbor
|
||||
newton
|
||||
package
|
||||
pair_coeff
|
||||
pair_modify
|
||||
pair_style
|
||||
pair_write
|
||||
processors
|
||||
region
|
||||
reset_timestep
|
||||
restart
|
||||
run_style
|
||||
special_bonds
|
||||
suffix
|
||||
thermo
|
||||
thermo_modify
|
||||
thermo_style
|
||||
timestep
|
||||
timer
|
||||
uncompute
|
||||
undump
|
||||
unfix
|
||||
units
|
||||
reset_atoms
|
||||
@ -57,6 +57,7 @@
|
||||
|
||||
static const QString blank(" ");
|
||||
static constexpr int MAXRECENT = 5;
|
||||
static constexpr int BUFLEN = 128;
|
||||
|
||||
// duplicate string
|
||||
static char *mystrdup(const std::string &text)
|
||||
@ -296,6 +297,25 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
|
||||
setWindowTitle(QString("LAMMPS-GUI - *unknown*"));
|
||||
}
|
||||
resize(settings.value("mainx", "500").toInt(), settings.value("mainy", "320").toInt());
|
||||
|
||||
// start LAMMPS and initialize command completion
|
||||
start_lammps();
|
||||
QStringList command_list;
|
||||
QFile internal_commands(":/lammps_internal_commands.txt");
|
||||
if (internal_commands.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
while (!internal_commands.atEnd()) {
|
||||
command_list << QString(internal_commands.readLine()).trimmed();
|
||||
}
|
||||
}
|
||||
internal_commands.close();
|
||||
int ncmds = lammps.style_count("command");
|
||||
char buf[BUFLEN];
|
||||
for (int i = 0; i < ncmds; ++i) {
|
||||
if (lammps.style_name("command", i, buf, BUFLEN))
|
||||
command_list << buf;
|
||||
}
|
||||
command_list.sort();
|
||||
ui->textEdit->setCommandList(command_list);
|
||||
}
|
||||
|
||||
LammpsGui::~LammpsGui()
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>lammps-icon-128x128.png</file>
|
||||
<file>help_index.table</file>
|
||||
<!-- This file is updated with: grep 'mycmd ==' ../../src/input.cpp | sed -e 's/^.*mycmd == "\(.*\)".*$/\1/' > lammps_internal_commands.txt -->
|
||||
<file>lammps_internal_commands.txt</file>
|
||||
<file>antialias.png</file>
|
||||
<file>application-calc.png</file>
|
||||
<file>application-exit.png</file>
|
||||
@ -34,7 +37,6 @@
|
||||
<file>help-about.png</file>
|
||||
<file>help-browser.png</file>
|
||||
<file>help-faq.png</file>
|
||||
<file>help_index.table</file>
|
||||
<file>image-x-generic.png</file>
|
||||
<file>media-playback-start-2.png</file>
|
||||
<file>media-playlist-repeat.png</file>
|
||||
|
||||
@ -97,6 +97,33 @@ int LammpsWrapper::id_name(const char *keyword, int idx, char *buf, int len)
|
||||
return val;
|
||||
}
|
||||
|
||||
int LammpsWrapper::style_count(const char *keyword)
|
||||
{
|
||||
int val = 0;
|
||||
if (lammps_handle) {
|
||||
#if defined(LAMMPS_GUI_USE_PLUGIN)
|
||||
val = ((liblammpsplugin_t *)plugin_handle)->style_count(lammps_handle, keyword);
|
||||
#else
|
||||
val = lammps_style_count(lammps_handle, keyword);
|
||||
#endif
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
int LammpsWrapper::style_name(const char *keyword, int idx, char *buf, int len)
|
||||
{
|
||||
int val = 0;
|
||||
if (lammps_handle) {
|
||||
#if defined(LAMMPS_GUI_USE_PLUGIN)
|
||||
val =
|
||||
((liblammpsplugin_t *)plugin_handle)->style_name(lammps_handle, keyword, idx, buf, len);
|
||||
#else
|
||||
val = lammps_style_name(lammps_handle, keyword, idx, buf, len);
|
||||
#endif
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
int LammpsWrapper::variable_info(int idx, char *buf, int len)
|
||||
{
|
||||
int val = 0;
|
||||
|
||||
@ -35,6 +35,8 @@ public:
|
||||
|
||||
int id_count(const char *idtype);
|
||||
int id_name(const char *idtype, int idx, char *buf, int buflen);
|
||||
int style_count(const char *keyword);
|
||||
int style_name(const char *keyword, int idx, char *buf, int buflen);
|
||||
int variable_info(int idx, char *buf, int buflen);
|
||||
|
||||
double get_thermo(const char *keyword);
|
||||
|
||||
Reference in New Issue
Block a user