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

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.16)
project(BareCode
VERSION 1.0.0
VERSION 1.1.0
DESCRIPTION "A modular code editor built with Qt6"
LANGUAGES CXX
)

View File

@@ -1,7 +1,7 @@
# BareCode
Ein modularer Code-Editor, entwickelt mit **C++17**, **Qt6** und **CMake**
von **Dany Thinnes** | [Projekt Hirnfrei](https://www.projekt-hirnfrei.de)
**BareCode Schlanker Code-Editor für Web-Entwickler**
Version 1.1.0
Kompiliert sauber auf **Linux**, **Windows** und **Haiku**.

View File

@@ -7,7 +7,7 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
app.setApplicationName("BareCode");
app.setApplicationVersion("1.0.0");
app.setApplicationVersion("1.1.0");
app.setOrganizationName("BareCode");
// Icon in allen verfügbaren Größen setzen

1197
resources/php_functions.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -7,5 +7,6 @@
<file>icon_48.png</file>
<file>icon_32.png</file>
<file>icon_16.png</file>
<file>php_functions.json</file>
</qresource>
</RCC>

View File

@@ -74,7 +74,7 @@ AboutDialog::AboutDialog(QWidget *parent)
info->addLayout(row);
};
makeRow(tr("Version"), "1.0.0");
makeRow(tr("Version"), "1.1.0");
makeRow(tr("Entwickler"), "Dany Thinnes");
makeRow(tr("Projekt"), "Projekt Hirnfrei");
makeRow(tr("Framework"), QString("Qt %1").arg(qVersion()));

View File

@@ -13,6 +13,10 @@ set(EDITOR_SOURCES
FileSearchPanel.h
ColorIndicator.cpp
ColorIndicator.h
SignatureHelper.cpp
SignatureHelper.h
SignatureTooltip.cpp
SignatureTooltip.h
)
add_library(BareCode_Editor STATIC ${EDITOR_SOURCES})

View File

@@ -1,6 +1,7 @@
#include "CodeEditor.h"
#include "LineNumberArea.h"
#include "ColorIndicator.h"
#include "SignatureHelper.h"
#include "core/Settings.h"
#include "highlighter/HighlighterFactory.h"
@@ -24,6 +25,7 @@ CodeEditor::CodeEditor(Settings *settings, QWidget *parent)
{
m_lineNumberArea = new LineNumberArea(this);
m_colorIndicator = new ColorIndicator(this);
m_signatureHelper = new SignatureHelper(this);
setupEditor();
connect(this, &CodeEditor::blockCountChanged,

View File

@@ -9,6 +9,7 @@ class LineNumberArea;
class Settings;
class SyntaxHighlighter;
class ColorIndicator;
class SignatureHelper;
// ---------------------------------------------------------------------------
// CodeEditor Core editing widget.
@@ -70,5 +71,6 @@ private:
LineNumberArea *m_lineNumberArea = nullptr;
SyntaxHighlighter *m_highlighter = nullptr;
ColorIndicator *m_colorIndicator = nullptr;
SignatureHelper *m_signatureHelper = nullptr;
QString m_filePath;
};

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;
}

View File

@@ -0,0 +1,51 @@
#pragma once
#include <QObject>
#include <QString>
#include <QHash>
class CodeEditor;
class SignatureTooltip;
// ---------------------------------------------------------------------------
// SignatureHelper Lädt die PHP-Funktionsdatenbank und zeigt beim Tippen
// automatisch die passende Funktionssignatur als Tooltip.
//
// Logik:
// • Bei jedem Tastendruck: Text links vom Cursor analysieren
// • Wenn "funktionsname(" erkannt wird → Tooltip anzeigen
// • Wenn ")" die öffnende Klammer schließt → Tooltip verstecken
// • Wenn Cursor sich weg bewegt → Tooltip verstecken
// ---------------------------------------------------------------------------
class SignatureHelper : public QObject
{
Q_OBJECT
public:
explicit SignatureHelper(CodeEditor *editor);
private slots:
void onCursorPositionChanged();
private:
struct FunctionInfo
{
QString signature;
QString description;
};
void loadDatabase();
void loadProjectFunctions();
// Extrahiert den Funktionsnamen direkt links vor dem letzten '('
// Gibt leeren String zurück wenn kein Kontext gefunden
QString extractFunctionName(const QString &textUpToCursor) const;
// Zählt offene Klammern — bei 0 ist der Aufruf abgeschlossen
int countOpenParens(const QString &textUpToCursor) const;
CodeEditor *m_editor = nullptr;
SignatureTooltip *m_tooltip = nullptr;
QHash<QString, FunctionInfo> m_functions; // name → info
};

View File

@@ -0,0 +1,91 @@
#include "SignatureTooltip.h"
#include <QApplication>
#include <QScreen>
SignatureTooltip::SignatureTooltip(QWidget *parent)
: QFrame(parent, Qt::ToolTip | Qt::FramelessWindowHint)
{
setFrameShape(QFrame::StyledPanel);
setFrameShadow(QFrame::Raised);
setAttribute(Qt::WA_ShowWithoutActivating);
// Dezentes Styling passend zu Hell- und Dunkeltheme
setStyleSheet(
"SignatureTooltip {"
" background: palette(toolTipBase);"
" border: 1px solid palette(mid);"
" border-radius: 4px;"
" padding: 4px;"
"}"
);
m_layout = new QVBoxLayout(this);
m_layout->setContentsMargins(8, 6, 8, 6);
m_layout->setSpacing(3);
// Signatur — Monospace, deutlich hervorgehoben
m_sigLabel = new QLabel(this);
m_sigLabel->setTextFormat(Qt::PlainText);
m_sigLabel->setWordWrap(false);
QFont sigFont = m_sigLabel->font();
sigFont.setFamily("Monospace");
sigFont.setStyleHint(QFont::Monospace);
sigFont.setPointSize(sigFont.pointSize());
m_sigLabel->setFont(sigFont);
m_sigLabel->setStyleSheet("color: palette(toolTipText); font-weight: bold;");
m_layout->addWidget(m_sigLabel);
// Beschreibung — kleiner, gedimmt
m_descLabel = new QLabel(this);
m_descLabel->setTextFormat(Qt::PlainText);
m_descLabel->setWordWrap(false);
m_descLabel->setStyleSheet("color: palette(mid);");
QFont descFont = m_descLabel->font();
descFont.setPointSize(qMax(descFont.pointSize() - 1, 8));
m_descLabel->setFont(descFont);
m_layout->addWidget(m_descLabel);
hide();
}
void SignatureTooltip::showSignature(const QString &signature,
const QString &description,
const QPoint &globalPos)
{
m_sigLabel->setText(signature);
if (description.isEmpty())
{
m_descLabel->hide();
}
else
{
m_descLabel->setText(description);
m_descLabel->show();
}
adjustSize();
// Position so wählen dass das Popup nicht aus dem Bildschirm ragt
QPoint pos = globalPos;
const QRect screen = QApplication::primaryScreen()->availableGeometry();
if (pos.x() + width() > screen.right())
{
pos.setX(screen.right() - width() - 4);
}
if (pos.y() + height() > screen.bottom())
{
pos.setY(globalPos.y() - height() - 24);
}
move(pos);
show();
raise();
}
void SignatureTooltip::hide()
{
QFrame::hide();
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <QFrame>
#include <QLabel>
#include <QString>
#include <QVBoxLayout>
// ---------------------------------------------------------------------------
// SignatureTooltip Schwebendes Popup das die Signatur einer Funktion zeigt.
// Erscheint unter dem Cursor, verschwindet automatisch wenn der Nutzer
// die Klammer schließt oder den Kontext verlässt.
// ---------------------------------------------------------------------------
class SignatureTooltip : public QFrame
{
Q_OBJECT
public:
explicit SignatureTooltip(QWidget *parent = nullptr);
void showSignature(const QString &signature,
const QString &description,
const QPoint &globalPos);
void hide();
private:
QVBoxLayout *m_layout = nullptr;
QLabel *m_sigLabel = nullptr;
QLabel *m_descLabel = nullptr;
};