Dateien, die als Parameter übergeben werden, werden nach dem Start direkt geladen

This commit is contained in:
2026-08-25 14:56:27 +02:00
parent 7264b68f11
commit 04c5212d54
78 changed files with 9528 additions and 0 deletions

View File

@@ -0,0 +1,256 @@
#include "VariableCompleter.h"
#include "CodeEditor.h"
#include <QTextCursor>
#include <QTextBlock>
#include <QKeyEvent>
#include <QListWidgetItem>
#include <QAbstractItemView>
#include <QScrollBar>
#include <QApplication>
#include <QScreen>
VariableCompleter::VariableCompleter(CodeEditor *editor)
: QObject(editor)
, m_editor(editor)
{
// Popup als reines Anzeige-Fenster — dieselbe Fensterart wie
// SignatureTooltip, die nachweislich nie den Fokus an sich reißt.
// Wichtig: Ein echtes Elternfenster (editor->window()) angeben, sonst
// behandelt der Fenstermanager das Popup als eigenständiges Fenster.
// Das führte dazu, dass bei mehreren offenen Dateien/Tabs verwaiste
// Popups entstehen konnten, die den Fokus übernehmen und die
// Texteingabe blockieren.
m_popup = new QListWidget(editor->window());
m_popup->setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint);
m_popup->setAttribute(Qt::WA_ShowWithoutActivating);
m_popup->setFocusPolicy(Qt::NoFocus);
m_popup->setMaximumHeight(200);
m_popup->setMinimumWidth(180);
m_popup->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_popup->setStyleSheet(
"QListWidget {"
" border: 1px solid palette(mid);"
" background: palette(toolTipBase);"
" color: palette(toolTipText);"
" font-family: Monospace;"
"}"
"QListWidget::item:selected {"
" background: palette(highlight);"
" color: palette(highlightedText);"
"}"
);
connect(m_popup, &QListWidget::itemActivated,
this, &VariableCompleter::onItemActivated);
}
// ---------------------------------------------------------------------------
// Nach jedem Tastendruck aufrufen
// ---------------------------------------------------------------------------
void VariableCompleter::handleKeyPress(QKeyEvent *event)
{
// Popup-Navigation
if (m_popup->isVisible())
{
if (event->key() == Qt::Key_Escape)
{
hidePopup();
return;
}
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
{
if (m_popup->currentItem())
{
onItemActivated(m_popup->currentItem());
}
hidePopup();
return;
}
if (event->key() == Qt::Key_Down)
{
const int next = qMin(m_popup->currentRow() + 1,
m_popup->count() - 1);
m_popup->setCurrentRow(next);
return;
}
if (event->key() == Qt::Key_Up)
{
const int prev = qMax(m_popup->currentRow() - 1, 0);
m_popup->setCurrentRow(prev);
return;
}
}
// Nach dem normalen Tastendruck Popup aktualisieren
// (der Event wurde bereits an QPlainTextEdit weitergegeben)
updatePopup();
}
// ---------------------------------------------------------------------------
// Popup aktualisieren
// ---------------------------------------------------------------------------
void VariableCompleter::updatePopup()
{
const QString prefix = currentPrefix();
// Nur bei $ und mindestens einem weiteren Zeichen anzeigen
if (prefix.length() < 2 || !prefix.startsWith('$'))
{
hidePopup();
return;
}
const QStringList allVars = collectVariables();
const QString filter = prefix.toLower();
QStringList matches;
for (const QString &var : allVars)
{
if (var.toLower().startsWith(filter) && var != prefix)
{
matches.append(var);
}
}
if (matches.isEmpty())
{
hidePopup();
return;
}
// Popup befüllen
m_popup->clear();
for (const QString &var : matches)
{
m_popup->addItem(var);
}
m_popup->setCurrentRow(0);
// Größe anpassen
const int itemHeight = m_popup->sizeHintForRow(0) + 2;
const int height = qMin(matches.size() * itemHeight + 4, 200);
m_popup->setFixedHeight(height);
// Position unter dem Cursor
const QRect cursorRect = m_editor->cursorRect();
QPoint pos = m_editor->viewport()->mapToGlobal(
QPoint(cursorRect.left(), cursorRect.bottom() + 2)
);
// Nicht aus dem Bildschirm herausragen
const QRect screen = QApplication::primaryScreen()->availableGeometry();
if (pos.x() + m_popup->width() > screen.right())
{
pos.setX(screen.right() - m_popup->width());
}
if (pos.y() + height > screen.bottom())
{
pos.setY(cursorRect.top() - height - 2);
}
m_popup->move(pos);
m_popup->show();
m_popup->raise();
}
void VariableCompleter::hidePopup()
{
m_popup->hide();
m_popup->clear();
}
// ---------------------------------------------------------------------------
// Editor hat den Fokus verloren (z. B. Tab-Wechsel) — Popup schließen
// ---------------------------------------------------------------------------
void VariableCompleter::notifyFocusLost()
{
hidePopup();
}
// ---------------------------------------------------------------------------
// Variablen im aktuellen Dokument sammeln
// ---------------------------------------------------------------------------
QStringList VariableCompleter::collectVariables() const
{
static const QRegularExpression varRegex(R"(\$[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)");
QSet<QString> seen;
QStringList result;
const QString text = m_editor->toPlainText();
QRegularExpressionMatchIterator it = varRegex.globalMatch(text);
while (it.hasNext())
{
const QString var = it.next().captured(0);
if (!seen.contains(var))
{
seen.insert(var);
result.append(var);
}
}
result.sort(Qt::CaseInsensitive);
return result;
}
// ---------------------------------------------------------------------------
// Text links vom Cursor — das angefangene $variable
// ---------------------------------------------------------------------------
QString VariableCompleter::currentPrefix() const
{
const QTextCursor cursor = m_editor->textCursor();
const QString line = cursor.block().text();
const int col = cursor.columnNumber();
if (col == 0)
{
return QString();
}
// Rückwärts gehen bis zum $ oder einem Nicht-Bezeichner-Zeichen
int start = col - 1;
while (start > 0)
{
const QChar c = line[start - 1];
if (!c.isLetterOrNumber() && c != '_' && c != '$')
{
break;
}
--start;
}
const QString token = line.mid(start, col - start);
return token.startsWith('$') ? token : QString();
}
// ---------------------------------------------------------------------------
// Klick oder Enter — Variable einfügen
// ---------------------------------------------------------------------------
void VariableCompleter::onItemActivated(QListWidgetItem *item)
{
if (!item)
{
return;
}
const QString selected = item->text();
const QString prefix = currentPrefix();
if (prefix.isEmpty())
{
hidePopup();
return;
}
// Prefix durch den vollständigen Variablennamen ersetzen
QTextCursor cursor = m_editor->textCursor();
cursor.movePosition(QTextCursor::Left,
QTextCursor::KeepAnchor,
prefix.length());
cursor.insertText(selected);
m_editor->setTextCursor(cursor);
hidePopup();
}