BareCode V 1.1.0

This commit is contained in:
2026-08-10 09:28:12 +02:00
parent 663127eaa6
commit d9d60b73f9
13 changed files with 1604 additions and 5 deletions

View File

@@ -0,0 +1,222 @@
#include "SignatureHelper.h"
#include "SignatureTooltip.h"
#include "CodeEditor.h"
#include <QTextCursor>
#include <QTextBlock>
#include <QFile>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QRect>
#include <QRegularExpression>
SignatureHelper::SignatureHelper(CodeEditor *editor)
: QObject(editor)
, m_editor(editor)
{
// Tooltip als Kind des Viewports — bleibt im Fenster
m_tooltip = new SignatureTooltip(editor->window());
loadDatabase();
connect(m_editor, &CodeEditor::cursorPositionChanged,
this, &SignatureHelper::onCursorPositionChanged);
}
// ---------------------------------------------------------------------------
// Datenbank laden
// ---------------------------------------------------------------------------
void SignatureHelper::loadDatabase()
{
QFile f(":/php_functions.json");
if (!f.open(QIODevice::ReadOnly))
{
return;
}
const QJsonDocument doc = QJsonDocument::fromJson(f.readAll());
if (!doc.isArray())
{
return;
}
for (const QJsonValue &val : doc.array())
{
const QJsonObject obj = val.toObject();
const QString name = obj["name"].toString();
if (name.isEmpty())
{
continue;
}
FunctionInfo info;
info.signature = obj["signature"].toString();
info.description = obj["desc"].toString();
m_functions.insert(name.toLower(), info);
}
}
// ---------------------------------------------------------------------------
// Cursor-Bewegung auswerten
// ---------------------------------------------------------------------------
void SignatureHelper::onCursorPositionChanged()
{
const QTextCursor cursor = m_editor->textCursor();
const QString block = cursor.block().text();
const int col = cursor.columnNumber();
const QString leftText = block.left(col);
const QString funcName = extractFunctionName(leftText);
if (funcName.isEmpty())
{
m_tooltip->hide();
return;
}
// Klammern zählen — wenn alle geschlossen, Tooltip ausblenden
if (countOpenParens(leftText) <= 0)
{
m_tooltip->hide();
return;
}
const QString key = funcName.toLower();
if (!m_functions.contains(key))
{
m_tooltip->hide();
return;
}
const FunctionInfo &info = m_functions[key];
// Position unter dem Cursor berechnen
const QRect cursorRect = m_editor->cursorRect(cursor);
const QPoint globalPos = m_editor->viewport()->mapToGlobal(
QPoint(cursorRect.left(), cursorRect.bottom() + 4)
);
m_tooltip->showSignature(info.signature, info.description, globalPos);
}
// ---------------------------------------------------------------------------
// Funktionsnamen links vor der öffnenden Klammer extrahieren
// ---------------------------------------------------------------------------
QString SignatureHelper::extractFunctionName(const QString &text) const
{
// Wir suchen das letzte '(' das zu einem Funktionsnamen gehört.
// Dabei müssen wir verschachtelte Klammern korrekt behandeln.
int depth = 0;
int openPos = -1;
for (int i = text.length() - 1; i >= 0; --i)
{
const QChar ch = text[i];
if (ch == ')')
{
++depth;
}
else if (ch == '(')
{
if (depth == 0)
{
openPos = i;
break;
}
--depth;
}
}
if (openPos <= 0)
{
return QString();
}
// Funktionsnamen direkt links von '(' lesen
int end = openPos - 1;
// Leerzeichen überspringen
while (end >= 0 && text[end].isSpace())
{
--end;
}
if (end < 0)
{
return QString();
}
// Bezeichner-Zeichen sammeln (Buchstaben, Ziffern, _, :, \)
int start = end;
while (start > 0 &&
(text[start - 1].isLetterOrNumber() ||
text[start - 1] == '_' ||
text[start - 1] == ':' ||
text[start - 1] == '\\'))
{
--start;
}
const QString name = text.mid(start, end - start + 1);
// Schlüsselwörter und leere Namen ausschließen
static const QStringList keywords = {
"if", "else", "elseif", "while", "for", "foreach",
"switch", "match", "catch", "function", "fn"
};
if (name.isEmpty() || keywords.contains(name.toLower()))
{
return QString();
}
// Nur den letzten Teil nach :: oder -> nehmen
const int colonPos = name.lastIndexOf("::");
const int arrowPos = name.lastIndexOf("->");
const int backslashPos = name.lastIndexOf("\\");
const int splitPos = qMax(backslashPos, qMax(colonPos, arrowPos));
if (splitPos >= 0)
{
return name.mid(splitPos + (name[splitPos] == ':' ? 2 : (name[splitPos] == '\\' ? 1 : 2)));
}
return name;
}
// ---------------------------------------------------------------------------
// Offene Klammern zählen
// ---------------------------------------------------------------------------
int SignatureHelper::countOpenParens(const QString &text) const
{
int depth = 0;
bool inString = false;
QChar stringChar;
for (int i = 0; i < text.length(); ++i)
{
const QChar ch = text[i];
// Einfache String-Erkennung (kein vollständiger PHP-Parser)
if (!inString && (ch == '\'' || ch == '"'))
{
inString = true;
stringChar = ch;
continue;
}
if (inString)
{
if (ch == stringChar && (i == 0 || text[i - 1] != '\\'))
{
inString = false;
}
continue;
}
if (ch == '(') { ++depth; }
else if (ch == ')') { --depth; }
}
return depth;
}