Compare commits

...

2 Commits

124 changed files with 2763 additions and 32827 deletions

3
.gitmodules vendored
View File

@ -11,3 +11,6 @@
[submodule "3rdparty/cpptrace"]
path = 3rdparty/cpptrace
url = git@github.com:Wing-summer/cpptrace.git
[submodule "3rdparty/WingCodeEdit"]
path = 3rdparty/WingCodeEdit
url = git@github.com:Wing-summer/WingCodeEdit.git

View File

@ -9,8 +9,6 @@
QConsoleIODevice::QConsoleIODevice(QConsoleWidget *w, QObject *parent)
: QIODevice(parent), widget_(w), readpos_(0), writtenSinceLastEmit_(0),
readSinceLastEmit_(0) {
setCurrentWriteChannel(STDOUT_FILENO);
open(QIODevice::ReadWrite | QIODevice::Unbuffered);
}
@ -47,16 +45,12 @@ qint64 QConsoleIODevice::readData(char *data, qint64 len) {
memcpy(data, readbuff_.constData() + readpos_, b);
readpos_ += b;
}
return qint64(b);
return (qint64)b;
}
qint64 QConsoleIODevice::writeData(const char *data, qint64 len) {
QByteArray ba(data, (int)len);
int ch = currentWriteChannel();
if (ch == STDOUT_FILENO)
widget_->writeStdOut(ba);
else
widget_->writeStdErr(ba);
widget_->write(ba);
writtenSinceLastEmit_ += len;
if (!signalsBlocked()) {

View File

@ -6,14 +6,6 @@
class QConsoleWidget;
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
class QConsoleIODevice : public QIODevice {
Q_OBJECT

View File

@ -1,437 +1,442 @@
#include "QConsoleWidget.h"
#include "class/ascompletion.h"
#include "control/qcodecompletionwidget.h"
#include "qdocumentline.h"
#include "qformatscheme.h"
#include "QConsoleIODevice.h"
#include <QApplication>
#include <QClipboard>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QKeyEvent>
#include <QMenu>
#include <QMimeData>
#include <QMouseEvent>
#include <QScrollBar>
QConsoleWidget::QConsoleWidget(QWidget *parent)
: QEditor(false, parent), mode_(Output) {
iodevice_ = new QConsoleIODevice(this, this);
m_doc->setProperty("console", QVariant::fromValue(inpos_));
setFlag(QEditor::AutoCloseChars, true);
setAcceptDrops(false);
setUndoRedoEnabled(false);
setCursorMirrorEnabled(false);
createSimpleBasicContextMenu(false, false);
}
QConsoleWidget::~QConsoleWidget() {}
void QConsoleWidget::setMode(ConsoleMode m) {
if (m == mode_)
return;
if (m == Input) {
auto cursor = this->cursor();
cursor.movePosition(QDocumentCursor::End);
setCursor(cursor);
inpos_ = cursor;
m_doc->setProperty("console", QVariant::fromValue(inpos_));
mode_ = Input;
}
if (m == Output) {
mode_ = Output;
}
}
QString QConsoleWidget::getCommandLine() {
if (mode_ == Output)
return QString();
auto textCursor = this->cursor();
auto ltxt = textCursor.line().text();
QString code = ltxt.mid(inpos_.columnNumber());
return code.replace(QChar::ParagraphSeparator, QChar::LineFeed);
}
void QConsoleWidget::paste() {
auto text = qApp->clipboard()->text();
if (canPaste()) {
m_cursor.insertText(text.replace('\n', ' '));
}
}
void QConsoleWidget::handleReturnKey() {
QString code = getCommandLine();
// start new block
auto textCursor = this->cursor();
auto line = textCursor.line();
textCursor.moveTo(line.lineNumber(), line.length());
textCursor.insertLine();
setMode(Output);
setCursor(textCursor);
// Update the history
if (!code.isEmpty())
history_.add(code);
// send signal / update iodevice
if (iodevice_->isOpen())
iodevice_->consoleWidgetInput(code);
emit consoleCommand(code);
}
void QConsoleWidget::keyPressEvent(QKeyEvent *e) {
if (mode() == Input) {
auto ascom = dynamic_cast<AsCompletion *>(completionEngine());
if (ascom) {
auto cw = ascom->codeCompletionWidget();
if (cw && cw->isVisible()) {
// The following keys are forwarded by the completer to the
// widget
switch (e->key()) {
case Qt::Key_Tab:
case Qt::Key_Enter:
case Qt::Key_Return:
case Qt::Key_Escape:
case Qt::Key_Backtab:
e->ignore();
return; // let the completer do default behavior
default:
break;
}
}
}
}
auto textCursor = this->cursor();
bool selectionInEditZone = isSelectionInEditZone();
// check for user abort request
if (e->modifiers() & Qt::ControlModifier) {
if (e->key() == Qt::Key_Q) // Ctrl-Q aborts
{
emit abortEvaluation();
e->accept();
return;
}
}
// Allow copying anywhere in the console ...
if (e->key() == Qt::Key_C && e->modifiers() == Qt::ControlModifier) {
if (textCursor.hasSelection())
copy();
e->accept();
return;
}
// the rest of key events are ignored during output mode
if (mode() != Input) {
e->ignore();
return;
}
// Allow cut only if the selection is limited to the interactive area ...
if (e->key() == Qt::Key_X && e->modifiers() == Qt::ControlModifier) {
cut();
e->accept();
return;
}
// Allow paste only if the selection is in the interactive area ...
if (e->key() == Qt::Key_V && e->modifiers() == Qt::ControlModifier) {
if (selectionInEditZone || isCursorInEditZone()) {
const QMimeData *const clipboard =
QApplication::clipboard()->mimeData();
const QString text = clipboard->text();
if (!text.isNull()) {
textCursor.insertText(text);
}
}
e->accept();
return;
}
int key = e->key();
// int shiftMod = e->modifiers() == Qt::ShiftModifier;
if (history_.isActive() && key != Qt::Key_Up && key != Qt::Key_Down)
history_.deactivate();
// Force the cursor back to the interactive area
// for all keys except modifiers
if (!isCursorInEditZone() && key != Qt::Key_Control &&
key != Qt::Key_Shift && key != Qt::Key_Alt) {
auto line = textCursor.line();
textCursor.moveTo(line.lineNumber(), line.length());
setCursor(textCursor);
}
switch (key) {
case Qt::Key_Up:
// Activate the history and move to the 1st matching history item
if (!history_.isActive())
history_.activate(getCommandLine());
if (history_.move(true))
replaceCommandLine(history_.currentValue());
else
QApplication::beep();
e->accept();
break;
case Qt::Key_Down:
if (history_.move(false))
replaceCommandLine(history_.currentValue());
else
QApplication::beep();
e->accept();
case Qt::Key_Left:
if (textCursor > inpos_)
QEditor::keyPressEvent(e);
else {
QApplication::beep();
e->accept();
}
break;
case Qt::Key_Delete:
e->accept();
if (selectionInEditZone)
cut();
else {
// cursor must be in edit zone
if (textCursor < inpos_)
QApplication::beep();
else
QEditor::keyPressEvent(e);
}
break;
case Qt::Key_Backspace:
e->accept();
if (selectionInEditZone)
cut();
else {
// cursor must be in edit zone
QDocumentCursor pos;
if (textCursor.hasSelection()) {
pos = textCursor.selectionStart();
} else {
pos = textCursor;
}
if (pos <= inpos_)
QApplication::beep();
else
QEditor::keyPressEvent(e);
}
break;
case Qt::Key_Home:
e->accept();
setCursor(inpos_);
break;
case Qt::Key_Enter:
case Qt::Key_Return:
e->accept();
handleReturnKey();
break;
case Qt::Key_Escape:
e->accept();
replaceCommandLine(QString());
break;
default:
// setCurrentCharFormat(chanFormat_[StandardInput]);
if (isCursorInEditZone()) {
QEditor::keyPressEvent(e);
} else {
e->ignore();
}
break;
}
}
bool QConsoleWidget::isSelectionInEditZone() const {
auto textCursor = this->cursor();
if (!textCursor.hasSelection())
return false;
auto selectionStart = textCursor.selectionStart();
auto selectionEnd = textCursor.selectionEnd();
return selectionStart >= inpos_ && selectionEnd > inpos_;
}
bool QConsoleWidget::isCursorInEditZone() const { return cursor() >= inpos_; }
bool QConsoleWidget::canPaste() const {
auto textCursor = this->cursor();
if (textCursor < inpos_)
return false;
return true;
}
void QConsoleWidget::replaceCommandLine(const QString &str) {
// Select the text after the last command prompt ...
auto textCursor = this->cursor();
auto line = textCursor.line();
textCursor.moveTo(line.lineNumber(), line.length());
auto bcursor = inpos_;
bcursor.setSelectionBoundary(textCursor);
bcursor.replaceSelectedText(str);
bcursor.movePosition(str.length());
setCursor(bcursor);
}
void QConsoleWidget::write(const QString &message, const QString &sfmtID) {
auto tc = cursor();
auto ascom = dynamic_cast<AsCompletion *>(completionEngine());
QCodeCompletionWidget *cw = nullptr;
if (ascom) {
cw = ascom->codeCompletionWidget();
}
if (ascom == nullptr || mode() == Output || (cw && cw->isCompleting())) {
// in output mode or completion messages are appended
auto tc1 = tc;
auto line = tc1.line();
tc1.moveTo(line, line.length());
// check is cursor was not at the end
// (e.g. had been moved per mouse action)
bool needsRestore = tc1.position() != tc.position();
// insert text
setCursor(tc1);
tc.insertText(message, false, sfmtID);
ensureCursorVisible();
// restore cursor if needed
if (needsRestore)
setCursor(tc);
} else {
// in Input mode output messages are inserted
// before the edit block
// get offset of current pos from the end
auto editpos = tc;
auto line = editpos.line();
tc.moveTo(line, 0);
tc.insertLine();
tc.insertText(message, false, sfmtID);
setCursor(editpos);
}
}
void QConsoleWidget::writeStdOut(const QString &s) {
write(s, QStringLiteral("stdout"));
}
void QConsoleWidget::writeStdErr(const QString &s) {
write(s, QStringLiteral("stderr"));
}
/////////////////// QConsoleWidget::History /////////////////////
QConsoleWidget::History QConsoleWidget::history_;
QConsoleWidget::History::History(void)
: pos_(0), active_(false), maxsize_(10000) {}
QConsoleWidget::History::~History(void) {}
void QConsoleWidget::History::add(const QString &str) {
active_ = false;
// if (strings_.contains(str)) return;
if (strings_.size() == maxsize_)
strings_.pop_back();
strings_.push_front(str);
}
void QConsoleWidget::History::activate(const QString &tk) {
active_ = true;
token_ = tk;
pos_ = -1;
}
bool QConsoleWidget::History::move(bool dir) {
if (active_) {
int next = indexOf(dir, pos_);
if (pos_ != next) {
pos_ = next;
return true;
} else
return false;
} else
return false;
}
int QConsoleWidget::History::indexOf(bool dir, int from) const {
int i = from, to = from;
if (dir) {
while (i < strings_.size() - 1) {
const QString &si = strings_.at(++i);
if (si.startsWith(token_)) {
return i;
}
}
} else {
while (i > 0) {
const QString &si = strings_.at(--i);
if (si.startsWith(token_)) {
return i;
}
}
return -1;
}
return to;
}
void QConsoleWidget::cut() {
if (isSelectionInEditZone()) {
QEditor::cut();
}
}
/////////////////// Stream manipulators /////////////////////
QTextStream &waitForInput(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d)
d->waitForReadyRead(-1);
return s;
}
QTextStream &inputMode(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d && d->widget())
d->widget()->setMode(QConsoleWidget::Input);
return s;
}
QTextStream &outChannel(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d)
d->setCurrentWriteChannel(STDOUT_FILENO);
return s;
}
QTextStream &errChannel(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d)
d->setCurrentWriteChannel(STDERR_FILENO);
return s;
}
#include "QConsoleWidget.h"
#include "QConsoleIODevice.h"
#include "class/skinmanager.h"
#include <KSyntaxHighlighting/Repository>
#include <KSyntaxHighlighting/Theme>
#include <QAbstractItemView>
#include <QApplication>
#include <QClipboard>
#include <QDebug>
#include <QKeyEvent>
#include <QMenu>
#include <QMimeData>
#include <QMouseEvent>
#include <QScrollBar>
#include <QStringListModel>
#include <QTextBlock>
#include <QTextCursor>
#include <QTextDocumentFragment>
QConsoleWidget::QConsoleWidget(QWidget *parent)
: WingCodeEdit(parent), mode_(Output) {
setAutoCloseChar(true);
switch (SkinManager::instance().currentTheme()) {
case SkinManager::Theme::Dark:
setTheme(syntaxRepo().defaultTheme(
KSyntaxHighlighting::Repository::DarkTheme));
break;
case SkinManager::Theme::Light:
setTheme(syntaxRepo().defaultTheme(
KSyntaxHighlighting::Repository::LightTheme));
break;
}
iodevice_ = new QConsoleIODevice(this, this);
setTextInteractionFlags(Qt::TextEditorInteraction);
setUndoRedoEnabled(false);
}
QConsoleWidget::~QConsoleWidget() {}
void QConsoleWidget::setMode(ConsoleMode m) {
if (m == mode_)
return;
if (m == Input) {
QTextCursor cursor = textCursor();
cursor.movePosition(QTextCursor::End);
setTextCursor(cursor);
inpos_ = cursor.position();
mode_ = Input;
}
if (m == Output) {
mode_ = Output;
}
}
QString QConsoleWidget::getCommandLine() {
if (mode_ == Output)
return QString();
// select text in edit zone (from the input pos to the end)
QTextCursor textCursor = this->textCursor();
textCursor.movePosition(QTextCursor::End);
textCursor.setPosition(inpos_, QTextCursor::KeepAnchor);
QString code = textCursor.selectedText();
code.replace(QChar::ParagraphSeparator, QChar::LineFeed);
return code;
}
QConsoleWidget::History &QConsoleWidget::history() { return history_; }
void QConsoleWidget::handleReturnKey() {
QString code = getCommandLine();
// start new block
appendPlainText(QString());
setMode(Output);
QTextCursor textCursor = this->textCursor();
textCursor.movePosition(QTextCursor::End);
setTextCursor(textCursor);
// Update the history
if (!code.isEmpty())
history_.add(code);
// send signal / update iodevice
if (iodevice_->isOpen())
iodevice_->consoleWidgetInput(code);
emit consoleCommand(code);
}
void QConsoleWidget::handleTabKey() {
QTextCursor tc = this->textCursor();
int anchor = tc.anchor();
int position = tc.position();
tc.setPosition(inpos_);
tc.setPosition(position, QTextCursor::KeepAnchor);
QString text = tc.selectedText().trimmed();
tc.setPosition(anchor, QTextCursor::MoveAnchor);
tc.setPosition(position, QTextCursor::KeepAnchor);
if (text.isEmpty()) {
tc.insertText(" ");
} else {
// updateCompleter();
// if (completer_ && completer_->completionCount() == 1) {
// insertCompletion(completer_->currentCompletion());
// completer_->popup()->hide();
// }
}
}
void QConsoleWidget::keyPressEvent(QKeyEvent *e) {
QTextCursor textCursor = this->textCursor();
bool selectionInEditZone = isSelectionInEditZone();
// check for user abort request
if (e->modifiers() & Qt::ControlModifier) {
if (e->key() == Qt::Key_Q) // Ctrl-Q aborts
{
emit abortEvaluation();
e->accept();
return;
}
}
// Allow copying anywhere in the console ...
if (e->key() == Qt::Key_C && e->modifiers() == Qt::ControlModifier) {
if (textCursor.hasSelection())
copy();
e->accept();
return;
}
// the rest of key events are ignored during output mode
if (mode() != Input) {
e->ignore();
return;
}
// Allow cut only if the selection is limited to the interactive area ...
if (e->key() == Qt::Key_X && e->modifiers() == Qt::ControlModifier) {
if (selectionInEditZone)
cut();
e->accept();
return;
}
// Allow paste only if the selection is in the interactive area ...
if (e->key() == Qt::Key_V && e->modifiers() == Qt::ControlModifier) {
if (selectionInEditZone || isCursorInEditZone()) {
const QMimeData *const clipboard =
QApplication::clipboard()->mimeData();
const QString text = clipboard->text();
if (!text.isNull()) {
textCursor.insertText(text);
}
}
e->accept();
return;
}
int key = e->key();
int shiftMod = e->modifiers() == Qt::ShiftModifier;
// if (history_.isActive() && key != Qt::Key_Up && key != Qt::Key_Down)
// history_.deactivate();
// Force the cursor back to the interactive area
// for all keys except modifiers
if (!isCursorInEditZone() && key != Qt::Key_Control &&
key != Qt::Key_Shift && key != Qt::Key_Alt) {
textCursor.movePosition(QTextCursor::End);
setTextCursor(textCursor);
}
switch (key) {
case Qt::Key_Up:
// Activate the history and move to the 1st matching history item
if (!history_.isActive())
history_.activate(getCommandLine());
if (history_.move(true))
replaceCommandLine(history_.currentValue());
else
QApplication::beep();
e->accept();
break;
case Qt::Key_Down:
if (history_.move(false))
replaceCommandLine(history_.currentValue());
else
QApplication::beep();
e->accept();
case Qt::Key_Left:
if (textCursor.position() > inpos_)
WingCodeEdit::keyPressEvent(e);
else {
QApplication::beep();
e->accept();
}
break;
case Qt::Key_Delete:
e->accept();
if (selectionInEditZone)
cut();
else {
// cursor must be in edit zone
if (textCursor.position() < inpos_)
QApplication::beep();
else
WingCodeEdit::keyPressEvent(e);
}
break;
case Qt::Key_Backspace:
e->accept();
if (selectionInEditZone)
cut();
else {
// cursor must be in edit zone
if (textCursor.position() <= inpos_)
QApplication::beep();
else
WingCodeEdit::keyPressEvent(e);
}
break;
case Qt::Key_Tab:
e->accept();
handleTabKey();
return;
case Qt::Key_Home:
e->accept();
textCursor.setPosition(inpos_, shiftMod ? QTextCursor::KeepAnchor
: QTextCursor::MoveAnchor);
setTextCursor(textCursor);
break;
case Qt::Key_Enter:
case Qt::Key_Return:
e->accept();
handleReturnKey();
break;
case Qt::Key_Escape:
e->accept();
replaceCommandLine(QString());
break;
default:
e->accept();
WingCodeEdit::keyPressEvent(e);
break;
}
}
void QConsoleWidget::contextMenuEvent(QContextMenuEvent *event) {
QMenu *menu = createStandardContextMenu();
QAction *a;
if ((a = menu->findChild<QAction *>("edit-cut")))
a->setEnabled(canCut());
if ((a = menu->findChild<QAction *>("edit-delete")))
a->setEnabled(canCut());
if ((a = menu->findChild<QAction *>("edit-paste")))
a->setEnabled(canPaste());
menu->exec(event->globalPos());
delete menu;
}
bool QConsoleWidget::isSelectionInEditZone() const {
QTextCursor textCursor = this->textCursor();
if (!textCursor.hasSelection())
return false;
int selectionStart = textCursor.selectionStart();
int selectionEnd = textCursor.selectionEnd();
return selectionStart >= inpos_ && selectionEnd >= inpos_;
}
bool QConsoleWidget::isCursorInEditZone() const {
return textCursor().position() >= inpos_;
}
bool QConsoleWidget::canPaste() const {
QTextCursor textCursor = this->textCursor();
if (textCursor.position() < inpos_)
return false;
if (textCursor.anchor() < inpos_)
return false;
return true;
}
void QConsoleWidget::replaceCommandLine(const QString &str) {
// Select the text after the last command prompt ...
QTextCursor textCursor = this->textCursor();
textCursor.movePosition(QTextCursor::End);
textCursor.setPosition(inpos_, QTextCursor::KeepAnchor);
// ... and replace it with new string.
textCursor.insertText(str);
// move to the end of the document
textCursor.movePosition(QTextCursor::End);
setTextCursor(textCursor);
}
void QConsoleWidget::write(const QString &message) {
QTextCharFormat currfmt = currentCharFormat();
QTextCursor tc = textCursor();
if (mode() == Input) {
// in Input mode output messages are inserted
// before the edit block
// get offset of current pos from the end
int editpos = tc.position();
tc.movePosition(QTextCursor::End);
editpos = tc.position() - editpos;
// convert the input pos as relative from the end
inpos_ = tc.position() - inpos_;
// insert block
tc.movePosition(QTextCursor::StartOfBlock);
tc.insertBlock();
tc.movePosition(QTextCursor::PreviousBlock);
tc.insertText(message);
tc.movePosition(QTextCursor::End);
// restore input pos
inpos_ = tc.position() - inpos_;
// restore the edit pos
tc.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, editpos);
setTextCursor(tc);
setCurrentCharFormat(currfmt);
} else {
// in output mode messages are appended
QTextCursor tc1 = tc;
tc1.movePosition(QTextCursor::End);
// check is cursor was not at the end
// (e.g. had been moved per mouse action)
bool needsRestore = tc1.position() != tc.position();
// insert text
setTextCursor(tc1);
textCursor().insertText(message);
ensureCursorVisible();
// restore cursor if needed
if (needsRestore)
setTextCursor(tc);
}
}
/////////////////// QConsoleWidget::History /////////////////////
QConsoleWidget::History QConsoleWidget::history_;
QConsoleWidget::History::History(void)
: pos_(0), active_(false), maxsize_(10000) {}
QConsoleWidget::History::~History(void) {}
void QConsoleWidget::History::add(const QString &str) {
active_ = false;
// if (strings_.contains(str)) return;
if (strings_.size() == maxsize_)
strings_.pop_back();
strings_.push_front(str);
}
void QConsoleWidget::History::activate(const QString &tk) {
active_ = true;
token_ = tk;
pos_ = -1;
}
bool QConsoleWidget::History::move(bool dir) {
if (active_) {
int next = indexOf(dir, pos_);
if (pos_ != next) {
pos_ = next;
return true;
} else
return false;
} else
return false;
}
int QConsoleWidget::History::indexOf(bool dir, int from) const {
int i = from, to = from;
if (dir) {
while (i < strings_.size() - 1) {
const QString &si = strings_.at(++i);
if (si.startsWith(token_)) {
return i;
}
}
} else {
while (i > 0) {
const QString &si = strings_.at(--i);
if (si.startsWith(token_)) {
return i;
}
}
return -1;
}
return to;
}
/////////////////// Stream manipulators /////////////////////
QTextStream &waitForInput(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d)
d->waitForReadyRead(-1);
return s;
}
QTextStream &inputMode(QTextStream &s) {
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
if (d && d->widget())
d->widget()->setMode(QConsoleWidget::Input);
return s;
}
QTextStream &outChannel(QTextStream &s) { return s; }

View File

@ -1,102 +1,87 @@
#ifndef _QCONSOLEWIDGET_H_
#define _QCONSOLEWIDGET_H_
#include <QIODevice>
#include <QTextCharFormat>
#include <QTextStream>
#include "qeditor.h"
class QConsoleIODevice;
class QConsoleWidget : public QEditor {
Q_OBJECT
public:
struct History {
QStringList strings_;
int pos_;
QString token_;
bool active_;
int maxsize_;
History(void);
~History(void);
void add(const QString &str);
const QString &currentValue() const {
return pos_ == -1 ? token_ : strings_.at(pos_);
}
void activate(const QString &tk = QString());
void deactivate() { active_ = false; }
bool isActive() const { return active_; }
bool move(bool dir);
int indexOf(bool dir, int from) const;
};
public:
enum ConsoleMode { Input, Output };
Q_ENUM(ConsoleMode)
explicit QConsoleWidget(QWidget *parent = nullptr);
virtual ~QConsoleWidget();
ConsoleMode mode() const { return mode_; }
void setMode(ConsoleMode m);
QIODevice *device() const { return (QIODevice *)iodevice_; }
virtual QSize sizeHint() const override { return QSize(600, 400); }
// write a formatted message to the console
void write(const QString &message, const QString &sfmtID = {}) override;
static History &history() { return history_; }
// get the current command line
QString getCommandLine();
public slots:
virtual void paste() override;
// write to StandardOutput
void writeStdOut(const QString &s);
// write to StandardError
void writeStdErr(const QString &s);
signals:
// fired when user hits the return key
void consoleCommand(const QString &code);
// fired when user enters a Ctrl-Q
void abortEvaluation();
protected:
bool canPaste() const;
bool canCut() const { return isSelectionInEditZone(); }
void handleReturnKey();
void keyPressEvent(QKeyEvent *e) override;
// Returns true if there is a selection in edit zone
bool isSelectionInEditZone() const;
// Returns true if cursor is in edit zone
bool isCursorInEditZone() const;
// replace the command line
void replaceCommandLine(const QString &str);
// QEditor interface
public slots:
virtual void cut() override;
private:
static History history_;
ConsoleMode mode_;
QDocumentCursor inpos_;
QString currentMultiLineCode_;
QConsoleIODevice *iodevice_;
};
QTextStream &waitForInput(QTextStream &s);
QTextStream &inputMode(QTextStream &s);
QTextStream &outChannel(QTextStream &s);
QTextStream &errChannel(QTextStream &s);
#endif
#ifndef _QCONSOLEWIDGET_H_
#define _QCONSOLEWIDGET_H_
#include "WingCodeEdit/wingcodeedit.h"
#include <QTextStream>
class QConsoleIODevice;
class QConsoleWidget : public WingCodeEdit {
Q_OBJECT
public:
struct History {
QStringList strings_;
int pos_;
QString token_;
bool active_;
int maxsize_;
History(void);
~History(void);
void add(const QString &str);
const QString &currentValue() const {
return pos_ == -1 ? token_ : strings_.at(pos_);
}
void activate(const QString &tk = QString());
void deactivate() { active_ = false; }
bool isActive() const { return active_; }
bool move(bool dir);
int indexOf(bool dir, int from) const;
};
public:
enum ConsoleMode { Input, Output };
Q_ENUM(ConsoleMode)
QConsoleWidget(QWidget *parent = 0);
~QConsoleWidget();
ConsoleMode mode() const { return mode_; }
void setMode(ConsoleMode m);
QIODevice *device() const { return (QIODevice *)iodevice_; }
virtual QSize sizeHint() const override { return QSize(600, 400); }
// write a formatted message to the console
void write(const QString &message);
// get the current command line
QString getCommandLine();
static History &history();
signals:
// fired when user hits the return key
void consoleCommand(const QString &code);
// fired when user enters a Ctrl-Q
void abortEvaluation();
protected:
bool canPaste() const;
bool canCut() const { return isSelectionInEditZone(); }
void handleReturnKey();
void handleTabKey();
// reimp QPlainTextEdit functions
void keyPressEvent(QKeyEvent *e) override;
void contextMenuEvent(QContextMenuEvent *event) override;
// Returns true if there is a selection in edit zone
bool isSelectionInEditZone() const;
// Returns true if cursor is in edit zone
bool isCursorInEditZone() const;
// replace the command line
void replaceCommandLine(const QString &str);
private:
ConsoleMode mode_;
int inpos_;
QString currentMultiLineCode_;
QConsoleIODevice *iodevice_;
static History history_;
};
QTextStream &waitForInput(QTextStream &s);
QTextStream &inputMode(QTextStream &s);
QTextStream &outChannel(QTextStream &s);
#endif

@ -1 +1 @@
Subproject commit f9becd7ca224f32bc8d86ca09d697e2455a9d97e
Subproject commit 7cdf84f7c23256032f9bbae44e6a47b439ed66c8

1
3rdparty/WingCodeEdit vendored Submodule

@ -0,0 +1 @@
Subproject commit 02519a8ab63c741c06191a93782aa9e2aa2e1a3c

2
3rdparty/cpptrace vendored

@ -1 +1 @@
Subproject commit c37b5ed7364f4fc1c58e92d13399cd04656e6572
Subproject commit fac4d08fd0473a94d99c143c6ba6b1f9e0bd7636

View File

@ -1,150 +0,0 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveBitFields: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
- Regex: '.*'
Priority: 1
SortPriority: 0
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
...

View File

@ -1,89 +0,0 @@
cmake_minimum_required(VERSION 3.6)
project(QCodeEditor2 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Gui PrintSupport Xml)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Gui PrintSupport
Xml)
add_definitions(-DQNFA_BUILD)
set(DOCUMENT_SRC
lib/document/qdocumentline_p.h
lib/document/qdocumentbuffer.h
lib/document/qdocumentcommand.h
lib/document/qdocumentline.h
lib/document/qdocumentcursor.h
lib/document/qdocumentcursor_p.h
lib/document/qdocument_p.h
lib/document/qdocument.h
lib/document/qdocumentbuffer.cpp
lib/document/qdocumentline.cpp
lib/document/qdocumentcursor.cpp
lib/document/qdocumentcommand.cpp
lib/document/qdocument.cpp)
set(WIDGETS_SRC
lib/widgets/qfoldpanel.cpp
lib/widgets/qfoldpanel.h
lib/widgets/qlinechangepanel.cpp
lib/widgets/qlinechangepanel.h
lib/widgets/qlinemarkpanel.cpp
lib/widgets/qlinemarkpanel.h
lib/widgets/qlinenumberpanel.cpp
lib/widgets/qlinenumberpanel.h
lib/widgets/qpanel.cpp
lib/widgets/qpanel.h)
set(QNFA_SRC
lib/qnfa/light_vector.h lib/qnfa/qnfadefinition.h lib/qnfa/qnfa.h
lib/qnfa/xml2qnfa.cpp lib/qnfa/qnfa.cpp lib/qnfa/qnfadefinition.cpp)
set(SOURCE_FILES
lib/qce-config.h
lib/qcodecompletionengine.h
lib/qcodeedit.h
lib/qeditor.h
lib/qeditsession.h
lib/qformat.h
lib/qformatfactory.h
lib/qformatscheme.h
lib/qlanguagedefinition.h
lib/qlanguagefactory.h
lib/qlinemarksinfocenter.h
lib/qpanellayout.h
lib/qreliablefilewatch.h
lib/qcodecompletionengine.cpp
lib/qcodeedit.cpp
lib/qeditor.cpp
lib/qeditsession.cpp
lib/qformatscheme.cpp
lib/qlanguagedefinition.cpp
lib/qlanguagefactory.cpp
lib/qlinemarksinfocenter.cpp
lib/qpanellayout.cpp
lib/qreliablefilewatch.cpp)
add_library(QCodeEditor2 STATIC ${SOURCE_FILES} ${DOCUMENT_SRC} ${WIDGETS_SRC}
${QNFA_SRC})
target_compile_definitions(QCodeEditor2 PUBLIC _QCODE_EDIT_BUILD_
_QCODE_EDIT_EMBED_)
target_include_directories(
QCodeEditor2
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/lib"
"${CMAKE_CURRENT_SOURCE_DIR}/lib/document"
"${CMAKE_CURRENT_SOURCE_DIR}/lib/widgets"
"${CMAKE_CURRENT_SOURCE_DIR}/lib/qnfa"
"${CMAKE_CURRENT_SOURCE_DIR}/lib/snippets")
target_link_libraries(
QCodeEditor2
PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Xml Qt${QT_VERSION_MAJOR}::PrintSupport)

View File

@ -1,223 +0,0 @@
# Doxyfile 1.4.6
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = QCodeEdit
PROJECT_NUMBER = 2.2
OUTPUT_DIRECTORY = doc
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF =
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
BUILTIN_STL_SUPPORT = NO
DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = NO
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = qce.dox lib
FILE_PATTERNS = *.h *.cpp *.c *.cxx *.cc *.hpp *.hxx *.hh *.dox
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH = .
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = NO
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
HIDE_UNDOC_RELATIONS = NO
HAVE_DOT = YES
CLASS_GRAPH = YES
COLLABORATION_GRAPH = NO
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = NO
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO

View File

@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -1,175 +0,0 @@
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
QCodeEdit, copyright (c) 2006-2009 Luc Bruant aka fullmetalcoder,
is a free and open source software
QCodeEdit sources are part of Edyuk and are thus available under GNU General Public
License version 3 (GPL v3), as published by the Free Software Foundation.
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
QCodeEdit is a project aiming at the creation of a flexible and powerful text
editing framework for Qt4. It has started as a sub-project of Edyuk, copyright (c)
Luc Bruant, a free and open source IDE. As it proved successful it is also
released as a standalone library to make it easy for everyone to use such
a framework within other apps without having to reinvent the wheel.
Writing closed source applications with QCodeEdit is possible after buying a
proper license. For more informations about pricing and licensing conditions
please contact the author directly <non.deterministic.finite.organism@gmail.com>
Note that you will still need a Qt commercial license for that or, starting with
Qt 4.5, a LGPL one.
QCodeEdit depends on Qt 4.3 or newer, copyright (c) Nokia Corporation, which can
be downloaded at : ftp://ftp.trolltech.com/qt/sources
More information about Qt and Qt Software (formerly Trolltech) :
http://www.qtsoftware.com
Hoping you'll like it.
The author would like to thank all the people who contributed to QCodeEdit in various ways :
* testing, reporting bugs, making suggestions :
Jeremy Sonander, from Saros Inc
Phil Martinot
Benito van der Zander
Ulrich Van Den Hekke
Boris Barbulovski
* contributing patches :
Jerome Vizcaino
Benito van der Zander
Ulrich Van Den Hekke
Boris Barbulovski
* funding (by buying commercial licenses) :
Saros Inc
Movimento SE
* spreading the word :
Johan Thelin (posted a blog post that appeared on PlanetKDE)
(If you have been forgotten send an email to the author and the list will be updated)
IMPORTANT : If you encounter any sort of troubles trying to build or run QCodeEdit
please send a bug report with as many details as possible (including but not limited
to : OS, Qt version, compiler, QCodeEdit version, compile log, backtrace, ...) to the
team using either of these :
* staff@qcodeedit.edyuk.org
* Edyuk task tracker on Sf.net : http://sf.net/projects/edyuk
* Edyuk webissues server (needs a WebIssues client) : http://edyuk.org/webissues/
- login : anonymous
- password : anonymous
* QtCentre dedicated thread in Qt Software section : http://www.qtcentre.org/forum
In case you don't understand, blocks of text enclosed between lines of minus signs are
shell commands. The dollar signs just stand for command prompt.
>>> Building :
------------------------------------------------------------------------------------------
$ qmake
$ make
------------------------------------------------------------------------------------------
This will build the library and the example. You may want to alter the build mode to force
either debug or release. If so just pass the mode you want to make, e.g. :
------------------------------------------------------------------------------------------
$ make release
------------------------------------------------------------------------------------------
or
------------------------------------------------------------------------------------------
$ make debug
------------------------------------------------------------------------------------------
Finally, with admins rights/root privilegdes, you can install QCodeEdit so as to be able
to use it simply :
------------------------------------------------------------------------------------------
$ qmake
$ make install
------------------------------------------------------------------------------------------
NB : the extra "qmake" is NEEDED to ensure that binaries will be located and copied properly.
NB 2 : Only the "make install" command requires root priviledges, "qmake" can and should
always be run as normal user.
NB 3 : Apart from libs and headers, QCodeEdit also provides a .prf file which makes it
easier to use the lib in another project. Under non-Unix platforms it is recommended to
copy the files manually (and possibly edit them to fit your needs).
>>> Using within an app :
To have one of your app building with QCodeEdit just add the following line to your project
file (this won't work if you have not installed QCodeEdit as described above....) :
CONFIG += qcodeedit
If you did not install QCodeEdit as described above you will have to either update the file
qcodeedit.prf or inspect it to determine what project variables need to be adjusted and how.
Then, add proper headers in your sources and start coding. :D
>>> Testing :
A very basic example is provided which open a list of files passed as parameters
and try to highlight them according to their file extension. Only a few language
definitions are provided :
* C++ (with Doxygen support)
* PHP
* XML
* Doxygen alone (for .dox files)
* QMake project files
* Python
* QtScript/JavaScript
* C# (WIP)
* Lua (WIP)
* LaTex (WIP)
* BibTex (WIP)
If you write a new one for your own use (or modify an existing one to suit you needs)
please consider contributing it back to the project.
------------------------------------------------------------------------------------------
$ example/example [file]
------------------------------------------------------------------------------------------
Note : on Unix system it is recommended to use the script due to the need of setting
the LD_LIBRARY_PATH variable properly :
------------------------------------------------------------------------------------------
$ ./example.sh [file]
------------------------------------------------------------------------------------------
NB : [file] stands for a filename. If omitted a minimal string will be loaded and
considered as C++ source code
>>> Generating documentation [needs Doxygen : http://www.doxygen.org] :
------------------------------------------------------------------------------------------
$ doxygen
------------------------------------------------------------------------------------------
NB :
* This will create the documentation in the doc folder. Just open doc/html/index.html
>>> Fetching bleeding edge sources [needs Subversion : http://subversion.tigris.org] :
------------------------------------------------------------------------------------------
$ svn co http://edyuk.svn.sf.net/svnroot/edyuk/trunk/3rdparty/qcodeedit2
------------------------------------------------------------------------------------------
NB : Using a graphical client this command extends to a "checkout" action using the above
repository URL.

File diff suppressed because it is too large Load Diff

View File

@ -1,272 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QDOCUMENT_H_
#define _QDOCUMENT_H_
#include "qce-config.h"
/*!
\file qdocument.h
\brief Definition of the QDocument class
\defgroup document Document related classes
*/
#include <QList>
#include <QVector>
#include <QMetaType>
#include <QObject>
#include <QPalette>
class QFont;
class QRect;
class QPrinter;
class QDateTime;
class QFormatScheme;
class QLanguageDefinition;
struct QCE_EXPORT QDocumentSelection {
int start, end;
int startLine, endLine;
};
class QDocumentLine;
class QDocumentCursor;
class QDocumentPrivate;
class QDocumentCommand;
class QDocumentLineHandle;
class QDocumentCursorHandle;
typedef QVector<QDocumentLineHandle *>::iterator QDocumentIterator;
typedef QVector<QDocumentLineHandle *>::const_iterator QDocumentConstIterator;
Q_DECLARE_METATYPE(QDocumentIterator)
Q_DECLARE_METATYPE(QDocumentConstIterator)
class QCE_EXPORT QDocument : public QObject {
friend class QMatcher;
friend class QDocumentPrivate;
friend class QDocumentCommand;
Q_OBJECT
public:
struct PaintContext {
int width;
int height;
int xoffset;
int yoffset;
QPalette palette;
bool blinkingCursor;
bool fillCursorRect;
QList<QDocumentCursorHandle *> extra;
QList<QDocumentCursorHandle *> cursors;
QList<QDocumentSelection> selections;
};
enum LineEnding {
Conservative,
Local,
Unix,
Windows,
Mac, // backward compat only : use OldMac instead (more
// self-explanatory)
OldMac = Mac
};
enum TextProcessing {
RemoveTrailingWS = 1,
PreserveIndent = 2,
RestoreTrailingIndent = 4
};
enum WhiteSpaceFlag {
ShowNone = 0x00,
ShowTrailing = 0x01,
ShowLeading = 0x02,
ShowTabs = 0x04
};
Q_DECLARE_FLAGS(WhiteSpaceMode, WhiteSpaceFlag)
explicit QDocument(QObject *p = nullptr);
virtual ~QDocument();
QStringList textLines(int mode) const;
QStringList textLines(bool removeTrailing = false,
bool preserveIndent = true) const;
QString text(int mode) const;
QString text(bool removeTrailing = false, bool preserveIndent = true) const;
void setText(const QString &s);
void startChunkLoading();
void stopChunkLoading();
void addChunk(const QString &txt);
LineEnding lineEnding() const;
LineEnding originalLineEnding() const;
void setLineEnding(LineEnding le);
QString lineEndingString() const;
QDateTime lastModified() const;
void setLastModified(const QDateTime &d);
bool canUndo() const;
bool canRedo() const;
int width() const;
int height() const;
int widthConstraint() const;
int lines() const;
int lineCount() const;
int visualLines() const;
int visualLineCount() const;
int visualLineNumber(int textLineNumber) const;
int textLineNumber(int visualLineNumber) const;
int y(int line) const;
int lineNumber(int ypos, int *wrap = 0) const;
int y(const QDocumentLine &l) const;
QRect lineRect(int line) const;
QRect lineRect(const QDocumentLine &l) const;
QDocumentCursor *editCursor() const;
void setEditCursor(QDocumentCursor *c);
QLanguageDefinition *languageDefinition() const;
void setLanguageDefinition(QLanguageDefinition *l);
int maxMarksPerLine() const;
int findNextMark(int id, int from = 0, int until = -1) const;
int findPreviousMark(int id, int from = -1, int until = 0) const;
QDocumentLine lineAt(const QPoint &p) const;
void cursorForDocumentPosition(const QPoint &p, int &line,
int &column) const;
QDocumentCursor cursorAt(const QPoint &p) const;
QDocumentLine line(int line) const;
QDocumentLine line(QDocumentConstIterator iterator) const;
QDocumentCursor cursor(int line, int column = 0) const;
QDocumentLine findLine(int &position) const;
bool isLineModified(const QDocumentLine &l) const;
bool hasLineEverBeenModified(const QDocumentLine &l) const;
virtual void draw(QPainter *p, PaintContext &cxt);
void execute(QDocumentCommand *cmd);
inline QDocumentPrivate *impl() { return m_impl; }
QDocumentConstIterator begin() const;
QDocumentConstIterator end() const;
QDocumentConstIterator iterator(int ln) const;
QDocumentConstIterator iterator(const QDocumentLine &l) const;
void beginMacro();
void endMacro();
QFormatScheme *formatScheme() const;
void setFormatScheme(QFormatScheme *f);
int lineSpacing() const;
int getNextGroupId();
void releaseGroupId(int groupId);
void clearMatches(int groupId);
void flushMatches(int groupId);
void addMatch(int groupId, int line, int pos, int len, int format);
QFont font();
void setFont(const QFont &f);
const QFontMetrics &fontMetrics();
int tabStop();
void setTabStop(int n);
WhiteSpaceMode showSpaces();
void setShowSpaces(WhiteSpaceMode y);
static QFormatScheme *defaultFormatScheme();
static void setDefaultFormatScheme(QFormatScheme *f);
static QFormatScheme *formatFactory();
static void setFormatFactory(QFormatScheme *f);
static int screenLength(const QChar *d, int l, int tabStop);
static QString screenable(const QChar *d, int l, int tabStop);
inline void markViewDirty() { emit formatsChanged(); }
bool isClean() const;
public slots:
void clear();
void undo();
void redo();
void setClean();
void highlight();
void print(QPrinter *p);
void clearWidthConstraint();
void setWidthConstraint(int width);
signals:
void cleanChanged(bool m);
void undoAvailable(bool y);
void redoAvailable(bool y);
void formatsChanged();
void contentsChanged();
void formatsChange(int line, int lines);
void contentsChange(int line, int lines);
void widthChanged(int width);
void heightChanged(int height);
void sizeChanged(const QSize &s);
void lineCountChanged(int n);
void visualLineCountChanged(int n);
void lineDeleted(QDocumentLineHandle *h);
void markChanged(QDocumentLineHandle *l, int m, bool on);
void lineEndingChanged(int lineEnding);
void fontChanged(const QFont &font);
private:
QString m_leftOver;
QDocumentPrivate *m_impl;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QDocument::WhiteSpaceMode)
#endif

View File

@ -1,226 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QDOCUMENT_P_H_
#define _QDOCUMENT_P_H_
#include "qce-config.h"
/*!
\file qdocument_p.h
\brief Definition of the private document API
*/
#include "qdocument.h"
#include "qdocumentcursor.h"
#include "qdocumentline.h"
#include <QDateTime>
#include <QFont>
#include <QFontMetrics>
#include <QHash>
#include <QQueue>
#include <QStack>
#include <QStringList>
#include <QUndoCommand>
#include <QUndoStack>
class QDocument;
class QDocumentBuffer;
class QDocumentPrivate;
class QDocumentCommand;
class QDocumentCommandBlock;
class QLanguageDefinition;
Q_DECLARE_TYPEINFO(QDocumentSelection, Q_PRIMITIVE_TYPE);
#include "qdocumentline_p.h"
#include "qdocumentcursor_p.h"
class QCE_EXPORT QDocumentPrivate {
friend class QEditConfig;
friend class QEditor;
friend class QDocument;
friend class QDocumentCommand;
friend class QDocumentLineHandle;
friend class QDocumentCursorHandle;
public:
QDocumentPrivate(QDocument *d);
~QDocumentPrivate();
void execute(QDocumentCommand *cmd);
void draw(QPainter *p, QDocument::PaintContext &cxt);
QDocumentLineHandle *lineForPosition(int position) const;
int position(const QDocumentLineHandle *l) const;
QDocumentLineHandle *at(int line) const;
int indexOf(const QDocumentLineHandle *l) const;
QDocumentIterator index(const QDocumentLineHandle *l);
QDocumentConstIterator index(const QDocumentLineHandle *l) const;
QDocumentLineHandle *next(const QDocumentLineHandle *l) const;
QDocumentLineHandle *previous(const QDocumentLineHandle *l) const;
void adjustWidth(int l);
// int checkWidth(QDocumentLineHandle *l, int w);
// int checkWidth(QDocumentLineHandle *l, const QString& s);
void setWidth();
void setHeight();
void setFont(const QFont &f);
void beginChangeBlock();
void endChangeBlock();
inline int maxMarksPerLine() const { return m_maxMarksPerLine; }
inline bool hasMarks() const { return m_marks.count(); }
QList<int> marks(QDocumentLineHandle *h) const;
void addMark(QDocumentLineHandle *h, int mid);
void toggleMark(QDocumentLineHandle *h, int mid);
void removeMark(QDocumentLineHandle *h, int mid);
int findNextMark(int id, int from = 0, int until = -1);
int findPreviousMark(int id, int from = -1, int until = 0);
int getNextGroupId();
void releaseGroupId(int groupId);
void clearMatches(int gid);
void flushMatches(int gid);
void addMatch(int gid, int line, int pos, int len, int format);
void emitFormatsChange(int line, int lines);
void emitContentsChange(int line, int lines);
int visualLine(int textLine) const;
int textLine(int visualLine, int *wrap = 0) const;
void hideEvent(int line, int count);
void showEvent(int line, int count);
void setWidth(int width);
void emitContentsChanged();
void emitLineDeleted(QDocumentLineHandle *h);
void emitMarkChanged(QDocumentLineHandle *l, int m, bool on);
inline QDocumentIterator begin() { return m_lines.begin(); }
inline QDocumentIterator end() { return m_lines.end(); }
inline QDocumentConstIterator constBegin() const {
return m_lines.constBegin();
}
inline QDocumentConstIterator constEnd() const {
return m_lines.constEnd();
}
protected:
void updateHidden(int line, int count);
void updateWrapped(int line, int count);
void insertLines(int after, const QList<QDocumentLineHandle *> &l);
void removeLines(int after, int n);
void emitWidthChanged();
void emitHeightChanged();
void updateFormatCache();
void setFormatScheme(QFormatScheme *f);
void tunePainter(QPainter *p, int fid);
private:
QDocument *m_doc;
QUndoStack m_commands;
QDocumentCursor *m_editCursor;
bool m_suspend, m_deleting;
QQueue<QPair<int, int>> m_notifications;
QMap<int, int> m_hidden;
QMap<int, int> m_wrapped;
QVector<QPair<QDocumentLineHandle *, int>> m_largest;
struct Match {
int line;
QFormatRange range;
QDocumentLineHandle *h = nullptr;
};
struct MatchList : QList<Match> {
MatchList() : index(0) {}
int index;
};
int m_lastGroupId;
QList<int> m_freeGroupIds;
QHash<int, MatchList> m_matches;
bool m_constrained;
int m_width, m_height;
int m_tabStop;
QFont m_font;
bool m_fixedPitch;
QFontMetrics m_fontMetrics;
int m_leftMargin;
QDocument::WhiteSpaceMode m_showSpaces;
int m_lineHeight;
int m_lineSpacing;
int m_spaceWidth;
int m_ascent;
int m_descent;
int m_leading;
int m_wrapMargin;
static QFont m_defaultFont;
static int m_defaultTabStop;
static QDocument::LineEnding m_defaultLineEnding;
static QDocument::WhiteSpaceMode m_defaultShowSpaces;
QFormatScheme *m_formatScheme;
QLanguageDefinition *m_language;
static QFormatScheme *m_defaultFormatScheme;
QVector<QFont> m_fonts;
static QList<QDocumentPrivate *> m_documents;
int m_maxMarksPerLine;
QHash<QDocumentLineHandle *, QList<int>> m_marks;
QHash<QDocumentLineHandle *, QPair<int, int>> m_status;
int _nix, _dos, _mac;
QString m_lineEndingString;
QDocument::LineEnding m_lineEnding;
QDateTime m_lastModified;
QDocumentBuffer *m_buffer;
QVector<QDocumentLineHandle *> m_lines;
};
#endif

View File

@ -1,355 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qdocumentbuffer.h"
/*
Notes on design :
The idea is to fragment the storage to workaround the issue of Qt
containers alocation model (too much memory usage when number of items
grow) and provide faster modification of the content.
The number one goal is to keep lookup by index as fast possible to avoid
significant impact on document iteration/drawing speed
for such a storage to be useful the block size may not be fixed but
instead must be kept around an "average" value.
*/
QDocumentBuffer::QDocumentBuffer()
: m_safetyRoom(10), m_optimalSize(1000), m_forkThresold(1500),
m_mergeThresold(100) {}
QDocumentBuffer::~QDocumentBuffer() { qDeleteAll(m_blocks); }
// for loading
void QDocumentBuffer::appendLine(QDocumentLineHandle *l) {
Block *b = m_blocks.last();
if (b->size() >= m_optimalSize) {
b = new Block();
m_blocks << b;
}
b->lines.append(l);
}
int QDocumentBuffer::blockForLine(int index) const {
// TODO : binary search?
for (int i = 0; i < m_blocks.count(); ++i) {
if (index < m_blocks.at(i)->end)
return i;
}
// too high...
return -1;
}
QDocumentLineHandle *QDocumentBuffer::at(int index) const {
int blockIndex = blockForLine(index);
return blockIndex != -1 ? m_blocks.at(blockIndex)->at(index) : 0;
}
void QDocumentBuffer::insertLine(int index, QDocumentLineHandle *l) {
int blockIndex = blockForLine(index);
if (blockIndex == -1) {
qWarning("cannot insert line at pos %i", index);
return;
}
Block *b = m_blocks.at(blockIndex);
if ((b->size() + 1) >= m_forkThresold) {
// split block
int bounds = b->start + m_optimalSize;
Block *nb = new Block(bounds);
nb->insert(bounds, b->lines.constData() + m_optimalSize,
b->size() - m_optimalSize);
nb->lines.append(l);
nb->end = bounds + nb->size();
m_blocks.insert(blockIndex + 1, nb);
b->lines.resize(m_optimalSize);
b->end = bounds;
blockIndex += 2;
} else {
b->insert(index, l);
}
// update block boundaries
while (blockIndex < m_blocks.count()) {
b = m_blocks.at(blockIndex);
++b->start;
++b->end;
}
}
void QDocumentBuffer::removeLine(int index) {
int blockIndex = blockForLine(index);
if (blockIndex == -1) {
qWarning("cannot remove line at pos %i", index);
return;
}
Block *b = m_blocks.at(blockIndex);
b->remove(index);
--b->end;
// if block too small, merge it with blocks around?
if (!b->size()) {
// remove empty block
m_blocks.remove(blockIndex);
delete b;
} else if (b->size() < m_mergeThresold) {
// "merge" block with its neighbors
int n = b->size();
n += qMin(1, n / m_safetyRoom);
int roomPrev =
blockIndex ? m_forkThresold - m_blocks.at(blockIndex - 1)->size()
: 0;
int roomNext =
blockIndex + 1 < m_blocks.count()
? m_forkThresold - m_blocks.at(blockIndex + 1)->size()
: 0;
bool maxPrev = false;
int maxRoom = 0, minRoom = 0;
Block *moreRoom = 0, *lessRoom = 0;
if (roomPrev > roomNext) {
maxPrev = true;
maxRoom = roomPrev;
moreRoom = m_blocks.at(blockIndex - 1);
minRoom = roomNext;
if (roomNext)
lessRoom = m_blocks.at(blockIndex + 1);
} else {
maxRoom = roomNext;
if (roomNext)
moreRoom = m_blocks.at(blockIndex + 1);
minRoom = roomPrev;
if (roomPrev)
lessRoom = m_blocks.at(blockIndex - 1);
}
if (maxRoom > n) {
// put everything in one
moreRoom->lines << b->lines;
moreRoom->end += b->size();
m_blocks.remove(blockIndex);
delete b;
} else if ((maxRoom + minRoom) > n) {
// try to alloc evenly
int part = b->size() * maxRoom / (maxRoom + minRoom);
if (maxPrev) {
moreRoom->append(b->lines.constData(), part);
lessRoom->prepend(b->lines.constData() + part,
b->size() - part);
} else {
moreRoom->prepend(b->lines.constData(), part);
lessRoom->append(b->lines.constData() + part, b->size() - part);
}
moreRoom->end += part;
lessRoom->end += b->size() - part;
m_blocks.remove(blockIndex);
delete b;
} else {
// cannot merge simply... let's forget about it for now as it is not
// vital
++blockIndex;
}
} else {
++blockIndex;
}
// update block boundaries
while (blockIndex < m_blocks.count()) {
b = m_blocks.at(blockIndex);
--b->start;
--b->end;
}
}
void QDocumentBuffer::insertLines(int after,
const QVector<QDocumentLineHandle *> &l) {
int index = after + 1;
int blockIndex = blockForLine(index);
if (blockIndex == -1) {
qWarning("cannot insert line at pos %i", index);
return;
}
int n = l.count();
Block *b = m_blocks.at(blockIndex);
if ((b->size() + 1) >= m_forkThresold) {
// split block
int bounds = b->start + m_optimalSize;
Block *nb = new Block(bounds);
nb->insert(bounds, b->lines.constData() + m_optimalSize,
b->size() - m_optimalSize);
nb->append(l.constData(), n);
nb->end = bounds + nb->size();
m_blocks.insert(blockIndex + 1, nb);
b->lines.resize(m_optimalSize);
b->end = bounds;
blockIndex += 2;
} else {
b->insert(index, l.constData(), n);
}
// update block boundaries
while (blockIndex < m_blocks.count()) {
b = m_blocks.at(blockIndex);
b->start += n;
b->end += n;
}
}
void QDocumentBuffer::removeLines(int after, int n) {
int index = after + 1;
int blockIndex = blockForLine(index);
if (blockIndex == -1) {
qWarning("cannot remove line at pos %i", index);
return;
}
// update block boundaries
int count = n;
Block *b = m_blocks.at(blockIndex);
while (count > 0) {
int room = b->end - index;
int toRem = qMin(room, count);
b->remove(index, toRem);
b->end -= toRem;
count -= toRem;
if (!b->size()) {
m_blocks.remove(blockIndex);
delete b;
} else {
++blockIndex;
}
if (blockIndex >= m_blocks.count())
break;
b = m_blocks.at(blockIndex);
b->start -= toRem;
}
if (index) {
qWarning("Troubles in line removal");
}
if (b->size() < m_mergeThresold) {
// "merge" block with its neighbors
int sz = b->size();
sz += qMin(1, sz / m_safetyRoom);
int roomPrev =
blockIndex ? m_forkThresold - m_blocks.at(blockIndex - 1)->size()
: 0;
int roomNext =
blockIndex + 1 < m_blocks.count()
? m_forkThresold - m_blocks.at(blockIndex + 1)->size()
: 0;
bool maxPrev = false;
int maxRoom = 0, minRoom = 0;
Block *moreRoom = 0, *lessRoom = 0;
if (roomPrev > roomNext) {
maxPrev = true;
maxRoom = roomPrev;
moreRoom = m_blocks.at(blockIndex - 1);
minRoom = roomNext;
if (roomNext)
lessRoom = m_blocks.at(blockIndex + 1);
} else {
maxRoom = roomNext;
if (roomNext)
moreRoom = m_blocks.at(blockIndex + 1);
minRoom = roomPrev;
if (roomPrev)
lessRoom = m_blocks.at(blockIndex - 1);
}
if (maxRoom > sz) {
// put everything in one
moreRoom->lines << b->lines;
moreRoom->end += b->size();
m_blocks.remove(blockIndex);
delete b;
} else if ((maxRoom + minRoom) > sz) {
// try to alloc evenly
int part = b->size() * maxRoom / (maxRoom + minRoom);
moreRoom->append(b->lines.constData(), part);
moreRoom->end += part;
lessRoom->end += b->size() - part;
lessRoom->append(b->lines.constData() + part, b->size() - part);
m_blocks.remove(blockIndex);
delete b;
} else {
// cannot merge simply... let's forget about it for now as it is not
// vital
++blockIndex;
}
} else {
++blockIndex;
}
// update block boundaries
while (blockIndex < m_blocks.count()) {
b = m_blocks.at(blockIndex);
b->start -= n;
b->end -= n;
}
}

View File

@ -1,149 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QDOCUMENT_BUFFER_H_
#define _QDOCUMENT_BUFFER_H_
#include "qce-config.h"
#include <QVector>
#include "qdocumentline_p.h"
class QDocumentLineHandle;
class QCE_EXPORT QDocumentBuffer {
friend class QDocumentLineHandle;
public:
class iterator {
public:
iterator(const iterator &i);
bool atEnd() const;
int lineNumber() const;
QDocumentLineHandle *lineHandle() const;
void move(int numLines);
protected:
iterator(QDocumentBuffer *buffer, int block, int line);
private:
int m_block;
int m_line;
QDocumentBuffer *m_buffer;
};
QDocumentBuffer();
~QDocumentBuffer();
QDocumentLineHandle *at(int index) const;
void appendLine(QDocumentLineHandle *l);
void insertLine(int index, QDocumentLineHandle *l);
void removeLine(int index);
void insertLines(int after, const QVector<QDocumentLineHandle *> &l);
void removeLines(int after, int n);
private:
static void cleanHelper(QVector<QDocumentLineHandle *> &l) {
foreach (QDocumentLineHandle *h, l)
h->deref();
}
struct Block {
inline Block() : start(-1), end(-1) {}
inline Block(int line) : start(line), end(line) {}
~Block() { cleanHelper(lines); }
inline void move(int numLines) {
start += numLines;
end += numLines;
}
inline int size() const { return lines.count(); }
inline QDocumentLineHandle *at(int index) const {
return lines.at(index - start);
}
inline void append(QDocumentLineHandle *h) { lines.append(h); }
inline void prepend(QDocumentLineHandle *h) { lines.prepend(h); }
inline void insert(int index, QDocumentLineHandle *h) {
lines.insert(index - start, h);
}
inline void insert(int index, const QDocumentLineHandle *const *l,
int n) {
QDocumentLineHandle **d = const_cast<QDocumentLineHandle **>(l);
int i = index - start;
lines.insert(i, n, 0);
while (n) {
lines[i++] = *d;
++d;
--n;
}
}
inline void append(const QDocumentLineHandle *const *l, int n) {
QDocumentLineHandle **d = const_cast<QDocumentLineHandle **>(l);
int i = lines.count();
lines.insert(i, n, 0);
while (n) {
lines[i++] = *d;
++d;
--n;
}
}
inline void prepend(const QDocumentLineHandle *const *l, int n) {
QDocumentLineHandle **d = const_cast<QDocumentLineHandle **>(l);
int i = 0;
lines.insert(i, n, 0);
while (n) {
lines[i++] = *d;
++d;
--n;
}
}
inline void remove(int index) { lines.remove(index - start); }
inline void remove(int index, int count) {
lines.remove(index - start, qMin(count, end - index));
}
int start, end;
QVector<QDocumentLineHandle *> lines;
};
int blockForLine(int index) const;
int m_safetyRoom;
int m_optimalSize;
int m_forkThresold;
int m_mergeThresold;
QVector<Block *> m_blocks;
};
#endif // !_QDOCUMENT_BUFFER_H_

View File

@ -1,888 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qdocumentcommand.h"
/*!
\file qdocumentcommand.cpp
\brief Implementation of the QDocumentCommand class and its basic heirs.
*/
#include "qdocument_p.h"
#include "qformatscheme.h"
/*!
\ingroup document
@{
*/
/*!
\class QDocumentCommand
\brief The base class for document editing command
*/
QList<QDocumentCursorHandle *> QDocumentCommand::m_autoUpdated;
/*!
\brief ctor
*/
QDocumentCommand::QDocumentCommand(Command c, QDocument *d, QDocumentCommand *p)
: QUndoCommand(p), m_state(false), m_first(true), m_doc(d), m_redoOffset(0),
m_undoOffset(0), m_silent(false), m_keepAnchor(false), m_command(c),
m_cursor(0) {}
/*!
\brief dtor
*/
QDocumentCommand::~QDocumentCommand() {
if (m_cursor) {
// release the handle
m_cursor->deref();
}
}
/*!
\return command identifier
*/
int QDocumentCommand::id() const { return m_command; }
/*!
\brief Attempts to merge with another command
Command merging is not implemented.
*/
bool QDocumentCommand::mergeWith(const QUndoCommand *) { return false; }
/*!
\brief Redo the command
*/
void QDocumentCommand::redo() { QUndoCommand::redo(); }
/*!
\brief Undo the command
*/
void QDocumentCommand::undo() { QUndoCommand::undo(); }
/*!
\return whether the command is silent
Silent command do not update the editing cursor of the host document.
*/
bool QDocumentCommand::isSilent() const { return m_silent; }
/*!
\brief Set whether the command is silent
*/
void QDocumentCommand::setSilent(bool y) { m_silent = y; }
/*!
\return whether the command preserve selection of the target cursor
When this property is true, cursor adjustement upon command execution
will preserve the anchor of target cursor and only alter its position
thus keeping a selection.
\note This is disabled by default
*/
bool QDocumentCommand::keepAnchor() const { return m_keepAnchor; }
/*!
\brief Set whether the command preserve selection of the target cursor
\note This is disabled by default
*/
void QDocumentCommand::setKeepAnchor(bool y) { m_keepAnchor = y; }
/*!
\brief Set the target cursor
The position of the target cursor is update upon undo() and redo()
*/
void QDocumentCommand::setTargetCursor(QDocumentCursorHandle *h) {
if (m_cursor) {
// release the handle
m_cursor->deref();
}
m_cursor = h;
if (m_cursor) {
// make sure the handle does not get deleted while the command knows it
m_cursor->ref();
}
}
/*!
\brief ?
*/
void QDocumentCommand::setRedoOffset(int off) { m_redoOffset = off; }
/*!
\brief ?
*/
void QDocumentCommand::setUndoOffset(int off) { m_undoOffset = off; }
/*!
\brief Insert some text
\param line target line
\param pos target text position within line
\param s text to insert
This helper method is provided so that subclasses may actually
modify the document contents without using private API.
*/
void QDocumentCommand::insertText(int line, int pos, const QString &s,
const QString &sfmtID) {
if (!m_doc)
return;
QDocumentPrivate *pd = m_doc->impl();
QDocumentLineHandle *h = pd->m_lines.at(line);
if (!h)
return;
h->textBuffer().insert(pos, s);
h->shiftOverlays(pos, s.length());
if (!sfmtID.isEmpty()) {
auto fmt = m_doc->formatScheme();
if (fmt) {
auto id = fmt->id(sfmtID);
if (id) {
QFormatRange over;
over.format = id;
over.offset = pos;
over.length = s.length();
h->addOverlay(over);
}
}
}
pd->adjustWidth(line);
}
/*!
\brief Remove some text
\param line target line
\param pos target text position within line
\param length length of the text to remove
This helper method is provided so that subclasses may actually
modify the document contents without using private API.
*/
void QDocumentCommand::removeText(int line, int pos, int length) {
if (!m_doc)
return;
QDocumentPrivate *pd = m_doc->impl();
QDocumentLineHandle *h = pd->m_lines.at(line);
if (!h || !length)
return;
h->textBuffer().remove(pos, length);
h->shiftOverlays(pos, -length);
pd->adjustWidth(line);
}
/*!
\brief Insert some lines in the host document
\param after where to insert lines (line number)
\param l list of lines to insert
This helper method is provided so that subclasses may actually
modify the document contents without using too much private API
(QDocumentLineHandle is part of the private API...)
*/
void QDocumentCommand::insertLines(int after,
const QList<QDocumentLineHandle *> &l) {
if (l.isEmpty() || !m_doc->impl()->at(after))
return;
m_doc->impl()->insertLines(after, l);
}
void QDocumentCommand::updateCursorsOnInsertion(int line, int column,
int prefixLength, int numLines,
int suffixLength) {
// qDebug("inserting %i lines at (%i, %i) with (%i : %i) bounds", numLines,
// line, column, prefixLength, suffixLength);
foreach (QDocumentCursorHandle *ch, m_autoUpdated) {
if (ch == m_cursor || ch->document() != m_doc)
continue;
// printf("[[watch:0x%x(%i, %i)]]", ch, ch->m_begLine, ch->m_begOffset);
// TODO : better selection handling
if (ch->hasSelection()) {
int lbeg = line, cbeg = column, lend = line, cend = column;
ch->intersectBoundaries(lbeg, cbeg, lend, cend);
if (lbeg == line && cbeg == column) {
// qDebug("expand (%i, %i : %i, %i)", ch->m_begLine,
// ch->m_begOffset, ch->m_endLine, ch->m_endOffset);
if ((ch->m_begLine > ch->m_endLine) ||
(ch->m_begLine == ch->m_endLine &&
ch->m_begOffset > ch->m_endOffset)) {
if (numLines) {
if (ch->m_begLine == line)
ch->m_begOffset -= column;
ch->m_begLine += numLines;
ch->m_begOffset += suffixLength;
} else if (ch->m_begLine == line) {
ch->m_begOffset += prefixLength;
}
} else {
if (numLines) {
if (ch->m_endLine == line)
ch->m_endOffset -= column;
ch->m_endLine += numLines;
ch->m_endOffset += suffixLength;
} else if (ch->m_endLine == line) {
ch->m_endOffset += prefixLength;
}
}
// qDebug("into (%i, %i : %i, %i)", ch->m_begLine,
// ch->m_begOffset, ch->m_endLine, ch->m_endOffset);
continue;
}
}
// move
if (ch->m_begLine > line) {
ch->m_begLine += numLines;
} else if (ch->m_begLine == line && ch->m_begOffset >= column) {
if (numLines) {
ch->m_begLine += numLines;
ch->m_begOffset -= column;
ch->m_begOffset += suffixLength;
} else {
ch->m_begOffset += prefixLength;
}
}
if (ch->m_endLine > line) {
ch->m_endLine += numLines;
} else if (ch->m_endLine == line && ch->m_endOffset >= column) {
if (numLines) {
ch->m_endLine += numLines;
ch->m_endOffset -= column;
ch->m_endOffset += suffixLength;
} else {
ch->m_endOffset += prefixLength;
}
}
}
}
void QDocumentCommand::updateCursorsOnDeletion(int line, int column,
int prefixLength, int numLines,
int suffixLength) {
// qDebug("removing %i lines at (%i, %i) with (%i : %i) bounds", numLines,
// line, column, prefixLength, suffixLength);
foreach (QDocumentCursorHandle *ch, m_autoUpdated) {
if (ch == m_cursor || ch->document() != m_doc)
continue;
// printf("[[watch:0x%x(%i, %i)]]", ch, ch->m_begLine, ch->m_begOffset);
// TODO : better selection handling
if (ch->hasSelection()) {
int lbeg = line, cbeg = column, lend = line + numLines,
cend = numLines ? suffixLength : column + prefixLength;
ch->intersectBoundaries(lbeg, cbeg, lend, cend);
// qDebug("intersection (%i, %i : %i, %i)", lbeg, cbeg, lend, cend);
if (lbeg != -1 && cbeg != -1 && lend != -1 && cend != -1) {
// qDebug("shrink (%i, %i : %i, %i)", ch->m_begLine,
// ch->m_begOffset, ch->m_endLine, ch->m_endOffset); qDebug("of
// intersection (%i, %i : %i, %i)", lbeg, cbeg, lend, cend);
ch->substractBoundaries(lbeg, cbeg, lend, cend);
// qDebug("into (%i, %i : %i, %i)", ch->m_begLine,
// ch->m_begOffset, ch->m_endLine, ch->m_endOffset);
continue;
}
}
// move
if (ch->m_begLine > line + numLines) {
ch->m_begLine -= numLines;
} else if (ch->m_begLine == line + numLines &&
ch->m_begOffset >= suffixLength) {
if (numLines) {
ch->m_begLine -= numLines;
ch->m_begOffset -= suffixLength;
ch->m_begOffset += column;
} else {
ch->m_begOffset -= prefixLength;
}
} else if (ch->m_begLine > line ||
(ch->m_begLine == line && ch->m_begOffset > column)) {
// cursor will become invalid in an unrecoverable way...
}
if (ch->m_endLine > line + numLines) {
ch->m_endLine -= numLines;
} else if (ch->m_endLine == line + numLines &&
ch->m_endOffset >= suffixLength) {
if (numLines) {
ch->m_endLine -= numLines;
ch->m_endOffset -= suffixLength;
ch->m_endOffset += column;
} else {
ch->m_endOffset -= prefixLength;
}
} else if (ch->m_endLine > line ||
(ch->m_endLine == line && ch->m_endOffset > column)) {
// cursor will become invalid in an unrecoverable way...
// except that it should have intersected in the first place...
}
}
}
/*!
\brief Remove some lines from the host document
\param after where to remove lines (line number)
\param n number of lines to remove
This helper method is provided so that subclasses may actually
modify the document contents without using the private API.
*/
void QDocumentCommand::removeLines(int after, int n) {
if (n <= 0 || !m_doc->impl()->at(after) || !m_doc->impl()->at(after + n))
return;
m_doc->impl()->removeLines(after, n);
}
/*!
\brief Update the target cursor
\param l target line
\param offset target text position within target line
*/
void QDocumentCommand::updateTarget(int l, int offset) {
// QDocumentLineHandle *h = m_doc->impl()->at(l);
// update command sender if any
if (m_cursor) {
// qDebug("moving cursor [0x%x:beg] from (%i, %i) to line
//(%i, %i) as updating", m_cursor,
// m_cursor->m_begLine,
// m_cursor->m_begOffset, l, offset
// );
//
while (l && (offset < 0)) {
--l;
offset += m_doc->line(l).length() + 1;
}
while ((l + 1) < m_doc->lines() && m_doc->line(l).length() < offset) {
offset -= m_doc->line(l).length() + 1;
++l;
}
if (!m_keepAnchor) {
m_cursor->m_endLine = -1;
m_cursor->m_endOffset = -1;
} else if (m_cursor->m_endLine == -1) {
m_cursor->m_endLine = m_cursor->m_begLine;
m_cursor->m_endOffset = m_cursor->m_begOffset;
}
m_cursor->m_begLine = qMax(0, l);
m_cursor->m_begOffset = qMax(0, offset);
m_cursor->refreshColumnMemory();
}
}
/*!
\return whether a given cursor is auto updated
*/
bool QDocumentCommand::isAutoUpdated(const QDocumentCursorHandle *h) {
return m_autoUpdated.contains(const_cast<QDocumentCursorHandle *>(h));
}
/*!
\brief Enable auto update for a given cursor
*/
void QDocumentCommand::enableAutoUpdate(QDocumentCursorHandle *h) {
// qDebug("up(0x%x)", h);
if (!m_autoUpdated.contains(h))
m_autoUpdated << h;
}
/*!
\brief Disable auto update for a given cursor
*/
void QDocumentCommand::disableAutoUpdate(QDocumentCursorHandle *h) {
// qDebug("no-up(0x%x)", h);
m_autoUpdated.removeAll(h);
}
void QDocumentCommand::discardHandlesFromDocument(QDocument *d) {
int idx = 0;
while (idx < m_autoUpdated.count()) {
if (m_autoUpdated.at(idx)->document() == d)
m_autoUpdated.removeAt(idx);
else
++idx;
}
}
/*!
\brief Change the modification status of a line
*/
void QDocumentCommand::markRedone(QDocumentLineHandle *h, bool firstTime) {
QHash<QDocumentLineHandle *, QPair<int, int>>::iterator it =
m_doc->impl()->m_status.find(h);
if (it != m_doc->impl()->m_status.end()) {
if (firstTime && it->first < it->second)
it->second = -1;
++it->first;
} else {
m_doc->impl()->m_status[h] = qMakePair(1, 0);
}
}
/*!
\brief Change the modifiaction status of a line
*/
void QDocumentCommand::markUndone(QDocumentLineHandle *h) {
QHash<QDocumentLineHandle *, QPair<int, int>>::iterator it =
m_doc->impl()->m_status.find(h);
if (it != m_doc->impl()->m_status.end()) {
--it->first;
} else {
qDebug("warning: status data and/or undo stack corrupted...");
m_doc->impl()->m_status[h] = qMakePair(-1, 0);
}
}
////////////////////////////
/*!
\class QDocumentInsertCommand
\brief A specialized command to insert text
*/
/*!
\brief ctor
\param l target line
\param offset target text position within target line
\param text text to insert (can contain line feeds, "\n", which will
result in the creation of new lines) \param doc host document \param p parent
command
*/
QDocumentInsertCommand::QDocumentInsertCommand(int l, int offset,
const QString &text,
QDocument *doc,
const QString &sfmtID,
QDocumentCommand *p)
: QDocumentCommand(Insert, doc, p), m_sfmtID(sfmtID) {
QStringList lines = text.split(QLatin1Char('\n'), Qt::KeepEmptyParts);
if (!m_doc || text.isEmpty())
qFatal("Invalid insert command");
m_data.lineNumber = l;
m_data.startOffset = offset;
m_data.begin = lines.takeAt(0);
m_data.endOffset = lines.count() ? lines.last().length() : -1;
for (auto &s : lines) {
auto lh = new QDocumentLineHandle(s, m_doc);
QFormatRange over;
auto fmt = m_doc->formatScheme();
auto id = fmt->id(sfmtID);
if (id) {
over.format = id;
over.offset = 0;
over.length = s.length();
lh->addOverlay(over);
}
m_data.handles << lh;
}
QDocumentLine bl = m_doc->line(l);
if (m_data.handles.count() && (bl.length() > offset)) {
m_data.end = bl.text().mid(offset);
m_data.handles.last()->textBuffer().append(m_data.end);
}
/*
if ( (text == "\n") && m_data.handles.isEmpty() )
qWarning("Go fix it by hand...");
*/
}
/*!
\brief dtor
*/
QDocumentInsertCommand::~QDocumentInsertCommand() {
if (m_state)
return;
// foreach ( QDocumentLineHandle *h, m_data.handles )
// h->deref();
}
bool QDocumentInsertCommand::mergeWith(const QUndoCommand *) { return false; }
void QDocumentInsertCommand::redo() {
// state : handles used by doc
m_state = true;
// QDocumentIterator it = m_doc->impl()->index(m_data.lineNumber);
// qDebug("inserting %i lines after %i", m_data.handles.count(),
// m_data.lineNumber);
QDocumentLineHandle *hl = m_doc->impl()->at(m_data.lineNumber);
if (m_data.handles.count()) {
removeText(m_data.lineNumber, m_data.startOffset, m_data.end.length());
}
insertText(m_data.lineNumber, m_data.startOffset, m_data.begin, m_sfmtID);
insertLines(m_data.lineNumber, m_data.handles);
if (m_data.handles.count()) {
QDocumentLineHandle *h = m_data.handles.last();
// updateTarget(h, h->text().length() - m_data.end.length());
updateTarget(m_data.lineNumber + m_data.handles.count(),
h->text().length() - m_data.end.length() + m_redoOffset);
} else {
updateTarget(m_data.lineNumber,
m_data.startOffset + m_data.begin.length() + m_redoOffset);
}
updateCursorsOnInsertion(m_data.lineNumber, m_data.startOffset,
m_data.begin.length(), m_data.handles.count(),
m_data.endOffset);
m_doc->impl()->emitContentsChange(m_data.lineNumber,
m_data.handles.count() + 1);
markRedone(hl, m_first);
foreach (QDocumentLineHandle *h, m_data.handles)
markRedone(h, m_first);
// m_doc->impl()->emitContentsChanged();
m_first = false;
}
void QDocumentInsertCommand::undo() {
// state : handles !used by doc
m_state = false;
// QDocumentIterator it = m_doc->impl()->index(m_data.line);
QDocumentLineHandle *hl = m_doc->impl()->at(m_data.lineNumber);
removeLines(m_data.lineNumber, m_data.handles.count());
removeText(m_data.lineNumber, m_data.startOffset, m_data.begin.size());
if (m_data.handles.count()) {
insertText(m_data.lineNumber, m_data.startOffset, m_data.end);
}
updateTarget(m_data.lineNumber, m_data.startOffset + m_undoOffset);
updateCursorsOnDeletion(m_data.lineNumber, m_data.startOffset,
m_data.begin.length(), m_data.handles.count(),
m_data.endOffset);
m_doc->impl()->emitContentsChange(m_data.lineNumber,
m_data.handles.count() + 1);
markUndone(hl);
foreach (QDocumentLineHandle *h, m_data.handles)
markUndone(h);
// m_doc->impl()->emitContentsChanged();
}
///////////////////////////
/*!
\class QDocumentEraseCommand
\brief A specialized command to erase text
*/
/*!
\brief ctor
\param bl begin line of the target area
\param bo begin text position of the target area
\param el end line of the target area
\param eo end text position of the target area
\param doc host document
\param p parent command
*/
QDocumentEraseCommand::QDocumentEraseCommand(int bl, int bo, int el, int eo,
QDocument *doc,
QDocumentCommand *p)
: QDocumentCommand(Erase, doc, p) {
QDocumentLineHandle *start = m_doc->impl()->at(bl),
*end = m_doc->impl()->at(el);
QDocumentConstIterator it = m_doc->impl()->begin() + bl; // index(start);
m_data.lineNumber = bl;
m_data.startOffset = bo;
if (start == end) {
m_data.begin = start->text().mid(bo, eo - bo);
m_data.end = QString();
m_data.endOffset = -1;
} else {
m_data.begin = start->text().mid(bo);
m_data.endOffset = eo;
m_data.end = end->text().mid(eo);
do {
m_data.handles << *(++it);
} while (*it != end);
}
m_state = true;
}
/*!
\brief dtor
*/
QDocumentEraseCommand::~QDocumentEraseCommand() {
if (m_state)
return;
// qDeleteAll(m_data.handles);
}
bool QDocumentEraseCommand::mergeWith(const QUndoCommand *) { return false; }
void QDocumentEraseCommand::redo() {
// state : handles !used by doc
m_state = false;
// QDocumentIterator it = m_doc->impl()->index(m_data.line);
QDocumentLineHandle *hl = m_doc->impl()->at(m_data.lineNumber);
if (m_data.handles.isEmpty()) {
removeText(m_data.lineNumber, m_data.startOffset,
m_data.begin.length());
m_doc->impl()->emitContentsChange(m_data.lineNumber, 1);
} else {
removeText(m_data.lineNumber, m_data.startOffset,
m_data.begin.length());
if (m_data.endOffset != -1)
insertText(m_data.lineNumber, m_data.startOffset, m_data.end);
removeLines(m_data.lineNumber, m_data.handles.count());
m_doc->impl()->emitContentsChange(m_data.lineNumber,
m_data.handles.count() + 1);
}
updateTarget(m_data.lineNumber, m_data.startOffset + m_redoOffset);
updateCursorsOnDeletion(m_data.lineNumber, m_data.startOffset,
m_data.begin.length(), m_data.handles.count(),
m_data.endOffset);
markRedone(hl, m_first);
foreach (QDocumentLineHandle *h, m_data.handles)
markRedone(h, m_first);
// m_doc->impl()->emitContentsChanged();
m_first = false;
}
void QDocumentEraseCommand::undo() {
// state : handles used by doc
m_state = true;
// QDocumentIterator it = m_doc->impl()->index(m_data.line);
QDocumentLineHandle *hl = m_doc->impl()->at(m_data.lineNumber);
if (m_data.handles.count()) {
insertLines(m_data.lineNumber, m_data.handles);
if (m_data.endOffset != -1)
removeText(m_data.lineNumber, m_data.startOffset,
m_data.end.size());
insertText(m_data.lineNumber, m_data.startOffset, m_data.begin);
m_doc->impl()->emitContentsChange(m_data.lineNumber,
m_data.handles.count() + 1);
} else {
insertText(m_data.lineNumber, m_data.startOffset, m_data.begin);
m_doc->impl()->emitContentsChange(m_data.lineNumber, 1);
}
if (m_data.handles.count()) {
QDocumentLineHandle *h = m_data.handles.last();
// updateTarget(h, h->text().length() - m_data.end.length());
updateTarget(m_data.lineNumber + m_data.handles.count(),
h->text().length() - m_data.end.length() + m_undoOffset);
} else {
updateTarget(m_data.lineNumber,
m_data.startOffset + m_data.begin.length() + m_undoOffset);
}
updateCursorsOnInsertion(m_data.lineNumber, m_data.startOffset,
m_data.begin.length(), m_data.handles.count(),
m_data.endOffset);
markUndone(hl);
foreach (QDocumentLineHandle *h, m_data.handles)
markUndone(h);
// m_doc->impl()->emitContentsChanged();
}
///////////////////////////
/*
QDocumentReplaceCommand::QDocumentReplaceCommand(const QDocumentLine& l, int,
int, const QString&) : QDocumentCommand(Replace, l.document())
{
}
QDocumentReplaceCommand::~QDocumentReplaceCommand()
{
}
bool QDocumentReplaceCommand::mergeWith(const QUndoCommand *)
{
return false;
}
void QDocumentReplaceCommand::redo()
{
}
void QDocumentReplaceCommand::undo()
{
}
*/
//////////////////////
/*!
\class QDocumentCommandBlock
\brief A meta command used for command grouping
*/
/*!
\brief ctor
\param d host document
*/
QDocumentCommandBlock::QDocumentCommandBlock(QDocument *d)
: QDocumentCommand(Custom, d), m_weakLocked(false) {}
/*!
\brief dtor
*/
QDocumentCommandBlock::~QDocumentCommandBlock() {}
void QDocumentCommandBlock::redo() {
if (isWeakLocked()) {
setWeakLock(false);
return;
}
// foreach ( QDocumentCommand *c, m_commands )
// c->redo();
for (int i = 0; i < m_commands.count(); ++i)
m_commands.at(i)->redo();
}
void QDocumentCommandBlock::undo() {
// foreach ( QDocumentCommand *c, m_commands )
// c->undo();
for (int i = m_commands.count() - 1; i >= 0; --i)
m_commands.at(i)->undo();
}
/*!
\brief Set whether the block is weakly locked
*/
void QDocumentCommandBlock::setWeakLock(bool l) { m_weakLocked = l; }
/*!
\return whether the block is weakly locked
Weak locking of command block is an obscure internal feature
which prevents the first redo() call from actually redo'ing
the grouped commands
*/
bool QDocumentCommandBlock::isWeakLocked() const { return m_weakLocked; }
/*!
\brief Add a command to the group
\warning Doing that after having pushed the command on the undo/redo
stack is likely to result in corruption of the undo/redo stack
*/
void QDocumentCommandBlock::addCommand(QDocumentCommand *c) { m_commands << c; }
/*!
\brief Remove a command from the block
\warning Doing that after having pushed the command on the undo/redo
stack is likely to result in corruption of the undo/redo stack
*/
void QDocumentCommandBlock::removeCommand(QDocumentCommand *c) {
m_commands.removeAll(c);
}
/*! @} */

View File

@ -1,156 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QDOCUMENT_COMMAND_H_
#define _QDOCUMENT_COMMAND_H_
#include "qce-config.h"
/*!
\file qdocumentcommand.h
\brief Definition of the QDocumentCommand class
*/
#include <QUndoCommand>
#include "qdocument.h"
class QDocumentLine;
class QDocumentLineHandle;
class QDocumentCursorHandle;
class QCE_EXPORT QDocumentCommand : public QUndoCommand {
public:
enum Command { None, Insert, Erase, Replace, Custom };
struct TextCommandData {
QString begin, end;
int lineNumber, startOffset, endOffset;
QList<QDocumentLineHandle *> handles;
};
QDocumentCommand(Command c, QDocument *d, QDocumentCommand *p = nullptr);
virtual ~QDocumentCommand();
virtual int id() const;
virtual bool mergeWith(const QUndoCommand *command);
virtual void redo();
virtual void undo();
bool isSilent() const;
void setSilent(bool y);
bool keepAnchor() const;
void setKeepAnchor(bool y);
void setTargetCursor(QDocumentCursorHandle *h);
void setRedoOffset(int off);
void setUndoOffset(int off);
static bool isAutoUpdated(const QDocumentCursorHandle *h);
static void enableAutoUpdate(QDocumentCursorHandle *h);
static void disableAutoUpdate(QDocumentCursorHandle *h);
static void discardHandlesFromDocument(QDocument *d);
protected:
bool m_state, m_first;
QDocument *m_doc;
int m_redoOffset, m_undoOffset;
void markRedone(QDocumentLineHandle *h, bool firstTime);
void markUndone(QDocumentLineHandle *h);
void updateTarget(int l, int offset);
void insertText(int line, int pos, const QString &s,
const QString &sfmtID = {});
void removeText(int line, int pos, int length);
void insertLines(int after, const QList<QDocumentLineHandle *> &l);
void removeLines(int after, int n);
void updateCursorsOnInsertion(int line, int column, int prefixLength,
int numLines, int suffixLength);
void updateCursorsOnDeletion(int line, int column, int prefixLength,
int numLines, int suffixLength);
private:
bool m_silent;
bool m_keepAnchor;
Command m_command;
QDocumentCursorHandle *m_cursor;
static QList<QDocumentCursorHandle *> m_autoUpdated;
};
Q_DECLARE_TYPEINFO(QDocumentCommand::TextCommandData, Q_MOVABLE_TYPE);
class QCE_EXPORT QDocumentInsertCommand : public QDocumentCommand {
public:
QDocumentInsertCommand(int l, int offset, const QString &text,
QDocument *doc, const QString &sfmtID = 0,
QDocumentCommand *p = nullptr);
virtual ~QDocumentInsertCommand();
virtual bool mergeWith(const QUndoCommand *command);
virtual void redo();
virtual void undo();
private:
TextCommandData m_data;
QString m_sfmtID;
};
class QCE_EXPORT QDocumentEraseCommand : public QDocumentCommand {
public:
QDocumentEraseCommand(int bl, int bo, int el, int eo, QDocument *doc,
QDocumentCommand *p = nullptr);
virtual ~QDocumentEraseCommand();
virtual bool mergeWith(const QUndoCommand *command);
virtual void redo();
virtual void undo();
private:
TextCommandData m_data;
};
class QCE_EXPORT QDocumentCommandBlock : public QDocumentCommand {
public:
QDocumentCommandBlock(QDocument *d);
virtual ~QDocumentCommandBlock();
virtual void redo();
virtual void undo();
void setWeakLock(bool l);
bool isWeakLocked() const;
virtual void addCommand(QDocumentCommand *c);
virtual void removeCommand(QDocumentCommand *c);
private:
bool m_weakLocked;
QList<QDocumentCommand *> m_commands;
};
#endif

View File

@ -1,778 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
/*!
\file qdocumentcursor.cpp
\brief Implementation of the QDocumentCursor class
*/
#include "qdocumentcursor.h"
/*!
\ingroup document
@{
*/
#include "qdocument_p.h"
#include "qdocumentline.h"
/*!
\class QDocumentCursor
\brief A cursor to navigate within documents and edit them
QDocumentCursor is a central class of the public API.
It is the best (as in fastest and easiest) way to iterate over
the content of a document.
It is also the only class that allows to perform editing operations.
A cursor position is defined by a line number and a text position
within the line.
Every cursor can have one or two cursor positions. In the later
case, they delimit a selection. The first position set (before
selecting) is referred to as the "anchor" and the other (if it
is different from the anchor) is the actual cursor position.
When the cursor does not have a selection, querying informations about
the anchor has the same result as querying informations about the cursor
position.
Informations you can get about both the anchor and the posiotion :
<ul>
<li>the line number : the logical line to which the cursor position
points inside the document <li>the column number : the logical text column to
which the cursor position points to, inside the pointed line. <li>the wrapped
line offset : when a cursor resides on a wrapped line, this indicates in
which part of the wrapped line it does <li>the document position : document
(x, y) coordinates corresponding to the place the cursor is drawn
</ul>
The visual line to which a given cursor resides can be obtained as
follows :
\code
int visual_line = cursor.document()->visualLine(cursor.lineNumber()) +
cursor.wrappedLineOffset(); \endcode
\note The line and column numbers passed to/returned by a cursor method
always start at zero.
\note Quick overview of the various coordinate systems :
<ul>
<li>document coordinates aka viewport coordinates : (x, y)
coords, in pixels, origin at the top left corner of the rectangle occupied by
the very first line of the document <li>text coordinates : (line, column) in
logical units (number of lines, number of characters) <li>visual text
coordinates : (line, column) in logical units but with a different mapping
</ul>
*/
QDocumentCursor::QDocumentCursor(QDocument *doc)
: m_handle(new QDocumentCursorHandle(doc)) {
m_handle->ref();
}
QDocumentCursor::QDocumentCursor(const QDocumentCursor &cursor) : m_handle(0) {
if (cursor.m_handle) {
m_handle = cursor.m_handle->clone();
m_handle->ref();
}
}
QDocumentCursor::QDocumentCursor(QDocument *doc, int line, int column)
: m_handle(new QDocumentCursorHandle(doc, line)) {
m_handle->ref();
m_handle->setColumnNumber(column);
}
/*
QDocumentCursor::QDocumentCursor(const QDocumentLine& line, int column)
: m_handle(new QDocumentCursorHandle(line.document(), line.lineNumber()))
{
m_handle->ref();
m_handle->setColumnNumber(column);
//movePosition(qMin(column, line.length()));
}
*/
QDocumentCursor::QDocumentCursor(QDocumentCursorHandle *handle)
: m_handle(handle) {
if (m_handle)
m_handle->ref();
}
QDocumentCursor::~QDocumentCursor() {
if (m_handle)
m_handle->deref();
}
QDocumentCursor QDocumentCursor::clone() const {
return m_handle ? QDocumentCursor(m_handle->clone()) : QDocumentCursor();
}
QDocumentCursor &QDocumentCursor::operator=(const QDocumentCursor &c) {
#if 0
if ( m_handle )
m_handle->deref();
m_handle = c.m_handle ? c.m_handle->clone() : 0;
//m_handle = c.m_handle;
if ( m_handle )
m_handle->ref();
#endif
if (c.m_handle) {
if (m_handle) {
m_handle->copy(c.m_handle);
} else {
m_handle = c.m_handle->clone();
m_handle->ref();
}
} else if (m_handle) {
// qWarning("Setting a cursor to null");
m_handle->deref();
m_handle = 0;
}
return *this;
}
/*!
\brief comparision operator
\note If any of the operand is an invalid cursor, false is returned
*/
bool QDocumentCursor::operator==(const QDocumentCursor &c) const {
if (!m_handle || !c.m_handle)
return false;
return m_handle->eq(c.m_handle);
}
/*!
\brief comparision operator
\note If any of the operand is an invalid cursor, true is returned (to
preserve logical consistency with == )
*/
bool QDocumentCursor::operator!=(const QDocumentCursor &c) const {
if (!m_handle || !c.m_handle)
return true;
return !m_handle->eq(c.m_handle);
}
/*!
\brief comparision operator
\note If any of the operand is an invalid cursor, false is returned
*/
bool QDocumentCursor::operator<(const QDocumentCursor &c) const {
if (!m_handle || !c.m_handle)
return false;
return m_handle->lt(c.m_handle);
}
/*!
\brief comparision operator
\note If any of the operand is an invalid cursor, false is returned
*/
bool QDocumentCursor::operator>(const QDocumentCursor &c) const {
if (!m_handle || !c.m_handle)
return false;
return m_handle->gt(c.m_handle);
}
/*!
\brief comparision operator
\note If any of the operand is an invalid cursor, false is returned
*/
bool QDocumentCursor::operator<=(const QDocumentCursor &c) const {
if (!m_handle || !c.m_handle)
return false;
return m_handle->lt(c.m_handle) || m_handle->eq(c.m_handle);
}
/*!
\brief comparision operator
\note If any of the operand is an invalid cursor, false is returned
*/
bool QDocumentCursor::operator>=(const QDocumentCursor &c) const {
if (!m_handle || !c.m_handle)
return false;
return m_handle->gt(c.m_handle) || m_handle->eq(c.m_handle);
}
/*!
\brief comparision operator
*/
bool QDocumentCursor::isNull() const {
return !m_handle || !m_handle->document() || !line().isValid();
}
/*!
\brief comparision operator
*/
bool QDocumentCursor::isValid() const {
return m_handle && m_handle->document() && line().isValid();
}
/*!
\return whether the cursor is at the end of the document
*/
bool QDocumentCursor::atEnd() const {
return m_handle ? m_handle->atEnd() : false;
}
/*!
\return whether the cursor is at the begining of the document
*/
bool QDocumentCursor::atStart() const {
return m_handle ? m_handle->atStart() : false;
}
/*!
\return whether the cursor is at the end of a block
*/
bool QDocumentCursor::atBlockEnd() const {
return m_handle ? m_handle->atBlockEnd() : false;
}
/*!
\return whether the cursor is at the start of a block
*/
bool QDocumentCursor::atBlockStart() const {
return m_handle ? m_handle->atBlockStart() : false;
}
/*!
\return whether the cursor is at the end of a line
\note this may only differ from atBlockEnd() on wrapped lines
*/
bool QDocumentCursor::atLineEnd() const {
return m_handle ? m_handle->atLineEnd() : false;
}
/*!
\return whether the cursor is at the start of a line
\note this may only differ from atBlockStart() on wrapped lines
*/
bool QDocumentCursor::atLineStart() const {
return m_handle ? m_handle->atLineStart() : false;
}
/*!
\return the document on which this cursor operates
*/
QDocument *QDocumentCursor::document() const {
return m_handle ? m_handle->document() : 0;
}
/*!
\return the text position (within the whole document) at which this
cursor is
\note available for compat with QTextCursor and ridiculously slow :
avoid whenever possible
*/
int QDocumentCursor::position() const {
return m_handle ? m_handle->position() : -1;
}
/*!
\return the text column of the anchor
*/
int QDocumentCursor::anchorColumnNumber() const {
return m_handle ? m_handle->anchorColumnNumber() : -1;
}
/*!
\return the "visual" text column of the cursor
\note this may only differ from columnNumber() when there are tabs on
the line
*/
int QDocumentCursor::visualColumnNumber() const {
return m_handle ? m_handle->visualColumnNumber() : -1;
}
/*!
\return the text column of the cursor
*/
int QDocumentCursor::columnNumber() const {
return m_handle ? m_handle->columnNumber() : -1;
}
/*!
\brief Set the text column of the cursor
\param c text column to set
\param m move mode (determines whether text will be selected)
*/
void QDocumentCursor::setColumnNumber(int c, MoveMode m) {
if (m_handle)
m_handle->setColumnNumber(c, m);
}
/*!
\return The line number to which the cursor points
*/
int QDocumentCursor::lineNumber() const {
return m_handle ? m_handle->lineNumber() : -1;
}
/*!
\return The line number to which the cursor points
*/
int QDocumentCursor::anchorLineNumber() const {
return m_handle ? m_handle->anchorLineNumber() : -1;
}
/*!
\return The wrapped line on which the cursor resides
Wrapped line are "sublines" of logical lines.
*/
int QDocumentCursor::wrappedLineOffset() const {
return line().wrappedLineForCursor(columnNumber());
}
/*!
\return The line number on which the anchor resides
*/
int QDocumentCursor::anchorWrappedLineOffset() const {
return anchorLine().wrappedLineForCursor(anchorColumnNumber());
}
/*!
\return the document position at which the cursor is
Document position and viewport position are two terms used
interchangeably. The only difference is the former refers to model perception
(QDocument) whereas the later refers to view perception (QEditor)
*/
QPoint QDocumentCursor::documentPosition() const {
return m_handle ? m_handle->documentPosition() : QPoint();
}
/*!
\return the document position of the anchor
*/
QPoint QDocumentCursor::anchorDocumentPosition() const {
return m_handle ? m_handle->anchorDocumentPosition() : QPoint();
}
QPolygon QDocumentCursor::documentRegion() const {
return m_handle ? m_handle->documentRegion() : QPolygon();
}
/*!
\return The line object on which the cursor resides
*/
QDocumentLine QDocumentCursor::line() const {
return m_handle ? m_handle->line() : QDocumentLine();
}
/*!
\return The line object on which the anchor resides
*/
QDocumentLine QDocumentCursor::anchorLine() const {
return m_handle ? m_handle->anchorLine() : QDocumentLine();
}
/*!
\brief Shift cursor position (text column) by a number of columns
(characters)
*/
void QDocumentCursor::shift(int offset) {
if (m_handle)
m_handle->shift(offset);
}
/*!
\brief Moves the cursor position
\param offset number of times the selected move will be done
\param op movement type
\param m movement mode (whether to select)
\return true on succes
*/
bool QDocumentCursor::movePosition(int offset, MoveOperation op, MoveMode m) {
return m_handle ? m_handle->movePosition(offset, op, m) : false;
}
/*!
\brief Jump to another cursor position
\param line target line number
\param colum target text column
*/
void QDocumentCursor::moveTo(int line, int column) {
if (m_handle)
m_handle->moveTo(line, column);
}
/*!
\brief Jump to the position of another cursor
\param c target cursor
*/
void QDocumentCursor::moveTo(const QDocumentCursor &c) {
if (m_handle)
m_handle->moveTo(c);
}
/*!
\brief Jump to another cursor position
\param l target line
\param column target text column
\note Calls QDocumentLine::lineNumber() => SLOW : avoid whenever
possible
*/
void QDocumentCursor::moveTo(const QDocumentLine &l, int column) {
if (m_handle)
m_handle->moveTo(l.lineNumber(), column);
}
/*!
\return the character at the position immediately after the cursor
*/
QChar QDocumentCursor::nextChar() const {
return m_handle ? m_handle->nextChar() : QChar();
}
/*!
\return the character at the position immediately before the cursor
*/
QChar QDocumentCursor::previousChar() const {
return m_handle ? m_handle->previousChar() : QChar();
}
/*!
\brief Delete the character at the position immediately after the cursor
*/
void QDocumentCursor::deleteChar() {
if (m_handle)
m_handle->deleteChar();
}
/*!
\brief Delete the character at the position immediately before the
cursor
*/
void QDocumentCursor::deletePreviousChar() {
if (m_handle)
m_handle->deletePreviousChar();
}
/*!
\brief erase the whole line the cursor is on, newline included
*/
void QDocumentCursor::eraseLine() {
if (m_handle)
m_handle->eraseLine();
}
/*!
\brief insert a new line at the cursor position
*/
void QDocumentCursor::insertLine(bool keepAnchor) {
if (m_handle)
m_handle->insertText(QStringLiteral("\n"), keepAnchor);
}
/*!
\brief insert some text at the cursor position
Selected text will be removed before insertion happens.
\note Nothing happens if \a s is empty
*/
void QDocumentCursor::insertText(const QString &s, bool keepAnchor,
const QString &sfmtID) {
if (m_handle)
m_handle->insertText(s, keepAnchor, sfmtID);
}
/*!
\return A cursor pointing at the position of the selection start.
Selection start is the position of the selection that is nearest to
document start.
\note an invalid cursor is returned when the cursor does not have a
selection
*/
QDocumentCursor QDocumentCursor::selectionStart() const {
return m_handle ? m_handle->selectionStart() : QDocumentCursor();
}
/*!
\return A cursor pointing at the position of the selection end.
Selection end is the position of the selection that is nearest to
document end.
\note an invalid cursor is returned when the cursor does not have a
selection
*/
QDocumentCursor QDocumentCursor::selectionEnd() const {
return m_handle ? m_handle->selectionEnd() : QDocumentCursor();
}
/*!
\return The selected text
*/
QString QDocumentCursor::selectedText() const {
return m_handle ? m_handle->selectedText() : QString();
}
/*!
\brief Remove the selected text
*/
void QDocumentCursor::removeSelectedText() {
if (m_handle)
m_handle->removeSelectedText();
}
/*!
\brief Replace the selected text
This method differs from insertText() in two ways :
<ul>
<li>if \a text is empty the selection WILL be removed
<li>after the replacement happens this command will
cause the cursor to select the new text (note that this
information is NOT preserved by the undo/redo stack
however).
</ul>
*/
void QDocumentCursor::replaceSelectedText(const QString &text) {
if (m_handle)
m_handle->replaceSelectedText(text);
}
/*!
\brief Begin an edit block
Edit blocks are command groups. All the commands in an edit block
are executed in a row when the edit block is ended with endEditBlock().
Edit blocks are considered as a single command as far as the undo/redo
stack is concerned.
Edit blocks can be nested but that isn't of much use
*/
void QDocumentCursor::beginEditBlock() {
if (m_handle)
m_handle->beginEditBlock();
}
/*!
\brief End an edit block
*/
void QDocumentCursor::endEditBlock() {
if (m_handle)
m_handle->endEditBlock();
}
/*!
\return Whether the cursor is silent
*/
bool QDocumentCursor::isSilent() const {
return m_handle ? m_handle->isSilent() : true;
}
/*!
\brief Set whether the cursor is silent
*/
void QDocumentCursor::setSilent(bool y) {
if (m_handle)
m_handle->setSilent(y);
}
/*!
\return whether the cursor is auto updated
An auto updated cursor will remain on the actual line it points
to when the document is modified.
\code
QDocumentCursor c1(10, 0, document), c2(10, 0, document), c(5, 0,
document);
c1.setAutoUpdated(true);
c.insertLine();
// at this point c2 still points to line 10 whereas c1 points to line 11
\endcode
*/
bool QDocumentCursor::isAutoUpdated() const {
return m_handle ? m_handle->isAutoUpdated() : true;
}
/*!
\brief Set whether the cursor is aut updated
*/
void QDocumentCursor::setAutoUpdated(bool y) {
if (m_handle)
m_handle->setAutoUpdated(y);
}
/*!
\brief Refresh the column memory of the cursor
This set the current column memory to the current column position.
\note It is not recommended to call that yourself. The various
movement method should do that perfectly fine.
*/
void QDocumentCursor::refreshColumnMemory() {
if (m_handle)
m_handle->refreshColumnMemory();
}
/*!
\return Whether the cursor has column memory
The column memory is a feature that allow a cursor
to remember its biggest column number so that moving
back and forth (with movePosition()) on lines of
different width does not result in the column to change.
*/
bool QDocumentCursor::hasColumnMemory() const {
return m_handle ? m_handle->hasColumnMemory() : false;
}
/*!
\brief Set whether the cursor use column memory
*/
void QDocumentCursor::setColumnMemory(bool y) {
if (m_handle)
m_handle->setColumnMemory(y);
}
/*!
\return whether the cursor has a selection
*/
bool QDocumentCursor::hasSelection() const {
return m_handle ? m_handle->hasSelection() : false;
}
/*!
\brief clear the selection
*/
void QDocumentCursor::clearSelection() {
if (m_handle)
m_handle->clearSelection();
}
/*!
\brief Select something
*/
void QDocumentCursor::select(SelectionType t) {
if (m_handle)
m_handle->select(t);
}
/*!
\brief Set the selection boundary
Select text between the current cursor anchor and the one
of \a c.
\note We mean ANCHOR. If the cursor already has a selection the
anchor will not change, but the position will be set to that of
\a c.
*/
void QDocumentCursor::setSelectionBoundary(const QDocumentCursor &c) {
if (m_handle)
m_handle->setSelectionBoundary(c);
}
/*!
\return whether a given cursor is within the selection
*/
bool QDocumentCursor::isWithinSelection(const QDocumentCursor &c) const {
return m_handle ? m_handle->isWithinSelection(c) : false;
}
/*!
\return selection information
\note The QDocumentSelection object is not updated if the selection
changes later on : use it right away and do not store it.
*/
QDocumentSelection QDocumentCursor::selection() const {
QDocumentSelection s;
if (isNull() || !hasSelection()) {
qDebug("NULL selection");
s.startLine = -1;
s.endLine = -1;
s.start = -1;
s.end = -1;
} else if (m_handle->m_begLine == m_handle->m_endLine) {
s.startLine = m_handle->m_begLine;
s.endLine = m_handle->m_begLine;
s.start = qMin(m_handle->m_begOffset, m_handle->m_endOffset);
s.end = qMax(m_handle->m_begOffset, m_handle->m_endOffset);
} else if (m_handle->m_begLine > m_handle->m_endLine) {
s.startLine = m_handle->m_endLine;
s.endLine = m_handle->m_begLine;
s.start = m_handle->m_endOffset;
s.end = m_handle->m_begOffset;
// qDebug("[(%i,%i);(%i,%i)]", s.startLine.lineNumber(), s.start,
// s.endLine.lineNumber(), s.end);
} else {
s.startLine = m_handle->m_begLine;
s.endLine = m_handle->m_endLine;
s.start = m_handle->m_begOffset;
s.end = m_handle->m_endOffset;
// qDebug("[(%i,%i);(%i,%i)]", s.startLine.lineNumber(), s.start,
// s.endLine.lineNumber(), s.end);
}
return s;
}
/*! @} */

View File

@ -1,188 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QDOCUMENT_CURSOR_H_
#define _QDOCUMENT_CURSOR_H_
#include "qce-config.h"
#include <QMetaType>
/*!
\file qdocumentcursor.h
\brief Definition of the QDocumentCursor class
*/
class QChar;
class QPoint;
class QString;
class QPolygon;
class QDocument;
class QDocumentLine;
struct QDocumentSelection;
class QDocumentCursorHandle;
class QCE_EXPORT QDocumentCursor {
public:
enum MoveFlag { MoveAnchor = 0, KeepAnchor = 1, ThroughWrap = 2 };
Q_DECLARE_FLAGS(MoveMode, MoveFlag);
enum MoveOperation {
NoMove,
Up,
Down,
Left,
PreviousCharacter = Left,
Right,
NextCharacter = Right,
Start,
StartOfLine,
StartOfBlock = StartOfLine,
StartOfWord,
PreviousBlock,
PreviousLine = PreviousBlock,
PreviousWord,
WordLeft,
WordRight,
End,
EndOfLine,
EndOfBlock = EndOfLine,
EndOfWord,
NextWord,
NextBlock,
NextLine = NextBlock
};
enum SelectionType { WordUnderCursor, LineUnderCursor };
explicit QDocumentCursor(QDocument *doc);
QDocumentCursor(const QDocumentCursor &cursor);
QDocumentCursor(QDocument *doc, int line, int column = 0);
// QDocumentCursor(const QDocumentLine& line, int column = 0);
QDocumentCursor(QDocumentCursorHandle *handle = 0);
~QDocumentCursor();
QDocumentCursor clone() const;
QDocumentCursor &operator=(const QDocumentCursor &c);
bool operator==(const QDocumentCursor &c) const;
bool operator!=(const QDocumentCursor &c) const;
bool operator<(const QDocumentCursor &c) const;
bool operator>(const QDocumentCursor &c) const;
bool operator<=(const QDocumentCursor &c) const;
bool operator>=(const QDocumentCursor &c) const;
bool isNull() const;
bool isValid() const;
bool atEnd() const;
bool atStart() const;
bool atBlockEnd() const;
bool atBlockStart() const;
bool atLineEnd() const;
bool atLineStart() const;
bool hasSelection() const;
bool isSilent() const;
void setSilent(bool y);
bool isAutoUpdated() const;
void setAutoUpdated(bool y);
int position() const;
int lineNumber() const;
int columnNumber() const;
int anchorLineNumber() const;
int anchorColumnNumber() const;
int visualColumnNumber() const;
void setColumnNumber(int c, MoveMode m = MoveAnchor);
int wrappedLineOffset() const;
int anchorWrappedLineOffset() const;
QPoint documentPosition() const;
QPoint anchorDocumentPosition() const;
QPolygon documentRegion() const;
QDocumentLine line() const;
QDocumentLine anchorLine() const;
void shift(int offset);
bool movePosition(int offset, MoveOperation op = NextCharacter,
MoveMode m = MoveAnchor);
void moveTo(int line, int column);
void moveTo(const QDocumentCursor &c);
void moveTo(const QDocumentLine &l, int column);
void eraseLine();
void insertLine(bool keepAnchor = false);
void insertText(const QString &s, bool keepAnchor = false,
const QString &sfmtID = {});
QDocumentCursor selectionStart() const;
QDocumentCursor selectionEnd() const;
QString selectedText() const;
void clearSelection();
void removeSelectedText();
void replaceSelectedText(const QString &text);
void select(SelectionType t);
void setSelectionBoundary(const QDocumentCursor &c);
bool isWithinSelection(const QDocumentCursor &c) const;
QChar nextChar() const;
QChar previousChar() const;
void deleteChar();
void deletePreviousChar();
void beginEditBlock();
void endEditBlock();
void refreshColumnMemory();
bool hasColumnMemory() const;
void setColumnMemory(bool y);
QDocumentSelection selection() const;
QDocument *document() const;
inline QDocumentCursorHandle *handle() const { return m_handle; }
private:
QDocumentCursorHandle *m_handle;
};
Q_DECLARE_METATYPE(QDocumentCursor);
#endif

View File

@ -1,179 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QDOCUMENT_CURSOR_P_H_
#define _QDOCUMENT_CURSOR_P_H_
#include "qce-config.h"
/*!
\file qdocumentcursor_p.h
\brief Definition of QDocumentCursorHandle
*/
#include "qdocumentcursor.h"
#include <QStack>
#if QT_VERSION < 0x040400
#include <QAtomic>
#else
#include <QAtomicInt>
#endif
class QPoint;
class QPolygon;
class QDocument;
class QDocumentLine;
class QDocumentPrivate;
class QDocumentCommand;
class QDocumentCommandBlock;
class QCE_EXPORT QDocumentCursorHandle {
friend class QDocumentCursor;
friend class QDocumentPrivate;
friend class QDocumentCommand;
public:
enum Flags { Silent = 1, ColumnMemory = 2, MoveWithinWrapped = 4 };
QDocument *document() const;
bool atEnd() const;
bool atStart() const;
bool atBlockEnd() const;
bool atBlockStart() const;
bool atLineEnd() const;
bool atLineStart() const;
bool hasSelection() const;
bool isSilent() const;
void setSilent(bool y);
bool isAutoUpdated() const;
void setAutoUpdated(bool y);
QDocumentLine line() const;
QDocumentLine anchorLine() const;
int lineNumber() const;
int columnNumber() const;
int anchorLineNumber() const;
int anchorColumnNumber() const;
int visualColumnNumber() const;
void setColumnNumber(int c, int m = QDocumentCursor::MoveAnchor);
QPoint documentPosition() const;
QPoint anchorDocumentPosition() const;
QPolygon documentRegion() const;
int position() const;
void shift(int offset);
bool movePosition(int offset, QDocumentCursor::MoveOperation op,
QDocumentCursor::MoveMode m);
void insertText(const QString &s, bool keepAnchor = false,
const QString &sfmtID = {});
QChar nextChar() const;
QChar previousChar() const;
void eraseLine();
void deleteChar();
void deletePreviousChar();
QDocumentCursor selectionStart() const;
QDocumentCursor selectionEnd() const;
bool eq(const QDocumentCursorHandle *h);
bool lt(const QDocumentCursorHandle *h);
bool gt(const QDocumentCursorHandle *h);
QString selectedText() const;
void clearSelection();
void removeSelectedText(bool keepAnchor = false);
void replaceSelectedText(const QString &text);
void select(QDocumentCursor::SelectionType t);
void setSelectionBoundary(const QDocumentCursor &c);
bool isWithinSelection(const QDocumentCursor &c) const;
QDocumentCursor intersect(const QDocumentCursor &c) const;
void beginBoundary(int &begline, int &begcol) const;
void endBoundary(int &endline, int &endcol) const;
void substractBoundaries(int lbeg, int cbeg, int lend, int cend);
void boundaries(int &begline, int &begcol, int &endline, int &endcol) const;
void intersectBoundaries(int &lbeg, int &cbeg, int &lend, int &cend) const;
void intersectBoundaries(QDocumentCursorHandle *h, int &lbeg, int &cbeg,
int &lend, int &cend) const;
void beginEditBlock();
void endEditBlock();
void moveTo(int line, int column);
void moveTo(const QDocumentCursor &c);
void copy(const QDocumentCursorHandle *c);
void refreshColumnMemory();
bool hasColumnMemory() const;
void setColumnMemory(bool y);
virtual void execute(QDocumentCommand *c);
inline void ref() { m_ref.ref(); }
inline void deref() {
if (m_ref)
m_ref.deref();
if (!m_ref)
delete this;
}
inline bool hasFlag(int f) const { return m_flags & f; }
inline void setFlag(int f) { m_flags |= f; }
inline void clearFlag(int f) { m_flags &= ~f; }
protected:
QDocumentCursorHandle(QDocument *d, int line = 0);
virtual ~QDocumentCursorHandle();
QDocumentCursorHandle *clone() const;
private:
int m_flags;
QDocument *m_doc;
#if QT_VERSION < 0x040400
QBasicAtomic m_ref;
#else
QAtomicInt m_ref;
#endif
int m_begOffset, m_endOffset, m_max, m_begLine, m_endLine;
QStack<QDocumentCommandBlock *> m_blocks;
};
Q_DECLARE_TYPEINFO(QDocumentCursorHandle *, Q_PRIMITIVE_TYPE);
#endif // !_QDOCUMENT_CURSOR_P_H_

View File

@ -1,542 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qdocumentline.h"
/*!
\file qdocumentline.cpp
\brief Implementation of the QDocumentLine class.
*/
#include "qdocument_p.h"
/*!
\ingroup document
@{
*/
/*!
\class QDocumentLine
\brief A reference to line objects
In QCodeEdit, documents are stored as a list of lines. A QDocumentLine
holds a pointer to the data of one line and gives access to its content.
It is not meant to be used to iterate over the document, though it is
possible for conveneience and compatibility reasons. Indeed, QDocumentLine
does not now where in the document it is located. It can obtain that
information but this is a O(n) operation. Navigation within the document is
one of the task devoted to QDocumentCursor which can move around in O(1) (or
amortized O(1) in some rare cases).
Lines can be given formatting in various way : "regular" formatting used
for highlighting, overlays used mainly to display search matches and similar
informations and marks.
*/
QDocumentLine::QDocumentLine(QDocument *doc)
: m_handle(doc ? doc->impl()->at(0) : 0) {
// m_lines_backing_store << this;
if (m_handle)
m_handle->ref();
}
QDocumentLine::QDocumentLine(const QDocumentLine &line)
: m_handle(line.m_handle) {
// m_lines_backing_store << this;
if (m_handle)
m_handle->ref();
}
QDocumentLine::QDocumentLine(QDocumentLineHandle *handle) : m_handle(handle) {
// m_lines_backing_store << this;
if (m_handle)
m_handle->ref();
}
QDocumentLine::~QDocumentLine() {
if (m_handle)
m_handle->deref();
// m_lines_backing_store.removeAll(this);
}
/*!
\brief Comparision operator
*/
bool QDocumentLine::operator==(const QDocumentLine &l) const {
return m_handle == l.m_handle;
// return lineNumber() == l.lineNumber();
}
/*!
\brief Comparision operator
*/
bool QDocumentLine::operator!=(const QDocumentLine &l) const {
return m_handle != l.m_handle;
// return lineNumber() != l.lineNumber();
}
/*!
\brief Comparision operator
\note Line number based : avoid whenever possible
*/
bool QDocumentLine::operator<(const QDocumentLine &l) const {
return lineNumber() < l.lineNumber();
}
/*!
\brief Comparision operator
\note Line number based : avoid whenever possible
*/
bool QDocumentLine::operator>=(const QDocumentLine &l) const {
return lineNumber() >= l.lineNumber();
}
/*!
\brief Comparision operator
\note Line number based : avoid whenever possible
*/
bool QDocumentLine::operator>(const QDocumentLine &l) const {
return lineNumber() > l.lineNumber();
}
/*!
\brief Comparision operator
\note Line number based : avoid whenever possible
*/
bool QDocumentLine::operator<=(const QDocumentLine &l) const {
return lineNumber() <= l.lineNumber();
}
/*!
\brief Iterate forward over the document
*/
QDocumentLine &QDocumentLine::operator++() {
operator=(next());
return *this;
}
/*!
\brief Iterate backward over the document
*/
QDocumentLine &QDocumentLine::operator--() {
operator=(previous());
return *this;
}
/*!
\brief Iterate forward over the document
*/
void QDocumentLine::operator++(int) { operator=(next()); }
/*!
\brief Iterate backward over the document
*/
void QDocumentLine::operator--(int) { operator=(previous()); }
/*!
\brief copy operator
QDocumentLine objects are just wrappers around the "real" line data.
Copies of a QDocumentLine all points to the same underlying data and
modifying one affect them all (no implicit sharing).
*/
QDocumentLine &QDocumentLine::operator=(const QDocumentLine &l) {
if (m_handle)
m_handle->deref();
m_handle = l.m_handle;
if (m_handle)
m_handle->ref();
return *this;
}
/*!
\return the document to which that line belongs
*/
QDocument *QDocumentLine::document() const {
return m_handle ? m_handle->document() : 0;
}
/*!
\return the line number of the line within the document
Starts at 0, -1 for invalid lines.
\note Avoid whenever possible : O(n) complexity, n being document size
in lines Prefer cursors over lines if you need to navigate within the
document
*/
int QDocumentLine::lineNumber() const {
return m_handle ? m_handle->line() : -1;
}
/*!
\return the position of the line within the document
\note This function is there for compatibility with QTextDocument & co
Avoid it whenever possible, it is ridiculously slow.
*/
int QDocumentLine::position() const {
return m_handle ? m_handle->position() : -1;
}
/*!
\brief Check whether a given flag is set to the line
*/
bool QDocumentLine::hasFlag(State s) const {
return m_handle ? m_handle->hasFlag(s) : false;
}
/*!
\brief Check whether any of the flags in a given combination is set to
the line
*/
bool QDocumentLine::hasAnyFlag(int s) const {
return m_handle ? m_handle->hasFlag(s) : false;
}
/*!
\brief Set a flag of the line
\warning Do not mess with flags unless you know what you are doing
*/
void QDocumentLine::setFlag(State s, bool y) {
if (m_handle)
m_handle->setFlag(s, y);
}
/*!
\return whether the line object is null (i.e invalid)
*/
bool QDocumentLine::isNull() const {
return m_handle ? !m_handle->document() : true;
}
/*!
\return whether the line object is valid
*/
bool QDocumentLine::isValid() const {
return m_handle ? !!m_handle->document() : false;
}
/*!
\return the text of the line
*/
QString QDocumentLine::text() const {
return m_handle ? m_handle->text() : QString();
}
/*!
\return The length of the line, in characters
*/
int QDocumentLine::length() const {
return m_handle ? m_handle->text().length() : 0;
}
/*!
\return the number of visual lines occupied by the line
This is NOT set to zero when the line is hidden (e.g due to folding).
*/
int QDocumentLine::lineSpan() const {
return m_handle && m_handle->document() ? m_handle->m_frontiers.count() + 1
: 0;
}
/*!
\brief Returns the position of the first non-whitespace character
\return position of first non-whitespace char or -1 if there is none
*/
int QDocumentLine::firstChar() const { return nextNonSpaceChar(0); }
/*!
\brief Returns the position of the last non-whitespace character
\return position of last non-whitespace char or -1 if there is none
*/
int QDocumentLine::lastChar() const {
return previousNonSpaceChar(length() - 1);
}
int QDocumentLine::indent() const { return m_handle ? m_handle->indent() : 0; }
/*!
Find the position of the next char that is not a space.
\param pos Column of the character which is examined first.
\return True if the specified or a following character is not a space
Otherwise false.
*/
int QDocumentLine::nextNonSpaceChar(int pos) const {
return m_handle ? m_handle->nextNonSpaceChar(pos) : -1;
}
/*!
\brief Find the position of the previous char that is not a space.
\param pos Column of the character which is examined first.
\return The position of the first non-whitespace character preceding
pos, or -1 if none is found.
*/
int QDocumentLine::previousNonSpaceChar(int pos) const {
return m_handle ? m_handle->previousNonSpaceChar(pos) : -1;
}
/*!
\return The previous line
\note Avoid using this function whenever possible, especially
inside loops or time-consuming processing : it is SLOW for big
documents as determination of the line number is O(n), n being
the total number of lines in the document
*/
QDocumentLine QDocumentLine::next() const {
return QDocumentLine(m_handle->next());
}
/*!
\return The next line
\note Avoid using this function whenever possible, especially
inside loops or time-consuming processing : it is SLOW for big
documents as determination of the line number is O(n), n being
the total number of lines in the document
*/
QDocumentLine QDocumentLine::previous() const {
return QDocumentLine(m_handle->previous());
}
/*!
\brief Converts a cursor position (column) to a document position
(unconstrained viewport)
\deprecated Use cursorToDocOffset() instead
This function is kept for compatribility only. It dates back to the time
before line wrapping was implemented. Due to the limitation of its design
(i.e signature) it works in a somewhat awkard way : the x position returned
is that the cursor would have in an unconstrained viewport, even when the
line is wrapped so it does not map to an actual viewport coordinate, unless
of course no wrapping is used.
*/
int QDocumentLine::cursorToX(int cpos) const {
return m_handle ? m_handle->cursorToX(cpos) : -1;
}
/*!
\brief Converts a document position (unconstrained viewport) to a cursor
position (column)
\deprecated Use cursorToDocOffset() instead
\see cursorToX() for more informations about this function
*/
int QDocumentLine::xToCursor(int xpos) const {
return m_handle ? m_handle->xToCursor(xpos) : -1;
}
/*!
\return The wrapped line (i.e "subline") to which a given cursor
position resides \param cpos cursor position, as a text column
*/
int QDocumentLine::wrappedLineForCursor(int cpos) const {
return m_handle ? m_handle->wrappedLineForCursor(cpos) : -1;
}
/*!
\brief Converts a document offset (viewport) to a cursor position
(character / text column)
The (x, y) coordinates given by this function are relative to the
absolute position of the line, which can be obtained from the document.
*/
int QDocumentLine::documentOffsetToCursor(int x, int y) const {
return m_handle ? m_handle->documentOffsetToCursor(x, y) : -1;
}
/*!
\brief Converts a cursor position (character / text column) to a
document offset (viewport)
The (x, y) coordinates given by this function are relative to the
absolute position of the line, which can be obtained from the document.
*/
void QDocumentLine::cursorToDocumentOffset(int cpos, int &x, int &y) const {
if (m_handle)
m_handle->cursorToDocumentOffset(cpos, x, y);
}
/*!
\overload
*/
QPoint QDocumentLine::cursorToDocumentOffset(int cpos) const {
return m_handle ? m_handle->cursorToDocumentOffset(cpos) : QPoint();
}
/*!
\brief Toggle a mark on the line
*/
void QDocumentLine::addMark(int id) {
if (!document())
return;
document()->impl()->addMark(m_handle, id);
}
/*!
\brief Toggle a mark on the line
*/
void QDocumentLine::toggleMark(int id) {
if (!document())
return;
document()->impl()->toggleMark(m_handle, id);
}
/*!
\brief Remove a mark from the line
*/
void QDocumentLine::removeMark(int id) {
if (!document())
return;
document()->impl()->removeMark(m_handle, id);
}
/*!
\return the list of marks set on this line
*/
QList<int> QDocumentLine::marks() const {
return document() ? document()->impl()->marks(m_handle) : QList<int>();
}
/*!
\return Whether a given mark has been set on the line
*/
bool QDocumentLine::hasMark(int id) const { return marks().contains(id); }
/*!
\brief Set the formatting of the line
\note this method is made available for syntax engine use.
If you want to apply extra formatting on a line use overlays
instead
\see addOverlay()
*/
void QDocumentLine::setFormats(const QVector<int> &formats) {
if (!m_handle)
return;
m_handle->setFormats(formats);
}
/*!
\return whether the line has at least one overlay of a given format id
*/
bool QDocumentLine::hasOverlay(int fid) const {
if (!m_handle)
return false;
foreach (const QFormatRange &r, m_handle->m_overlays)
if (r.format == fid)
return true;
return false;
}
/*!
\brief Clear all overlays applied to the line
*/
QList<QFormatRange> QDocumentLine::overlays() const {
if (!m_handle)
return QList<QFormatRange>();
return m_handle->m_overlays;
}
/*!
\brief Clear all overlays applied to the line
*/
void QDocumentLine::clearOverlays() {
if (!m_handle)
return;
m_handle->clearOverlays();
}
/*!
\brief Add an overlay to the line
Overlays are format range that get applied on top of regular formatting.
They are typically used to display search matches, matching braces, ...
*/
void QDocumentLine::addOverlay(const QFormatRange &over) {
if (!m_handle)
return;
m_handle->addOverlay(over);
}
/*!
\brief Remove an overlay from the line
*/
void QDocumentLine::removeOverlay(const QFormatRange &over) {
if (!m_handle)
return;
m_handle->removeOverlay(over);
}
/*!
\return the list of parentheses present on the line
\note This is language dependent.
*/
const QVector<QParenthesis> &QDocumentLine::parentheses() const {
Q_CHECK_PTR(m_handle);
return m_handle->m_parens;
}
/*!
\brief Set the parentheses present on that line
\note this should only be used by syntax engines
*/
void QDocumentLine::setParentheses(const QVector<QParenthesis> &parentheses) {
if (!m_handle)
return;
m_handle->m_parens = parentheses;
}
/*!
Reserved to syntax engines. do not mess with this unless you know what
you are doing.
*/
QNFAMatchContext *QDocumentLine::matchContext() {
return m_handle ? &m_handle->m_context : 0;
}
/*! @} */

View File

@ -1,175 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QDOCUMENT_LINE_H_
#define _QDOCUMENT_LINE_H_
#include "qce-config.h"
/*!
\file qdocumentline.h
\brief Definition of the QDocumentLine class
*/
#include "qformat.h"
class QPoint;
class QString;
class QDocument;
class QDocumentLineHandle;
struct QNFAMatchContext;
class QParenthesis {
public:
enum Role { Open = 1, Close = 2, Indent = 4, Fold = 8, Match = 16 };
inline QParenthesis() : id(0), role(0), offset(0), length(0) {}
inline QParenthesis(int i, quint8 r, int pos, int len)
: id(i), role(r), offset(pos), length(len) {}
int id;
int role;
int offset;
int length;
};
Q_DECLARE_TYPEINFO(QParenthesis, Q_MOVABLE_TYPE);
class QCE_EXPORT QDocumentLine {
friend class QDocumentLineHandle;
friend class QDocumentCursorHandle;
public:
enum State {
None = 0,
Hidden = 1,
CollapsedBlockStart = 2,
CollapsedBlockEnd = 4,
LayoutDirty = 16,
FormatsApplied = 32
};
Q_DECLARE_FLAGS(States, State);
explicit QDocumentLine(QDocument *doc);
QDocumentLine(const QDocumentLine &line);
QDocumentLine(QDocumentLineHandle *h = 0);
~QDocumentLine();
bool isNull() const;
bool isValid() const;
inline bool operator==(const QDocumentLineHandle *h) const {
return m_handle == h;
}
inline bool operator!=(const QDocumentLineHandle *h) const {
return m_handle != h;
}
bool operator==(const QDocumentLine &l) const;
bool operator!=(const QDocumentLine &l) const;
bool operator<(const QDocumentLine &l) const;
bool operator>=(const QDocumentLine &l) const;
bool operator>(const QDocumentLine &l) const;
bool operator<=(const QDocumentLine &l) const;
QDocumentLine &operator++();
QDocumentLine &operator--();
void operator++(int);
void operator--(int);
QDocumentLine &operator=(const QDocumentLine &l);
int lineNumber() const;
int position() const;
QString text() const;
int length() const;
int lineSpan() const;
int firstChar() const;
int lastChar() const;
int indent() const;
int nextNonSpaceChar(int pos) const;
int previousNonSpaceChar(int pos) const;
inline QString indentation() const {
int idx = firstChar();
return idx != -1 ? text().left(idx) : text();
}
inline bool isHidden() const { return hasFlag(Hidden); }
bool hasFlag(State s) const;
bool hasAnyFlag(int s) const;
void setFlag(State s, bool y = true);
QDocumentLine next() const;
QDocumentLine previous() const;
QDocument *document() const;
int xToCursor(int x) const;
int cursorToX(int cpos) const;
int wrappedLineForCursor(int cpos) const;
int documentOffsetToCursor(int x, int y) const;
void cursorToDocumentOffset(int cpos, int &x, int &y) const;
QPoint cursorToDocumentOffset(int cpos) const;
void addMark(int id);
void removeMark(int id);
void toggleMark(int id);
QList<int> marks() const;
bool hasMark(int id) const;
bool hasOverlay(int fid) const;
QList<QFormatRange> overlays() const;
void clearOverlays();
void addOverlay(const QFormatRange &over);
void removeOverlay(const QFormatRange &over);
void setFormats(const QVector<int> &formats);
const QVector<QParenthesis> &parentheses() const;
void setParentheses(const QVector<QParenthesis> &parentheses);
inline QDocumentLineHandle *handle() const { return m_handle; }
QNFAMatchContext *matchContext();
private:
QDocumentLineHandle *m_handle;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QDocumentLine::States)
#endif

View File

@ -1,155 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QDOCUMENT_LINE_P_H_
#define _QDOCUMENT_LINE_P_H_
#include "qce-config.h"
/*!
\file qdocumentline_p.h
\brief Definition of QDocumentLineHandle
*/
#include "qnfa.h"
#include "qformat.h"
#include "qdocumentline.h"
#include <QList>
#include <QPair>
#include <QString>
#include <QVector>
#include <QTextLayout>
#if QT_VERSION < 0x040400
#include <QAtomic>
#else
#include <QAtomicInt>
#endif
typedef QVector<int> QSmallArray;
typedef QVector<int> QMediumArray;
class QPoint;
class QDocument;
class QDocumentLine;
class QDocumentBuffer;
class QDocumentPrivate;
class QCE_EXPORT QDocumentLineHandle {
friend class QDocument;
friend class QDocumentLine;
friend class QDocumentBuffer;
friend class QDocumentPrivate;
public:
QDocumentLineHandle(QDocument *d);
QDocumentLineHandle(const QString &s, QDocument *d);
int length() const;
int position() const;
QString text() const;
int line() const;
int xToCursor(int x) const;
int cursorToX(int i) const;
int wrappedLineForCursor(int cpos) const;
int documentOffsetToCursor(int x, int y) const;
void cursorToDocumentOffset(int cpos, int &x, int &y) const;
QPoint cursorToDocumentOffset(int cpos) const;
int indent() const;
int nextNonSpaceChar(uint pos) const;
int previousNonSpaceChar(int pos) const;
bool hasFlag(int flag) const;
void setFlag(int flag, bool y = true) const;
QDocument *document() const;
QDocumentLineHandle *next() const;
QDocumentLineHandle *previous() const;
void updateWrap() const;
void setFormats(const QVector<int> &formats);
void clearOverlays();
void addOverlay(const QFormatRange &over);
void removeOverlay(const QFormatRange &over);
void shiftOverlays(int position, int offset);
void draw(QPainter *p, int xOffset, int vWidth, const QSmallArray &sel,
const QSmallArray &cursors, const QPalette &pal,
bool fullSel) const;
inline QString &textBuffer() {
setFlag(QDocumentLine::LayoutDirty, true);
return m_text;
}
inline void ref() { m_ref.ref(); }
inline void deref() {
if (m_ref)
m_ref.deref();
if (!m_ref)
delete this;
}
protected:
~QDocumentLineHandle();
private:
void layout() const;
void applyOverlays() const;
QMediumArray compose() const;
QVector<QTextLayout::FormatRange> decorations() const;
QString m_text;
QDocument *m_doc;
#if QT_VERSION < 0x040400
QBasicAtomic m_ref;
#else
QAtomicInt m_ref;
#endif
mutable int m_indent;
mutable quint16 m_state;
mutable QTextLayout *m_layout;
mutable QVector<int> m_cache;
mutable QVector<QPair<int, int>> m_frontiers;
QNFAMatchContext m_context;
QVector<int> m_formats;
QVector<QParenthesis> m_parens;
QList<QFormatRange> m_overlays;
};
Q_DECLARE_TYPEINFO(QDocumentLineHandle *, Q_PRIMITIVE_TYPE);
#endif // !_QDOCUMENT_LINE_P_H_

View File

@ -1,143 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QCE_CONFIG_H_
#define _QCE_CONFIG_H_
/*!
\file qce-config.h
\brief Utility file for shared library creation
*/
#include <qglobal.h>
/*!
\macro QCE_EXPORT
\brief Macro needed for cross-platform shared libraries creation
*/
#ifdef QCE_EXPORT
// QCE_EXPORT manually defined, trust the user
#else
#ifdef _QCODE_EDIT_BUILD_
#ifdef _QCODE_EDIT_EMBED_
#define QCE_EXPORT
#else
#define QCE_EXPORT Q_DECL_EXPORT
#endif
#else
#define QCE_EXPORT Q_DECL_IMPORT
#endif
#endif
#include <QString>
#include <QStringList>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QStringConverter>
#else
#include <QTextCodec>
#endif
namespace QCE {
QString fetchDataFile(const QString &file);
QStringList dataPathes();
void addDataPath(const QString &path);
template <typename Registerable>
class Registar {
public:
constexpr Registar() { Registerable::_register(); }
};
// added by wingsummer
Q_DECL_UNUSED static QStringList getEncodings() {
static QStringList encodings;
if (encodings.isEmpty()) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
for (auto e = 0; e < int(QStringConverter::Encoding::LastEncoding);
++e) {
auto ee = QStringConverter::nameForEncoding(
QStringConverter::Encoding(e));
if (ee == QStringLiteral("ISO-8859-1")) {
encodings << QStringLiteral("ASCII");
}
encodings << ee;
}
#else
for (auto &e : QTextCodec::availableCodecs()) {
if (e == QStringLiteral("ISO-8859-1")) {
encodings << QStringLiteral("ASCII");
} else {
encodings << e;
}
}
#endif
}
return encodings;
}
Q_DECL_UNUSED static QString convertString(const QString &encoding,
const QByteArray &data) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto en = encoding;
if (en.isEmpty() ||
en.compare(QStringLiteral("ASCII"), Qt::CaseInsensitive) == 0) {
en = QStringLiteral("ISO-8859-1");
}
auto enc = QStringConverter::encodingForName(en.toUtf8());
if (enc) {
QStringDecoder decoder(enc.value());
return decoder(data);
} else {
// Handle the case where the encoding is not recognized
auto unicode = QString::fromUtf8(data); // Fallback to UTF-8
return unicode;
}
#else
auto enc = QTextCodec::codecForName(encoding.toUtf8());
auto d = enc->makeDecoder();
auto unicode = d->toUnicode(data);
return unicode;
#endif
}
Q_DECL_UNUSED static QByteArray convertByteArray(const QString &encoding,
const QString &data) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto enc = QStringConverter::encodingForName(encoding.toUtf8());
if (enc) {
QStringEncoder decoder(enc.value());
return decoder.encode(data);
} else {
// Handle the case where the encoding is not recognized
auto unicode = data.toUtf8(); // Fallback to UTF-8
return unicode;
}
#else
auto enc = QTextCodec::codecForName(encoding.toUtf8());
auto d = enc->makeEncoder();
auto unicode = d->fromUnicode(data);
return unicode;
#endif
}
} // namespace QCE
#define QCE_AUTO_REGISTER(T) static QCE::Registar<T> _auto_##T##_registar;
#endif // !_QCE_CONFIG_H_

View File

@ -1,273 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qcodecompletionengine.h"
/*!
\file qcompletionengine.cpp
\brief Implementation of the QCodeCompletionEngine class.
*/
#include "qeditor.h"
#include <QAction>
#include <QKeyEvent>
#include <QTextCursor>
/*!
*/
QCodeCompletionEngine::QCodeCompletionEngine(QObject *p)
: QObject(p), m_max(0), m_trigWordLen(-1) {
pForcedTrigger = new QAction(tr("&Trigger completion"), this);
connect(pForcedTrigger, SIGNAL(triggered()), this, SLOT(complete()));
}
/*!
*/
QCodeCompletionEngine::~QCodeCompletionEngine() {}
/*!
\return
*/
QAction *QCodeCompletionEngine::triggerAction() const { return pForcedTrigger; }
/*!
*/
void QCodeCompletionEngine::retranslate() {
pForcedTrigger->setText(tr("&Trigger completion"));
}
/*!
*/
QStringList QCodeCompletionEngine::triggers() const { return m_triggers; }
/*!
*/
void QCodeCompletionEngine::addTrigger(const QString &s) {
if (m_triggers.contains(s))
return;
if (s.length() > m_max)
m_max = s.length();
m_triggers << s;
}
/*!
*/
void QCodeCompletionEngine::removeTrigger(const QString &s) {
m_triggers.removeAll(s);
}
/*!
*/
QEditor *QCodeCompletionEngine::editor() const { return pEdit; }
/*!
\brief Attach the completion engine instance to a new editor object
*/
void QCodeCompletionEngine::setEditor(QEditor *e) {
if (pEdit) {
pEdit->removeAction(pForcedTrigger, tr("&Edit"));
// pEdit->removeEventFilter(this);
disconnect(pEdit, SIGNAL(textEdited(QKeyEvent *)), this,
SLOT(textEdited(QKeyEvent *)));
}
pEdit = e;
if (pEdit) {
// pEdit->installEventFilter(this);
pEdit->addAction(pForcedTrigger, tr("&Edit"));
connect(pEdit, &QEditor::textEdited, this,
&QCodeCompletionEngine::textEdited);
}
}
/*!
\internal
*/
void QCodeCompletionEngine::run() {
if (m_cur.isNull())
return;
// qDebug("complete!");
complete(m_cur, m_trig);
m_cur = QDocumentCursor();
m_trig.clear();
}
/*!
\brief Forced completion trigger
*/
void QCodeCompletionEngine::complete(const QString &trigger) {
complete(editor()->cursor(), trigger);
}
/*!
\brief Standard completion entry point for QEditor
\param e QKeyEvent that caused a modification of the text
\note This slot is only called when editing happens without
any cursor mirrors
*/
void QCodeCompletionEngine::textEdited(QKeyEvent *k) {
QString s, txt = s = k->text();
QDocumentCursor cur = editor()->cursor();
auto count = txt.length();
if (txt.isEmpty()) {
return;
}
if (m_triggers.isEmpty()) {
triggerWordLenComplete();
return;
}
// qDebug("should trigger completion? (bis)");
if (count > m_max) {
txt = txt.right(m_max);
} else if (count < m_max) {
QDocumentCursor c(cur);
c.movePosition(m_max, QDocumentCursor::Left,
QDocumentCursor::KeepAnchor);
// qDebug("prev text : %s", qPrintable(c.selectedText()));
txt = c.selectedText();
}
// qDebug("text : %s", qPrintable(txt));
for (auto &trig : m_triggers) {
if (txt.endsWith(trig)) {
cur = editor()->cursor();
cur.movePosition(trig.size(), QDocumentCursor::PreviousCharacter);
// notify completion trigger
emit completionTriggered(trig);
// get rid of previous calltips/completions
editor()->setFocus();
// trigger completion
complete(cur, trig);
return;
}
}
triggerWordLenComplete();
}
/*!
\internal
*/
bool QCodeCompletionEngine::eventFilter(QObject *o, QEvent *e) {
if (!e || !o || (e->type() != QEvent::KeyPress) || (o != pEdit))
return false;
// qDebug("should trigger completion?");
QDocumentCursor cur = editor()->cursor();
QKeyEvent *k = static_cast<QKeyEvent *>(e);
QString s, txt = s = k->text();
auto count = txt.length();
if (txt.isEmpty() || m_triggers.isEmpty())
return false; // QThread::eventFilter(o, e);
// qDebug("should trigger completion? (bis)");
if (count > m_max) {
txt = txt.right(m_max);
} else if (count < m_max) {
QDocumentCursor c(cur);
c.movePosition(m_max - count, QDocumentCursor::Left,
QDocumentCursor::KeepAnchor);
// qDebug("prev text : %s", qPrintable(c.selectedText()));
txt.prepend(c.selectedText());
}
// qDebug("text : %s", qPrintable(txt));
for (auto &trig : m_triggers) {
if (txt.endsWith(trig)) {
editor()->write(s);
cur = editor()->cursor();
cur.movePosition(trig.length(), QDocumentCursor::PreviousCharacter);
// notify completion trigger
emit completionTriggered(trig);
// get rid of previous calltips/completions
editor()->setFocus();
// trigger completion
complete(cur, trig);
return true;
}
}
return false;
}
/*!
\brief Completion callback
*/
void QCodeCompletionEngine::complete(const QDocumentCursor &c,
const QString &trigger) {
Q_UNUSED(c)
Q_UNUSED(trigger)
qWarning("From complete(QDocumentCursor, QString)");
qWarning("QCodeCompletionEngine is not self-sufficient : subclasses should "
"reimplement at least one of the complete() method...");
}
void QCodeCompletionEngine::triggerWordLenComplete() {
if (m_trigWordLen > 0) {
QDocumentCursor cur = editor()->cursor();
emit completionTriggered({});
complete(cur, {});
}
}
qsizetype QCodeCompletionEngine::trigWordLen() const { return m_trigWordLen; }
void QCodeCompletionEngine::setTrigWordLen(qsizetype newTrigWordLen) {
m_trigWordLen = newTrigWordLen;
}

View File

@ -1,97 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QCOMPLETION_ENGINE_H_
#define _QCOMPLETION_ENGINE_H_
#include "qce-config.h"
/*!
\file qcompletionengine.h
\brief Definition of the QCodeCompletionEngine class.
*/
#include "qdocumentcursor.h"
#include <QObject>
#include <QPointer>
#include <QStringList>
class QEditor;
class QAction;
class QKeyEvent;
class QCodeModel;
class QCodeStream;
class QCE_EXPORT QCodeCompletionEngine : public QObject {
Q_OBJECT
public:
QCodeCompletionEngine(QObject *p = nullptr);
virtual ~QCodeCompletionEngine();
virtual QCodeCompletionEngine *clone() = 0;
virtual QString language() const = 0;
virtual QStringList extensions() const = 0;
QAction *triggerAction() const;
QEditor *editor() const;
virtual void setEditor(QEditor *e);
QStringList triggers() const;
void addTrigger(const QString &s);
void removeTrigger(const QString &s);
virtual void retranslate();
qsizetype trigWordLen() const;
void setTrigWordLen(qsizetype newTrigWordLen);
signals:
void popup();
void cloned(QCodeCompletionEngine *e);
void completionTriggered(const QString &s);
public slots:
void complete(const QString &trigger = {});
// make it public
virtual void complete(const QDocumentCursor &c, const QString &trigger);
void textEdited(QKeyEvent *e);
protected:
virtual void run();
virtual bool eventFilter(QObject *o, QEvent *e);
private:
void triggerWordLenComplete();
private:
qsizetype m_max;
qsizetype m_trigWordLen;
QString m_trig;
QDocumentCursor m_cur;
QAction *pForcedTrigger;
QStringList m_triggers;
QPointer<QEditor> pEdit;
};
#endif // _QCOMPLETION_ENGINE_H_

View File

@ -1,409 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qcodeedit.h"
/*!
\file qcodeedit.cpp
\brief Implementation of the QCodeEdit class
*/
#include "qeditor.h"
#include "qpanel.h"
#include "qpanellayout.h"
#include <QAction>
#include <QDir>
#include <QEvent>
#include <QFileInfo>
#include <QMenu>
#include <QMetaObject>
#include <QStringList>
/*!
\class QCodeEdit
\brief A thin layer over QEditor
The QCodeEdit class provides simple means to associate panels with
editors and manage them.
*/
/*!
\internal
\class QPanelWatcher
A class designed to work around some limitations of the hide/show event
system and allow proper setting and conservation of default visibility for
panels.
*/
class QPanelWatcher : public QObject {
public:
QPanelWatcher(QCodeEdit *e) : qce(e) {}
bool eventFilter(QObject *o, QEvent *e) {
QPanel *p = qobject_cast<QPanel *>(o);
QAction *a = qce->toggleViewAction(p);
if (a) {
bool sig = a->signalsBlocked();
a->blockSignals(true);
if (a->isChecked() && e->type() == QEvent::Hide)
a->setChecked(false);
else if (!a->isChecked() && e->type() == QEvent::Show)
a->setChecked(true);
a->blockSignals(sig);
}
return QObject::eventFilter(o, e);
}
private:
QCodeEdit *qce;
};
QStringList __qce_data_path;
/*!
\brief Centralized access point to data fetching
*/
QString QCE::fetchDataFile(const QString &file) {
if (QFileInfo(file).isAbsolute())
return file;
foreach (QString dp, __qce_data_path) {
QDir d(dp);
if (d.exists(file))
return d.absoluteFilePath(file);
}
return file;
}
/*!
\return The list of pathes used by QCE to fetch data
*/
QStringList QCE::dataPathes() { return __qce_data_path; }
/*!
\brief Add a path to the list of pathes used to fetch data
*/
void QCE::addDataPath(const QString &path) {
if (!__qce_data_path.contains(path))
__qce_data_path << path;
}
QList<QCodeEdit *> QCodeEdit::m_instances;
/*!
\brief ctor
The created editor object comes with builtin actions.
*/
QCodeEdit::QCodeEdit(QWidget *p) : m_panelsMenu(0) {
m_editor = new QEditor(p);
m_watcher = new QPanelWatcher(this);
m_layout = new QPanelLayout(m_editor);
m_instances << this;
}
/*!
\brief ctor
\param actions whether the QEditor object should create builtin actions
*/
QCodeEdit::QCodeEdit(bool actions, QWidget *p) : m_panelsMenu(0) {
m_editor = new QEditor(actions, p);
m_watcher = new QPanelWatcher(this);
m_layout = new QPanelLayout(m_editor);
m_instances << this;
}
/*!
\brief ctor
\param layout structure of the panel layout
The created editor object comes with builtin actions.
*/
QCodeEdit::QCodeEdit(const QString &layout, QWidget *p) : m_panelsMenu(0) {
m_editor = new QEditor(p);
m_watcher = new QPanelWatcher(this);
m_layout = new QPanelLayout(layout, m_editor);
m_instances << this;
}
/*!
\brief ctor
\param layout structure of the panel layout
\param actions whether the QEditor object should create builtin actions
*/
QCodeEdit::QCodeEdit(const QString &layout, bool actions, QWidget *p)
: m_panelsMenu(0) {
m_editor = new QEditor(actions, p);
m_watcher = new QPanelWatcher(this);
m_layout = new QPanelLayout(layout, m_editor);
m_instances << this;
}
/*!
\brief ctor
\param e editor to manage
\param p panel layout to associate with the editor
*/
QCodeEdit::QCodeEdit(QEditor *e, QPanelLayout *p) : m_panelsMenu(0) {
m_editor = e;
m_watcher = new QPanelWatcher(this);
m_layout = p ? p : new QPanelLayout(m_editor);
m_instances << this;
}
/*!
\brief ctor
\param e editor to manage
\param l structure of the panel layout
*/
QCodeEdit::QCodeEdit(QEditor *e, const QString &l) : m_panelsMenu(0) {
m_editor = e;
m_watcher = new QPanelWatcher(this);
m_layout = new QPanelLayout(l, m_editor);
m_instances << this;
}
/*!
\brief dtor
\warning Destroyes the editor and the panel layout it manages
*/
QCodeEdit::~QCodeEdit() {
m_instances.removeAll(this);
delete m_watcher;
delete m_editor;
delete m_layout;
}
/*!
\return the managed editor
*/
QEditor *QCodeEdit::editor() const { return m_editor; }
/*!
\return the panel layout associated with the managed editor
*/
QPanelLayout *QCodeEdit::panelLayout() const { return m_layout; }
/*!
\brief Add a panel
\return Toggle view action for the added panel
\param panel panel to add
\param pos position of the panel in the layout
\param _add whether to add the show action of the panel to the menu of
the editor
*/
QAction *QCodeEdit::addPanel(QPanel *panel, Position pos, bool _add) {
panel->attach(m_editor);
QAction *a = new QAction(panel->name(), m_editor);
a->setCheckable(true);
a->setChecked(panel->defaultVisibility());
QObject::connect(a, SIGNAL(toggled(bool)), panel, SLOT(setVisible(bool)));
m_layout->addWidget(panel, QPanelLayout::Position(pos));
m_layout->update();
m_actions << a;
panel->installEventFilter(m_watcher);
if (_add) {
if (!m_panelsMenu) {
m_panelsMenu = new QMenu(QEditor::tr("Panels"), m_editor);
m_panelsMenu->menuAction()->setObjectName("panels");
m_editor->addAction(m_panelsMenu->menuAction(),
QEditor::tr("&View"), QString());
}
m_panelsMenu->addAction(a);
}
return a;
}
/*!
\overload
\return Toggle view action for the added panel
\param name name of panel to add
\param pos position of the panel in the layout
\param _add whether to add the show action of the panel to the menu of
the editor
*/
QAction *QCodeEdit::addPanel(const QString &name, Position pos, bool _add) {
return addPanel(QPanel::panel(name, m_editor), pos, _add);
}
/*!
\return whether the editor has a panel of the given \a type
*/
bool QCodeEdit::hasPanel(const QString &type) const {
if (!m_layout)
return false;
QList<QPanel *> l = m_layout->panels();
foreach (QPanel *p, l)
if (p->type() == type)
return true;
return false;
}
/*!
\return a list of panels added to the editor
\param type Type of panel to look for (no filtering is performed if
empty)
*/
QList<QPanel *> QCodeEdit::panels(const QString &type) const {
if (!m_layout)
return QList<QPanel *>();
QList<QPanel *> l = m_layout->panels();
if (type.isEmpty())
return l;
int i = 0;
while (i < l.count()) {
if (l.at(i)->type() == type) {
++i;
} else {
l.removeAt(i);
}
}
return l;
}
/*!
\return the toggle view action of a given panel
*/
QAction *QCodeEdit::toggleViewAction(QPanel *p) const {
int idx = panels().indexOf(p);
return idx == -1 ? 0 : m_actions.at(idx);
}
/*!
\brief Send a command to every panel of a given type
\param signature method name suitable for QMetaObject::invokeMethod()
\param args list of arguments suitable for QMetaObject::invokeMethod()
Example use :
\code
sendPanelCommand("Status", "setVisible" Q_COMMAND << Q_ARG(bool,
false)); \endcode
*/
void QCodeEdit::sendPanelCommand(const QString &type, const char *signature,
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
const QList<QMetaMethodArgument> &args) {
#else
const QList<QGenericArgument> &args) {
#endif
QList<QPanel *> lp = panels();
// qDebug("looking for panel of type %s", qPrintable(type));
foreach (QPanel *p, lp) {
if (p && (p->type() == type)) {
// qDebug("found.");
// TODO : ask trolltech to provide an overloaded invokeMetaMethod()
// taking a QList<> instead of nine defaulted args...
if (args.isEmpty())
QMetaObject::invokeMethod(p, signature);
else if (args.count() == 1)
QMetaObject::invokeMethod(p, signature, args.at(0));
else if (args.count() == 2)
QMetaObject::invokeMethod(p, signature, args.at(0), args.at(1));
else if (args.count() == 3)
QMetaObject::invokeMethod(p, signature, args.at(0), args.at(1),
args.at(2));
else if (args.count() == 4)
QMetaObject::invokeMethod(p, signature, args.at(0), args.at(1),
args.at(2), args.at(3));
else if (args.count() == 5)
QMetaObject::invokeMethod(p, signature, args.at(0), args.at(1),
args.at(2), args.at(3), args.at(4));
else if (args.count() == 6)
QMetaObject::invokeMethod(p, signature, args.at(0), args.at(1),
args.at(2), args.at(3), args.at(4),
args.at(5));
else if (args.count() == 7)
QMetaObject::invokeMethod(p, signature, args.at(0), args.at(1),
args.at(2), args.at(3), args.at(4),
args.at(5), args.at(6));
else if (args.count() == 7)
QMetaObject::invokeMethod(p, signature, args.at(0), args.at(1),
args.at(2), args.at(3), args.at(4),
args.at(5), args.at(6));
else if (args.count() == 8)
QMetaObject::invokeMethod(p, signature, args.at(0), args.at(1),
args.at(2), args.at(3), args.at(4),
args.at(5), args.at(6), args.at(7));
else if (args.count() == 9)
QMetaObject::invokeMethod(p, signature, args.at(0), args.at(1),
args.at(2), args.at(3), args.at(4),
args.at(5), args.at(7), args.at(8));
else if (args.count() == 10)
QMetaObject::invokeMethod(p, signature, args.at(0), args.at(1),
args.at(2), args.at(3), args.at(4),
args.at(5), args.at(7), args.at(8),
args.at(9));
}
}
}
/*!
\return The QCodeEdit object managing a given editor or a null point if
the given editor is unmanaged
*/
QCodeEdit *QCodeEdit::manager(QEditor *e) {
foreach (QCodeEdit *m, m_instances)
if (m->m_editor == e)
return m;
return 0;
}
/*!
\brief The (first) managed editor editing a given file or a null pointer
if none found
*/
QEditor *QCodeEdit::managed(const QString &f) {
foreach (QCodeEdit *m, m_instances)
if (m && m->m_editor && (m->m_editor->fileName() == f))
return m->m_editor;
return 0;
}

View File

@ -1,94 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QCODE_EDIT_H_
#define _QCODE_EDIT_H_
#include "qce-config.h"
/*!
\file qcodeedit.h
\brief Definition of the QCodeEdit class
*/
#include <QList>
#include <QPointer>
class QMenu;
class QPanel;
class QEditor;
class QWidget;
class QString;
class QAction;
class QPanelLayout;
class QPanelWatcher;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QMetaMethodArgument>
#define Q_COMMAND QList<QMetaMethodArgument>()
#else
#include <QGenericArgument>
#define Q_COMMAND QList<QGenericArgument>()
#endif
class QCE_EXPORT QCodeEdit {
friend class QPanelWatcher;
public:
enum Position { West, North, South, East };
QCodeEdit(QWidget *p = nullptr);
QCodeEdit(bool actions, QWidget *p = nullptr);
QCodeEdit(const QString &layout, QWidget *p = nullptr);
QCodeEdit(const QString &layout, bool actions, QWidget *p = nullptr);
virtual ~QCodeEdit();
QEditor *editor() const;
QPanelLayout *panelLayout() const;
QAction *addPanel(QPanel *panel, Position pos, bool _add = false);
QAction *addPanel(const QString &name, Position pos, bool _add = false);
bool hasPanel(const QString &type) const;
QList<QPanel *> panels(const QString &type = QString()) const;
QAction *toggleViewAction(QPanel *p) const;
void sendPanelCommand(const QString &type, const char *signature,
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
const QList<QMetaMethodArgument> &args = Q_COMMAND);
#else
const QList<QGenericArgument> &args = Q_COMMAND);
#endif
static QCodeEdit *manager(QEditor *e);
static QEditor *managed(const QString &f);
// protected:
QCodeEdit(QEditor *e, QPanelLayout *p);
QCodeEdit(QEditor *e, const QString &l);
private:
QPanelWatcher *m_watcher;
QPointer<QEditor> m_editor;
QPointer<QPanelLayout> m_layout;
QMenu *m_panelsMenu;
QList<QAction *> m_actions;
static QList<QCodeEdit *> m_instances;
};
#endif // _QCODE_EDIT_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,462 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QEDITOR_H_
#define _QEDITOR_H_
#include "qce-config.h"
/*!
\file qeditor.h
\brief Definition of the QEditor class
*/
#include <QAbstractScrollArea>
#include <QBasicTimer>
#include <QFontMetrics>
#include <QHash>
#include <QPointer>
#include <QScrollBar>
#include "qdocument.h"
#include "qdocumentcursor.h"
class QMenu;
class QAction;
class QMimeData;
class QActionGroup;
class QReliableFileWatch;
class QDocumentLineHandle;
class QLanguageDefinition;
class QCodeCompletionEngine;
class QCE_EXPORT QEditor : public QAbstractScrollArea {
friend class QEditConfig;
friend class QEditorFactory;
Q_OBJECT
public:
enum CodecUpdatePolicy {
NoUpdate = 0,
UpdateOld = 1,
UpdateDefault = 2,
UpdateCustom = 4,
UpdateAll = 7
};
enum EditFlag {
None = 0,
Overwrite = 0x001,
CursorOn = 0x002,
ReadOnly = 0x004,
MousePressed = 0x008,
MaybeDrag = 0x010,
Selection = 0x020,
EnsureVisible = 0x040,
FoldedCursor = 0x100,
Internal = 0x00000fff,
LineWrap = 0x00001000,
CtrlNavigation = 0x00010000,
CursorJumpPastWrap = 0x00020000,
ReplaceTabs = 0x00100000,
RemoveTrailing = 0x00200000,
PreserveTrailingIndent = 0x00400000,
AdjustIndent = 0x00800000,
AutoCloseChars = 0x01000000,
AutoIndent = 0x02000000,
Accessible = 0xfffff000
};
Q_DECLARE_FLAGS(State, EditFlag)
struct PlaceHolder {
class Affector {
public:
virtual ~Affector() {}
virtual void affect(const QStringList &base, int ph,
const QKeyEvent *e, int mirror,
QString &after) const = 0;
};
PlaceHolder() : length(0), autoRemove(false), affector(0) {}
PlaceHolder(const PlaceHolder &ph)
: length(ph.length), autoRemove(ph.autoRemove),
affector(ph.affector) {
cursor = ph.cursor;
mirrors << ph.mirrors;
}
int length;
bool autoRemove;
Affector *affector;
QDocumentCursor cursor;
QList<QDocumentCursor> mirrors;
};
explicit QEditor(QWidget *p = nullptr);
explicit QEditor(bool actions, QWidget *p = nullptr);
virtual ~QEditor();
bool flag(EditFlag) const;
bool canUndo() const;
bool canRedo() const;
QString text() const;
QString text(int line) const;
QString codecName() const;
QDocument *document() const;
bool isCursorVisible() const;
QDocumentCursor cursor() const;
int cursorMirrorCount() const;
QDocumentCursor cursorMirror(int i) const;
QLanguageDefinition *languageDefinition() const;
QCodeCompletionEngine *completionEngine() const;
QAction *action(const QString &s);
virtual QRect cursorRect() const;
virtual QRect selectionRect() const;
virtual QRect lineRect(int line) const;
virtual QRect lineRect(const QDocumentLine &l) const;
virtual QRect cursorRect(const QDocumentCursor &c) const;
QString name() const;
QString fileName() const;
bool isContentModified() const;
bool isInConflict() const;
int wrapWidth() const;
inline int horizontalOffset() const {
return horizontalScrollBar()->isVisible()
? horizontalScrollBar()->value()
: 0;
}
inline int verticalOffset() const {
return verticalScrollBar()->isVisible()
? verticalScrollBar()->value() *
m_doc->fontMetrics().lineSpacing()
: 0;
}
inline QPoint mapToContents(const QPoint &point) const {
return QPoint(point.x() + horizontalOffset(),
point.y() + verticalOffset());
}
inline QPoint mapFromContents(const QPoint &point) const {
return QPoint(point.x() - horizontalOffset(),
point.y() - verticalOffset());
}
void createSimpleBasicContextMenu(bool shortcut, bool extTool);
virtual bool protectedCursor(const QDocumentCursor &c) const;
static int defaultFlags();
static void setDefaultFlags(int f);
static QFont defaultFont();
static void setDefaultFont(const QFont &font);
static int defaultTabStop();
static void setDefaultTabStop(int tabstop);
static QDocument::LineEnding defaultLineEnding();
static void setDefaultLineEnding(QDocument::LineEnding le);
static QDocument::WhiteSpaceMode defaultShowSpaces();
static void setDefaultShowSpaces(QDocument::WhiteSpaceMode y);
static QString defaultCodecName();
static void setDefaultCodec(const QString &name, int update);
static inline const QList<QEditor *> &editors() { return m_editors; }
public slots:
void undo();
void redo();
virtual void cut();
virtual void copy();
virtual void paste();
void clear();
void selectAll();
void find();
void findNext();
void replace();
void gotoLine();
void indentSelection();
void unindentSelection();
void commentSelection();
void uncommentSelection();
void setLineWrapping(bool on);
virtual bool save();
bool save(const QString &filename);
virtual void print();
virtual void retranslate();
virtual void write(const QString &s, const QString &sfmtID = {});
void addAction(QAction *a, const QString &menu,
const QString &toolbar = QString());
void removeAction(QAction *a, const QString &menu,
const QString &toolbar = QString());
bool load(const QString &file);
void setText(const QString &s);
void setCodec(const QString &name);
void setDocument(QDocument *d);
void setCursor(const QDocumentCursor &c);
void setLanguageDefinition(QLanguageDefinition *d);
void setCompletionEngine(QCodeCompletionEngine *e);
void setScaleRate(qreal rate);
void setPanelMargins(int l, int t, int r, int b);
void getPanelMargins(int *l, int *t, int *r, int *b) const;
void setTitle(const QString &title);
void highlight();
void clearPlaceHolders();
void removePlaceHolder(int i);
void addPlaceHolder(const QEditor::PlaceHolder &p, bool autoUpdate = true);
void nextPlaceHolder();
void previousPlaceHolder();
void setPlaceHolder(int i);
void setUndoRedoEnabled(bool b);
void setCursorMirrorEnabled(bool b);
virtual void setFileName(const QString &f);
public:
int placeHolderCount() const;
int currentPlaceHolder() const;
qreal scaleRate() const;
signals:
void loaded(QEditor *e, const QString &s);
void needLoading();
void saved(QEditor *e, const QString &s);
void contentModified(bool y);
void titleChanged(const QString &title);
void textEdited(QKeyEvent *e);
void cursorPositionChanged();
void copyAvailable(bool y);
void undoAvailable(bool y);
void redoAvailable(bool y);
void markChanged(const QString &f, QDocumentLineHandle *l, int mark,
bool on);
void zoomed();
void inputTimeOuted();
public slots:
void reconnectWatcher();
void fileChanged(const QString &f);
void setContentClean(bool y);
void emitCursorPositionChanged();
virtual void setContentModified(bool y);
protected:
virtual bool event(QEvent *e);
virtual void paintEvent(QPaintEvent *e);
virtual void timerEvent(QTimerEvent *e);
virtual void keyPressEvent(QKeyEvent *e);
virtual void inputMethodEvent(QInputMethodEvent *e);
virtual void mouseMoveEvent(QMouseEvent *e);
virtual void mousePressEvent(QMouseEvent *e);
virtual void mouseReleaseEvent(QMouseEvent *e);
virtual void mouseDoubleClickEvent(QMouseEvent *e);
virtual void dragEnterEvent(QDragEnterEvent *e);
virtual void dragLeaveEvent(QDragLeaveEvent *e);
virtual void dragMoveEvent(QDragMoveEvent *e);
virtual void dropEvent(QDropEvent *e);
virtual void changeEvent(QEvent *e);
virtual void showEvent(QShowEvent *);
virtual void wheelEvent(QWheelEvent *e);
virtual void resizeEvent(QResizeEvent *e);
virtual void focusInEvent(QFocusEvent *e);
virtual void focusOutEvent(QFocusEvent *e);
virtual void contextMenuEvent(QContextMenuEvent *e);
virtual bool focusNextPrevChild(bool next);
virtual bool moveKeyEvent(QDocumentCursor &c, QKeyEvent *e, bool *leave);
virtual bool isProcessingKeyEvent(QKeyEvent *e, int *offset = 0);
virtual bool processCursor(QDocumentCursor &c, QKeyEvent *e, bool &b);
virtual void startDrag();
virtual QMimeData *createMimeDataFromSelection() const;
virtual void insertFromMimeData(const QMimeData *d);
virtual void scrollContentsBy(int dx, int dy);
// got to make it public for bindings
public:
void setFlag(EditFlag f, bool b);
void pageUp(QDocumentCursor::MoveMode moveMode);
void pageDown(QDocumentCursor::MoveMode moveMode);
void repaintCursor();
void ensureCursorVisible();
void ensureVisible(int line);
void ensureVisible(const QRect &rect);
void preInsert(QDocumentCursor &c, const QString &text);
void insertText(QDocumentCursor &c, const QString &text,
const QString &sfmtID = {});
QDocumentLine lineAtPosition(const QPoint &p) const;
QDocumentCursor cursorForPosition(const QPoint &p) const;
void setClipboardSelection();
void setCursorPosition(const QPoint &p);
void setCursorPosition(int line, int index);
void getCursorPosition(int &line, int &index);
void clearCursorMirrors();
void addCursorMirror(const QDocumentCursor &c);
bool undoRedoEnabled() const;
bool cursorMirrorEnabled() const;
private:
bool unindent(const QDocumentCursor &cur);
bool isAutoCloseChar(const QString &ch);
bool isPairedCloseChar(const QString &ch);
QString getPairedBeginChar(const QString &ch);
QString getPairedCloseChar(const QString &ch);
protected slots:
void documentWidthChanged(int newWidth);
void documentHeightChanged(int newWidth);
void repaintContent(int i, int n);
void updateContent(int i, int n);
void emitMarkChanged(QDocumentLineHandle *l, int mark, bool on);
protected:
enum SaveState { Undefined, Saving, Saved, Conflict };
void init(bool actions = true);
QString m_name, m_fileName;
QMenu *pMenu;
QHash<QString, QAction *> m_actions;
char m_saveState;
quint16 m_checksum;
QDocument *m_doc;
QString m_codec;
QLanguageDefinition *m_definition;
QPointer<QCodeCompletionEngine> m_completionEngine;
QDocumentCursor m_cursor, m_doubleClick, m_dragAndDrop;
QList<QDocumentCursor> m_mirrors;
int m_curPlaceHolder, m_cphOffset;
QList<PlaceHolder> m_placeHolders;
bool m_undoRedoEnabled = true;
bool m_cursorMirrorEnabled = true;
int m_state;
bool m_selection;
QRect m_crect, m_margins;
QPoint m_clickPoint, m_dragPoint;
QBasicTimer m_blink, m_scroll, m_click, m_drag, m_inputto;
QFont _docfont;
qreal _scaleRate = 1.0;
static QReliableFileWatch *watcher();
static int m_defaultFlags;
static QString m_defaultCodecName;
static QList<QEditor *> m_editors;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QEditor::State);
#endif

View File

@ -1,482 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qeditsession.h"
/*!
\file qeditsession.cpp
\brief Implementation of the QEditSession class.
*/
#include "qdocument.h"
#include "qdocument_p.h"
#include "qdocumentcursor.h"
#include "qdocumentline.h"
#include "qeditor.h"
#include "qlinemarksinfocenter.h"
#include <QDataStream>
#include <QFile>
#include <QFileInfo>
#include <QScrollBar>
/*!
\class QEditSession
\brief A session recording class
The purpose of this class is to collect session data from several
QEditor object, to serialize it and to re-create the same session by
deserializing the stored data.
*/
/*!
\brief ctor
*/
QEditSession::QEditSession(QObject *p) : QObject(p), m_id(-1), m_delay(0) {}
/*!
\brief ctor
*/
QEditSession::QEditSession(const QString &f, QObject *p)
: QObject(p), m_id(-1), m_delay(0) {
setFileName(f);
}
/*!
\brief dtor
*/
QEditSession::~QEditSession() {}
/*!
\return The update interval, in milliseconds
A value of zero means the data is NOT automatically updated.
\see updateData()
*/
int QEditSession::autoUpdateInterval() const { return m_delay; }
/*!
\brief Set the update interval
If \a ms is strictly positive then the data will be
updated every \a ms milliseconds
If the session has been given a valid filename, the updated
data will automatically be saved to that file.
*/
void QEditSession::setAutoUpdateInterval(int ms) {
if (m_delay) {
killTimer(m_id);
m_id = -1;
}
m_delay = ms;
if (m_delay) {
m_id = startTimer(m_delay);
}
}
/*!
\return The file name used as storage
If it is empty then no auto-save is performed.
*/
QString QEditSession::fileName() const { return m_fileName; }
/*!
\brief Set the storage destination
Every time the data is updated, either when the autoupdate timer
ticks or when updateData() is called programmatically, it will be
written to that file, provided the filename is valid and points
to a writeable location.
\see updateData()
\see autoUpdateInterval()
*/
void QEditSession::setFileName(const QString &filename, bool r) {
m_fileName = filename;
if (r)
restore();
}
/*!
\brief Add an editor to the session
*/
void QEditSession::addEditor(QEditor *e) {
if (m_editors.contains(e))
return;
// qDebug("+ 0x%x", e);
Document *d = new Document;
m_editors << e;
m_sessionData << d;
connect(e, SIGNAL(destroyed(QObject *)), this, SLOT(destroyed(QObject *)));
connect(e, SIGNAL(saved(QEditor *, QString)), this,
SLOT(saved(QEditor *, QString)));
connect(e, SIGNAL(loaded(QEditor *, QString)), this,
SLOT(loaded(QEditor *, QString)));
update(e, d);
}
/*!
\brief Remove an editor from the session
*/
void QEditSession::removeEditor(QEditor *e) {
int idx = m_editors.indexOf(e);
if (idx == -1)
return;
// qDebug("- 0x%x", e);
disconnect(e, SIGNAL(destroyed(QObject *)), this,
SLOT(destroyed(QObject *)));
disconnect(e, SIGNAL(saved(QEditor *, QString)), this,
SLOT(saved(QEditor *, QString)));
disconnect(e, SIGNAL(loaded(QEditor *, QString)), this,
SLOT(loaded(QEditor *, QString)));
m_editors.removeAt(idx);
delete m_sessionData.takeAt(idx);
}
/*!
*/
void QEditSession::clear(bool cleanup) {
if (cleanup)
qDeleteAll(m_editors);
qDeleteAll(m_sessionData);
m_editors.clear();
m_sessionData.clear();
}
/*!
\brief Serialize session data
*/
void QEditSession::save() {
QFile f(m_fileName);
if (f.open(QFile::WriteOnly)) {
QDataStream s(&f);
save(s);
}
}
/*!
\brief Serialize session data
*/
void QEditSession::restore() {
QFile f(m_fileName);
if (f.open(QFile::ReadOnly)) {
QDataStream s(&f);
restore(s);
}
}
static const char _magic[] = "QES ";
/*!
\brief Serialize session data
*/
void QEditSession::save(QDataStream &s) {
// qDebug("saving");
s << *(reinterpret_cast<const quint32 *>(_magic));
s << m_sessionData.count();
foreach (Document *d, m_sessionData) {
// qDebug("> %s", qPrintable(d->fileName));
s << d->fileName;
s << d->timeStamp;
s << d->cursors.count();
foreach (const Cursor &c, d->cursors)
s << c.beginLine << c.beginColumn << c.endLine << c.endColumn;
s << d->marks.count();
QHash<int, QList<int>>::const_iterator it = d->marks.constBegin();
const QHash<int, QList<int>>::const_iterator end = d->marks.constEnd();
while (it != end) {
s << it.key() << *it;
}
s << d->scrollX;
s << d->scrollY;
}
}
/*!
\brief Deserialize session data
*/
void QEditSession::restore(QDataStream &s) {
// qDebug("restoring");
quint32 magic;
s >> magic;
if (magic != *(reinterpret_cast<const quint32 *>(_magic))) {
qDebug("header mismatch : %i, %i", magic, s.status());
return;
}
int documentCount = 0;
s >> documentCount;
for (int i = 0; i < documentCount; ++i) {
Document *d = new Document;
s >> d->fileName;
s >> d->timeStamp;
// qDebug("> %s", qPrintable(d->fileName));
int cursorCount = 0;
s >> cursorCount;
bool exist = QFile::exists(d->fileName);
QEditor *e = exist ? createEditor() : 0;
if (e)
e->load(d->fileName);
for (int j = 0; j < cursorCount; ++j) {
Cursor c;
s >> c.beginLine;
s >> c.beginColumn;
s >> c.endLine;
s >> c.endColumn;
d->cursors << c;
}
int markCount = 0;
s >> markCount;
for (int j = 0; j < markCount; ++j) {
int line = 0;
QList<int> marks;
s >> line;
s >> marks;
d->marks[line] = marks;
foreach (int mark, marks)
e->document()->line(line).addMark(mark);
}
s >> d->scrollX;
s >> d->scrollY;
if (e && cursorCount) {
QDocumentCursor c =
d->cursors.first().toDocumentCursor(e->document());
e->setCursor(c);
for (int j = 1; j < cursorCount; ++j) {
e->addCursorMirror(
d->cursors.at(j).toDocumentCursor(e->document()));
}
}
// TODO : defer. it does not seem to work properly that way
// TODO : view size independency (store the first visible line number)
e->verticalScrollBar()->setValue(d->scrollY);
e->horizontalScrollBar()->setValue(d->scrollX);
if (e) {
connect(e, SIGNAL(destroyed(QObject *)), this,
SLOT(destroyed(QObject *)));
connect(e, SIGNAL(saved(QEditor *, QString)), this,
SLOT(saved(QEditor *, QString)));
connect(e, SIGNAL(loaded(QEditor *, QString)), this,
SLOT(loaded(QEditor *, QString)));
m_editors << e;
m_sessionData << d;
emit restored(e);
} else {
delete d;
}
}
}
/*!
\brief Updates the data
Fetches up-to-date session data from the attached editors.
If the session has been given a valid filename the data will
automatically be saved.
\note This will NOT affect the automatic updates timing
*/
void QEditSession::updateData() {
for (int i = 0; i < m_editors.count(); ++i) {
QEditor *e = m_editors.at(i);
Document *d = m_sessionData.at(i);
update(e, d);
}
save();
}
void QEditSession::destroyed(QObject *o) {
// qDebug("~ 0x%x", o);
for (int i = 0; i < m_editors.count(); ++i) {
QEditor *e = m_editors.at(i);
if (!e || ((QObject *)e == o)) {
delete m_sessionData.takeAt(i);
m_editors.removeAt(i);
break;
}
}
}
/*!
\brief Called whenever an editor is saved
This handler is responsible for updating file names and time stamps
which is needed to avoid data loss upon session restoration
*/
void QEditSession::saved(QEditor *e, const QString &fn) {
int idx = m_editors.indexOf(e);
if (idx == -1)
return;
// qDebug("saved : %s", qPrintable(fn));
Document *d = m_sessionData.at(idx);
// d->timeStamp = QDateTime::currentDateTime();
update(e, d);
}
/*!
\brief Called whenever an editor is loaded with new content
This handler is responsible for updating file names and time stamps
which is needed to avoid data loss upon session restoration
*/
void QEditSession::loaded(QEditor *e, const QString &fn) {
int idx = m_editors.indexOf(e);
if (idx == -1)
return;
// qDebug("loaded : %s", qPrintable(fn));
Document *d = m_sessionData.at(idx);
// d->timeStamp = QDateTime::currentDateTime();
update(e, d);
}
void QEditSession::update(QEditor *e, Document *d) {
if (!e || !d)
return;
// qDebug(">>%s", qPrintable(e->fileName()));
d->fileName = e->fileName();
d->timeStamp = QFileInfo(d->fileName).lastModified();
d->cursors.clear();
d->cursors << Cursor(e->cursor());
for (int i = 0; i < e->cursorMirrorCount(); ++i)
d->cursors << Cursor(e->cursorMirror(i));
QLineMarkList marks = QLineMarksInfoCenter::instance()->marks(d->fileName);
foreach (const QLineMark &mark, marks) { d->marks[mark.line] << mark.mark; }
d->scrollX = e->verticalScrollBar()->value();
d->scrollY = e->horizontalScrollBar()->value();
}
/*!
\internal
*/
void QEditSession::timerEvent(QTimerEvent *e) {
if (e->timerId() == m_id) {
updateData();
}
}
QEditor *QEditSession::createEditor() { return new QEditor; }
QEditSession::Cursor::Cursor(const QDocumentCursor &c) {
beginLine = c.lineNumber();
beginColumn = c.columnNumber();
endLine = c.hasSelection() ? c.anchorLineNumber() : -1;
endColumn = c.hasSelection() ? c.anchorColumnNumber() : -1;
// qDebug("((%i, %i), (%i, %i))", beginLine, beginColumn, endLine,
// endColumn);
}
QDocumentCursor QEditSession::Cursor::toDocumentCursor(QDocument *d) const {
// qDebug("((%i, %i), (%i, %i))", beginLine, beginColumn, endLine,
// endColumn);
QDocumentCursor beg(d, beginLine, beginColumn);
QDocumentCursor end(d, endLine, endColumn);
if (endLine != -1) {
end.setSelectionBoundary(beg);
return end;
}
return beg;
}

View File

@ -1,125 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QEDIT_SESSION_H_
#define _QEDIT_SESSION_H_
#include "qce-config.h"
/*!
\file qeditsession.h
\brief Definition of the QEditSession class.
*/
#include <QDateTime>
#include <QHash>
#include <QObject>
#include <QPointer>
#include <QStringList>
class QEditor;
class QDocument;
class QDocumentCursor;
class QDocumentCommand;
class QDataStream;
class QCE_EXPORT QEditSession : public QObject {
Q_OBJECT
public:
QEditSession(QObject *p = nullptr);
QEditSession(const QString &f, QObject *p = nullptr);
virtual ~QEditSession();
int autoUpdateInterval() const;
QString fileName() const;
public slots:
virtual void addEditor(QEditor *e);
virtual void removeEditor(QEditor *e);
virtual void updateData();
virtual void setAutoUpdateInterval(int ms);
virtual void setFileName(const QString &filename, bool restore = false);
virtual void clear(bool cleanup = false);
virtual void save();
virtual void restore();
virtual void save(QDataStream &s);
virtual void restore(QDataStream &s);
signals:
void restored(QEditor *e);
protected slots:
virtual void destroyed(QObject *o);
virtual void saved(QEditor *e, const QString &fn);
virtual void loaded(QEditor *e, const QString &fn);
protected:
virtual void timerEvent(QTimerEvent *e);
virtual QEditor *createEditor();
struct Cursor {
Cursor() : beginLine(-1), beginColumn(-1), endLine(-1), endColumn(-1) {}
Cursor(int line, int column)
: beginLine(line), beginColumn(column), endLine(-1), endColumn(-1) {
}
Cursor(const Cursor &c)
: beginLine(c.beginLine), beginColumn(c.beginColumn),
endLine(c.endLine), endColumn(c.endColumn) {}
Cursor(const QDocumentCursor &c);
QDocumentCursor toDocumentCursor(QDocument *d) const;
int beginLine;
int beginColumn;
int endLine;
int endColumn;
};
struct Document {
QString fileName;
QDateTime timeStamp;
int scrollX, scrollY;
QList<Cursor> cursors;
QHash<int, QList<int>> marks;
};
virtual void update(QEditor *e, Document *d);
int m_id;
int m_delay;
QString m_fileName;
QList<QEditor *> m_editors;
QList<Document *> m_sessionData;
};
#endif // ! _QEDIT_SESSION_H_

View File

@ -1,148 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QFORMAT_H_
#define _QFORMAT_H_
/*!
\file qformat.h
\brief Definition of the QFormat class
*/
#include <QColor>
#include <QFont>
#include <QTextCharFormat>
#include <QVector>
struct QFormat {
typedef decltype(QFont().weight()) Weight;
inline QFormat()
: weight(QFont::Normal), italic(false), overline(false),
underline(false), strikeout(false), waveUnderline(false) {}
inline QFormat(const QColor &c)
: weight(QFont::Normal), italic(false), overline(false),
underline(false), strikeout(false), waveUnderline(false),
foreground(c) {}
inline QFormat(Weight w, const QColor &c)
: weight(w), italic(false), overline(false), underline(false),
strikeout(false), waveUnderline(false), foreground(c) {}
inline QFormat(Weight w, bool i, bool u, bool s, const QColor &c)
: weight(w), italic(i), overline(false), underline(u), strikeout(s),
waveUnderline(false), foreground(c) {}
inline QFormat(Weight w, bool i, bool o, bool u, bool s, bool wu,
const QColor &c)
: weight(w), italic(i), overline(o), underline(u), strikeout(s),
waveUnderline(wu), foreground(c) {}
inline QFormat(const QFormat &f)
: weight(f.weight), italic(f.italic), overline(f.overline),
underline(f.underline), strikeout(f.strikeout),
waveUnderline(f.waveUnderline), foreground(f.foreground),
background(f.background), linescolor(f.linescolor) {}
inline QFormat &operator=(const QFormat &f) {
weight = f.weight;
italic = f.italic;
overline = f.overline;
underline = f.underline;
strikeout = f.strikeout;
foreground = f.foreground;
background = f.background;
linescolor = f.linescolor;
waveUnderline = f.waveUnderline;
return *this;
}
inline bool operator==(const QFormat &f) const {
return (weight == f.weight) && (italic == f.italic) &&
(overline == f.overline) && (underline == f.underline) &&
(strikeout == f.strikeout) && (foreground == f.foreground) &&
(background == f.background) && (linescolor == f.linescolor) &&
(waveUnderline == f.waveUnderline);
}
inline bool operator!=(const QFormat &f) const {
return (weight != f.weight) || (italic != f.italic) ||
(overline != f.overline) || (underline != f.underline) ||
(strikeout != f.strikeout) || (foreground != f.foreground) ||
(background != f.background) || (linescolor != f.linescolor) ||
(waveUnderline != f.waveUnderline);
}
QTextCharFormat toTextCharFormat() const {
QTextCharFormat f;
f.setFontWeight(weight);
f.setFontItalic(italic);
f.setFontOverline(overline);
f.setFontUnderline(underline);
f.setFontStrikeOut(strikeout);
f.setUnderlineColor(linescolor);
if (waveUnderline) {
f.setUnderlineStyle(QTextCharFormat::WaveUnderline);
}
if (foreground.isValid())
f.setForeground(foreground);
if (background.isValid())
f.setBackground(background);
return f;
}
Weight weight;
bool italic;
bool overline;
bool underline;
bool strikeout;
bool waveUnderline;
QColor foreground;
QColor background;
QColor linescolor;
};
Q_DECLARE_TYPEINFO(QFormat, Q_MOVABLE_TYPE);
struct QFormatRange {
inline QFormatRange() : offset(0), length(0), format(0) {}
inline QFormatRange(int o, int l, int f)
: offset(o), length(l), format(f) {}
inline bool operator==(const QFormatRange &o) const {
return (offset == o.offset) && (length == o.length) &&
(format == o.format);
}
inline bool operator!=(const QFormatRange &o) const {
return (offset != o.offset) || (length != o.length) ||
(format != o.format);
}
int offset;
int length;
int format;
};
Q_DECLARE_TYPEINFO(QFormatRange, Q_PRIMITIVE_TYPE);
#endif

View File

@ -1,16 +0,0 @@
/*
Transition header file.
*/
#ifndef _QFORMAT_FACTORY_H_
#include "qformatscheme.h"
class QFormatFactory : public QFormatScheme {
public:
inline QFormatFactory(QObject *p = nullptr) : QFormatScheme(p) {}
inline QFormatFactory(const QString &f, QObject *p = nullptr)
: QFormatScheme(f, p) {}
};
#endif

View File

@ -1,444 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qformatscheme.h"
/*!
\file qformatscheme.cpp
\brief Implementation of QFormatScheme
\see QFormatScheme
*/
/*!
\ingroup language
@{
\class QFormatScheme
\brief A storage/configuration class for shared highlighting formats
It stores text formats used by highlighters interfaces and provides
a default serializing format in QXF format (XML-based).
\see QLanguageFactory
\see QHighlighter
*/
#include "qformat.h"
#include <QDomDocument>
#include <QDomElement>
#include <QDomText>
#include <QFile>
#include <QSettings>
#include <QStringList>
#define QFORMAT_VERSION "1.0"
static bool bool_cast(const QString &s) {
return !QString::compare(s, QLatin1String("true")) || s.toUInt() == 1;
}
/*!
\brief Constructor
*/
QFormatScheme::QFormatScheme(QObject *p) : QObject(p) {
QFormatScheme::setFormat("normal", QFormat());
}
/*!
\brief Constructor
\param f Filename of a format settings file to load
*/
QFormatScheme::QFormatScheme(const QString &f, QObject *p) : QObject(p) {
QFormatScheme::load(f);
}
/*!
\brief Destructor
*/
QFormatScheme::~QFormatScheme() {}
/*!
\brief Re-initialize the format scheme
Calling this method leaves the format scheme with only one
format : the "normal" one, set to a default-constructed QFormat
*/
void QFormatScheme::clear() {
m_formatKeys.clear();
m_formatValues.clear();
QFormatScheme::setFormat("normal", QFormat());
}
/*!
\brief Load format settings from a file
\param f file to load data from
The default implementation loads data in QXF format (XML-based)
\note Previous content is discarded
*/
void QFormatScheme::load(const QString &f) {
clear();
m_settings = f;
QFile settings(f);
if (settings.open(QFile::ReadOnly | QFile::Text)) {
QDomDocument doc;
doc.setContent(&settings);
QFormatScheme::load(doc.documentElement());
}
}
/*!
\brief Save the format settings to a file
\param f target file (if none specified, last value passed to load is
used)
The default implementation saves data in QXF format (XML-based)
*/
void QFormatScheme::save(const QString &f) const {
QFile settings(f.length() ? f : m_settings);
if (settings.open(QFile::WriteOnly | QFile::Text)) {
QDomDocument doc("QXF");
QDomElement root = doc.createElement("QXF");
save(root);
doc.appendChild(root);
settings.write(doc.toByteArray(4));
}
}
/*!
\overload
\param elem Source element to scan
\param ignoreNewIds whether unknown format identifiers should be ignored
The given dom element must contain a proper version attribute and format
data as child elements (&lt;format&gt; tags)
\note Previous content is not discarded
*/
void QFormatScheme::load(const QDomElement &elem, bool ignoreNewIds) {
if (elem.attribute("version") < QFORMAT_VERSION) {
qWarning("Format encoding version mismatch : [found]%s != [expected]%s",
qPrintable(elem.attribute("version")), QFORMAT_VERSION);
return;
}
QDomElement e, c;
QDomNodeList l, f = elem.elementsByTagName("format");
for (int i = 0; i < f.count(); i++) {
e = f.at(i).toElement();
if (ignoreNewIds && !m_formatKeys.contains(e.attribute("id")))
continue;
l = e.childNodes();
QFormat fmt;
for (int i = 0; i < l.count(); i++) {
c = l.at(i).toElement();
if (c.isNull())
continue;
QString field = c.tagName(), value = c.firstChild().toText().data();
if (field == "bold")
fmt.weight = bool_cast(value) ? QFont::Bold : QFont::Normal;
else if (field == "italic")
fmt.italic = bool_cast(value);
else if (field == "overline")
fmt.overline = bool_cast(value);
else if (field == "underline")
fmt.underline = bool_cast(value);
else if (field == "strikeout")
fmt.strikeout = bool_cast(value);
else if (field == "waveUnderline")
fmt.waveUnderline = bool_cast(value);
else if (field == "color" || field == "foreground")
fmt.foreground = QColor(value);
else if (field == "background")
fmt.background = QColor(value);
else if (field == "linescolor")
fmt.linescolor = QColor(value);
}
QFormatScheme::setFormat(e.attribute("id"), fmt);
}
}
/*!
\overload
*/
void QFormatScheme::save(QDomElement &elem) const {
QDomDocument doc = elem.ownerDocument();
elem.setAttribute("version", QFORMAT_VERSION);
for (int i = 0; i < m_formatKeys.count(); ++i) {
QDomText t;
QDomElement f, c = doc.createElement("format");
c.setAttribute("id", m_formatKeys.at(i));
const QFormat &fmt = m_formatValues.at(i);
f = doc.createElement("bold");
t = doc.createTextNode((fmt.weight == QFont::Bold) ? "true" : "false");
f.appendChild(t);
c.appendChild(f);
f = doc.createElement("italic");
t = doc.createTextNode(fmt.italic ? "true" : "false");
f.appendChild(t);
c.appendChild(f);
f = doc.createElement("overline");
t = doc.createTextNode(fmt.overline ? "true" : "false");
f.appendChild(t);
c.appendChild(f);
f = doc.createElement("underline");
t = doc.createTextNode(fmt.underline ? "true" : "false");
f.appendChild(t);
c.appendChild(f);
f = doc.createElement("strikeout");
t = doc.createTextNode(fmt.strikeout ? "true" : "false");
f.appendChild(t);
c.appendChild(f);
f = doc.createElement("waveUnderline");
t = doc.createTextNode(fmt.waveUnderline ? "true" : "false");
f.appendChild(t);
c.appendChild(f);
if (fmt.foreground.isValid()) {
f = doc.createElement("foreground");
t = doc.createTextNode(fmt.foreground.name());
f.appendChild(t);
c.appendChild(f);
}
if (fmt.background.isValid()) {
f = doc.createElement("background");
t = doc.createTextNode(fmt.background.name());
f.appendChild(t);
c.appendChild(f);
}
if (fmt.linescolor.isValid()) {
f = doc.createElement("linescolor");
t = doc.createTextNode(fmt.linescolor.name());
f.appendChild(t);
c.appendChild(f);
}
elem.appendChild(c);
}
}
/*!
\overload
\brief Load format data from a QSettings object
\param s QSettings object from which data will be fetched
\param ignoreNewIds whether unknown format identifiers should be ignored
The QSettings object is assumed to be initialized properly and to
point to a correct location.
\note Previous content is not discarded
*/
void QFormatScheme::load(QSettings &s, bool ignoreNewIds) {
QString version = s.value("version").toString();
if (version < QFORMAT_VERSION) {
qWarning("Format encoding version mismatch : [found]%s != [expected]%s",
qPrintable(version), QFORMAT_VERSION);
return;
}
s.beginGroup("data");
QStringList l = s.childGroups();
for (auto &id : l) {
if (ignoreNewIds && !m_formatKeys.contains(id))
continue;
s.beginGroup(id);
QFormat fmt;
QStringList fields = s.childKeys();
foreach (QString field, fields) {
QString value = s.value(field).toString();
if (field == "bold")
fmt.weight = bool_cast(value) ? QFont::Bold : QFont::Normal;
else if (field == "italic")
fmt.italic = bool_cast(value);
else if (field == "overline")
fmt.overline = bool_cast(value);
else if (field == "underline")
fmt.underline = bool_cast(value);
else if (field == "strikeout")
fmt.strikeout = bool_cast(value);
else if (field == "waveUnderline")
fmt.waveUnderline = bool_cast(value);
else if (field == "color" || field == "foreground")
fmt.foreground = QColor(value);
else if (field == "background")
fmt.background = QColor(value);
else if (field == "linescolor")
fmt.linescolor = QColor(value);
}
setFormat(id, fmt);
s.endGroup();
}
s.endGroup();
}
/*!
\overload
*/
void QFormatScheme::save(QSettings &s) const {
s.setValue("version", QFORMAT_VERSION);
s.beginGroup("data");
for (int i = 0; i < m_formatKeys.count(); ++i) {
s.beginGroup(m_formatKeys.at(i));
const QFormat &fmt = m_formatValues.at(i);
s.setValue("bold", (fmt.weight == QFont::Bold) ? "true" : "false");
s.setValue("italic", fmt.italic ? "true" : "false");
s.setValue("overline", fmt.overline ? "true" : "false");
s.setValue("underline", fmt.underline ? "true" : "false");
s.setValue("strikeout", fmt.strikeout ? "true" : "false");
s.setValue("waveUnderline", fmt.waveUnderline ? "true" : "false");
if (fmt.foreground.isValid()) {
s.setValue("foreground", fmt.foreground.name());
}
if (fmt.background.isValid()) {
s.setValue("background", fmt.background.name());
}
if (fmt.linescolor.isValid()) {
s.setValue("linescolor", fmt.linescolor.name());
}
s.endGroup();
}
s.endGroup();
}
/*!
\return The number of available formats
*/
int QFormatScheme::formatCount() const { return m_formatValues.count(); }
/*!
\return A list of available format keys
*/
QStringList QFormatScheme::formats() const { return m_formatKeys.toList(); }
/*!
\return The format key associated to integer format id \a ifid
*/
QString QFormatScheme::id(int ifid) const { return m_formatKeys.at(ifid); }
/*!
\return The integer format id associated to format key \a fid
*/
int QFormatScheme::id(const QString &sfid) const {
int idx = m_formatKeys.indexOf(sfid);
return (idx == -1) ? 0 : idx;
}
/*!
\return The text format associated with format key \a fid
\warning Use at your own risks : if there are no format associated
with the requested id this function will crash
*/
QFormat &QFormatScheme::formatRef(int ifid) { return m_formatValues[ifid]; }
/*!
\return The a reference to the text format associated with format key \a
fid
\warning Use at your own risks : if there are no format associated
with the requested id this function will crash.
*/
QFormat &QFormatScheme::formatRef(const QString &sfid) {
return m_formatValues[id(sfid)];
}
/*!
\return The text format associated with format key \a fid
*/
QFormat QFormatScheme::format(int ifid) const {
// qDebug("Querying format id %i within ]-1, %i[", ifid,
// m_formatValues.count());
return (ifid < m_formatValues.count()) ? m_formatValues.at(ifid)
: QFormat();
}
/*!
\return The text format associated with format key \a fid
*/
QFormat QFormatScheme::format(const QString &sfid) const {
return format(id(sfid));
}
/*!
\brief Set text format for key
\param fid Format key
\param fmt Format value
*/
void QFormatScheme::setFormat(const QString &fid, const QFormat &fmt) {
const int idx = m_formatKeys.indexOf(fid);
if (idx != -1) {
m_formatValues[idx] = fmt;
} else {
// qDebug("adding format %s [%i]", qPrintable(fid),
// m_formatKeys.count());
m_formatKeys << fid;
m_formatValues << fmt;
}
}
/*! @} */

View File

@ -1,82 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QFORMAT_SCHEME_H_
#define _QFORMAT_SCHEME_H_
/*!
\file qformatscheme.h
\brief Definition of the QFormatScheme class.
\see QFormatScheme
*/
/*!
\defgroup language Language framework
*/
#include "qce-config.h"
#include <QObject>
#include <QStringList>
#include <QVector>
struct QFormat;
class QString;
class QSettings;
class QDomElement;
class QCE_EXPORT QFormatScheme : public QObject {
Q_OBJECT
public:
QFormatScheme(QObject *p = nullptr);
QFormatScheme(const QString &f, QObject *p = nullptr);
virtual ~QFormatScheme();
void clear();
virtual void load(const QString &filename);
virtual void save(const QString &filename = QString()) const;
virtual void load(const QDomElement &doc, bool ignoreNewIds = false);
virtual void save(QDomElement &elem) const;
virtual void load(QSettings &s, bool ignoreNewIds = false);
virtual void save(QSettings &s) const;
int formatCount() const;
QStringList formats() const;
virtual QString id(int ifid) const;
virtual int id(const QString &sfid) const;
virtual QFormat &formatRef(int ifid);
virtual QFormat &formatRef(const QString &sfid);
virtual QFormat format(int ifid) const;
virtual QFormat format(const QString &sfid) const;
public slots:
virtual void setFormat(const QString &fid, const QFormat &fmt);
protected:
QString m_settings;
QVector<QString> m_formatKeys;
QVector<QFormat> m_formatValues;
};
#endif // !_QFORMAT_SCHEME_H_

View File

@ -1,156 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qlanguagedefinition.h"
/*!
\file qlanguagedefinition.cpp
\brief Implementation of QLanguageDefinition
\see QLanguageDefinition
*/
/*!
\ingroup language
@{
\class QLanguageDefinition
\brief Interface for language definition.
This class is meant to be subclassed, see \see QGenericDefinition for
more informations, and added to a QLanguageFactory.
A language definition is a wrapper that creates interfaces for a given
file extension from internally handled data (XML files in the case of
QGenericDefinition)
\see QLanguageFactory
*/
#include "qdocument.h"
#include "qdocumentcursor.h"
#include "qdocumentline.h"
#include "qlanguagefactory.h"
#include <QKeyEvent>
/*!
\brief Empty constructor
*/
QLanguageDefinition::QLanguageDefinition() {}
/*!
\brief Empty destructor
*/
QLanguageDefinition::~QLanguageDefinition() {}
/*!
\fn QLanguageDefinition::language()
\return The language supported by this definition
*/
/*!
\fn QLanguageDefinition::extensions()
\return the file extensions corrseponding to the supported language
\see language()
\see QFileInfo::completeSuffix()
*/
/*!
\brief Entry point for syntax highlighting
*/
int QLanguageDefinition::tokenize(QDocument *d, int line, int count) {
Q_UNUSED(d)
Q_UNUSED(line)
return count;
}
/*!
\brief Return the string starting a single line comment, if any offered
by the language
*/
QString QLanguageDefinition::singleLineComment() const { return QString(); }
/*!
\brief Let language specify which line mark should be toggled by left
clicking a line mark panel
*/
QString QLanguageDefinition::defaultLineMark() const { return QString(); }
/*!
\brief Brace matching entry point
*/
void QLanguageDefinition::clearMatches(QDocument *d) { Q_UNUSED(d) }
/*!
\brief Brace matching entry point
*/
void QLanguageDefinition::match(QDocumentCursor &c) { Q_UNUSED(c) }
/*!
\brief Return the indent to use when inserting a line at a given cursor
position
*/
QString QLanguageDefinition::indent(const QDocumentCursor &c) {
Q_UNUSED(c)
return QString();
}
/*!
\brief Determines whether the given key event at the given position
should cause unindent to happen
*/
bool QLanguageDefinition::unindent(const QDocumentCursor &c,
const QString &ktxt) {
Q_UNUSED(c)
Q_UNUSED(ktxt)
return false;
}
/*!
\brief Expand a collapsed block at a given line
*/
void QLanguageDefinition::expand(QDocument *d, int line) {
Q_UNUSED(d)
Q_UNUSED(line)
}
/*!
\brief Collapse a text block at a given line
*/
void QLanguageDefinition::collapse(QDocument *d, int line) {
Q_UNUSED(d)
Q_UNUSED(line)
}
/*!
\brief Compute the collapse state of a line
*/
int QLanguageDefinition::blockFlags(QDocument *d, int line, int depth) const {
Q_UNUSED(d)
Q_UNUSED(line)
Q_UNUSED(depth)
return 0;
}
/*! @} */

View File

@ -1,82 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QLANGUAGE_DEFINITION_H_
#define _QLANGUAGE_DEFINITION_H_
#include "qce-config.h"
/*!
\file qlanguagedefinition.h
\brief Definition of the QLanguageDefinition class.
\see QLanguageDefinition
*/
#include <QStringList>
class QKeyEvent;
class QDocument;
class QDocumentCursor;
#define QCE_FOLD_FLAGS(flags, open, close) \
((flags) | (open & QLanguageDefinition::OpenMask) | \
((close << 12) & QLanguageDefinition::CloseMask))
#define QCE_FOLD_OPEN_COUNT(flags) ((flags)&QLanguageDefinition::OpenMask)
#define QCE_FOLD_CLOSE_COUNT(flags) \
(((flags)&QLanguageDefinition::CloseMask) >> 12)
class QCE_EXPORT QLanguageDefinition {
public:
/// Collapse state of a line
enum CollapseFlag {
None = 0x00000000, ///< The line cannot be collapsed nor expanded
Collapsible =
0x10000000, ///< The line is expanded and can thus be collapsed
Collapsed =
0x20000000, ///< The line is collapsed and can thus be expanded
Closure =
0x40000000, ///< The line is expanded and mark the end of a block
CloseMask = 0x00fff000, ///< Number of actual closing fold mark
OpenMask = 0x00000fff ///< Number of actual open fold mark
};
Q_DECLARE_FLAGS(CollapseState, CollapseFlag);
QLanguageDefinition();
virtual ~QLanguageDefinition();
virtual QString language() const = 0;
virtual QStringList extensions() const = 0;
virtual int tokenize(QDocument *d, int line, int count);
virtual QString singleLineComment() const;
virtual QString defaultLineMark() const;
virtual void match(QDocumentCursor &c);
virtual void clearMatches(QDocument *d);
virtual QString indent(const QDocumentCursor &c);
virtual bool unindent(const QDocumentCursor &c, const QString &ktxt);
virtual void expand(QDocument *d, int line);
virtual void collapse(QDocument *d, int line);
virtual int blockFlags(QDocument *d, int line, int depth = 0) const;
};
#endif // _QLANGUAGE_DEFINITION_H_

View File

@ -1,290 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qlanguagefactory.h"
/*!
\file qlanguagefactory.cpp
\brief Implementation of QLanguageFactory
\see QLanguageFactory
*/
/*!
\ingroup language
@{
\class QLanguageFactory
\brief A class managing language definitions.
It stores language definitions, added programmatically or found in XML
files, in specified locations and only if generic components are built-in.
From these definitions, QLanguageFactory generates matchers, indenters and
highlighters for a text editor, according to a file name.
\see QLanguageDefinition
*/
#include <QDir>
#include <QFileInfo>
#include <QStringList>
#ifdef _QCODE_EDIT_DEBUG_
#include <QtDebug>
#endif
#include "qeditor.h"
#include "qformatscheme.h"
#include "qcodecompletionengine.h"
#include "qlanguagedefinition.h"
#ifdef QNFA_BUILD
#include "qnfadefinition.h"
#endif
/*!
\brief Empty constructor
*/
QLanguageFactory::QLanguageFactory(QFormatScheme *fmt, QObject *p)
: QObject(p), m_defaultFormatScheme(fmt) {}
/*!
\brief Empty destructor
*/
QLanguageFactory::~QLanguageFactory() {
foreach (QString l, m_languages) {
const LangData &d = m_data[l];
if (d.s != m_defaultFormatScheme)
delete d.s;
delete d.d;
// delete d.e;
}
}
/*!
\return a list of languages supported by this factory
*/
QStringList QLanguageFactory::languages() const { return m_languages; }
/*!
\return a list of file filters supported by this factory
\note This list is NEVER empty and the last item is always "All files
(*)"
*/
QStringList QLanguageFactory::fileFilters() const {
QStringList l;
foreach (QString lng, m_languages)
l << tr("%1 files (*.%2)").arg(lng, m_data[lng].extensions.join(" *."));
l << tr("All files (*)");
return l;
}
/*!
\param e target editor
\param file filename displayed by the editor
The \a file parameter may actuall be either a filename, an extension or
the name of the language, checked in that order.
If it is a filename, complete extension as higher priority than simple
extension (see QFileInfo suffix() and completeSuffix()).
Matches are first done case-sensitively.
If no matching language definition is found for all three possible
interpretations of the \a file parameter, the same search is done
case-insensitively.
If no matching language is found the previous language
definition/completion engine of the editor are removed, leaving it blank, and
the format scheme of the document is set to the defaultFormatScheme()
*/
void QLanguageFactory::setLanguage(QEditor *e, const QString &file) {
QString lang;
QFileInfo inf(file);
const QString ext = inf.suffix(), cext = inf.completeSuffix();
// qDebug("suff:%s; compSuff:%s", qPrintable(ext), qPrintable(cext));
QLanguageDefinition *oldLang = e->languageDefinition();
if (file.length()) {
QList<Qt::CaseSensitivity> lcs;
lcs << Qt::CaseSensitive << Qt::CaseInsensitive;
foreach (Qt::CaseSensitivity cs, lcs) {
int n = 0, idx = -1;
QStringList ext_langs, cext_langs, fcext_langs;
foreach (QString lang, m_languages) {
const QStringList &exts = m_data[lang].extensions;
// qDebug("%s in (%s) ?", qPrintable(ext),
// qPrintable(exts.join(" ")));
foreach (QString x, exts) {
if (!x.compare(ext, cs))
ext_langs << lang;
if (!x.compare(cext, cs))
cext_langs << lang;
if (!x.compare(file, cs))
fcext_langs << lang;
}
if (!lang.compare(file, cs))
idx = n;
++n;
}
if (cext_langs.count()) {
// TODO : use MIME types to resolve ambiguity
lang = cext_langs.first();
} else if (ext_langs.count()) {
// TODO : use MIME types to resolve ambiguity
lang = ext_langs.first();
} else if (fcext_langs.count()) {
// TODO : use MIME types to resolve ambiguity
lang = fcext_langs.first();
} else if (idx != -1) {
lang = m_languages.at(idx);
}
if (lang.length())
break;
}
}
if (lang.isEmpty()) {
// qDebug("no lang match for %s", qPrintable(file));
e->setLanguageDefinition(0);
e->setCompletionEngine(0);
e->document()->setFormatScheme(m_defaultFormatScheme);
if (oldLang)
e->highlight();
} else {
// qDebug("lang match for %s : %s", qPrintable(file), qPrintable(lang));
const LangData &data = m_data[lang];
e->setLanguageDefinition(data.d);
e->setCompletionEngine(data.e ? data.e->clone() : 0);
e->document()->setFormatScheme(data.s ? data.s : m_defaultFormatScheme);
if (oldLang != data.d)
e->highlight();
}
}
/*!
\brief Adds a language to the factory
\param d language data
\note The language data will overwrite any existing one for the same
language
*/
void QLanguageFactory::addLanguage(const QLanguageFactory::LangData &d) {
m_data[d.lang] = d;
if (!d.e) {
foreach (QCodeCompletionEngine *e, m_unusedEngines) {
if (e->language() == d.lang) {
m_data[d.lang].e = e;
break;
}
}
}
if (!m_languages.contains(d.lang))
m_languages << d.lang;
}
/*!
\brief Lookup language data for a matching language
The primary purpose of this function is to make it easy to create
configuration dialogs (mainly for format schemes). Beware though : some
language may use the default format scheme. It is recommended to check for
that before modifying a format scheme or users might be surprised...
\warning This function will lead to crashes if you pass it a language
name not contained in languages().
*/
const QLanguageFactory::LangData &
QLanguageFactory::languageData(const QString &lang) {
return m_data[lang];
}
/*!
\brief Registers a new completion engine
\note This engine will NOT be used if there are no language definition
for the language it supports...
*/
void QLanguageFactory::addCompletionEngine(QCodeCompletionEngine *e) {
foreach (QString l, m_languages) {
if (l == e->language()) {
m_data[l].e = e;
return;
}
}
m_unusedEngines << e;
}
/*!
\brief Fetches syntax definitions from files in \a path
*/
void QLanguageFactory::addDefinitionPath(const QString &path) {
QDir d(path);
foreach (QString f, d.entryList(QDir::Files | QDir::Readable)) {
#ifdef QNFA_BUILD
if (f.endsWith(".qnfa")) {
// qDebug("loading file %s", qPrintable(f));
QFileInfo info(d.filePath(f));
QString specificFormatScheme =
QDir(info.path()).filePath(info.baseName() + ".qxf");
QFormatScheme *scheme = m_defaultFormatScheme;
if (QFile::exists(specificFormatScheme)) {
scheme = new QFormatScheme(specificFormatScheme);
}
LangData data;
QNFADefinition::load(d.filePath(f), &data, scheme);
// qDebug("%s : (%s | %s)", qPrintable(data.lang),
// qPrintable(data.mime), qPrintable(data.extensions.join(", ")));
addLanguage(data);
// addLanguageDefinition(new QNFADefinition(d.filePath(f), this));
}
#endif
}
}
/*! @} */

View File

@ -1,83 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QLANGUAGE_FACTORY_H_
#define _QLANGUAGE_FACTORY_H_
/*!
\file qlanguagefactory.h
\brief Definition of the QLanguageFactory class.
\see QLanguageFactory
*/
/*!
\defgroup language Language framework
*/
#include "qce-config.h"
#include <QHash>
#include <QObject>
#include <QStringList>
class QEditor;
class QFormatScheme;
class QLanguageDefinition;
class QCodeCompletionEngine;
class QCE_EXPORT QLanguageFactory : public QObject {
Q_OBJECT
public:
struct LangData {
QString lang, mime;
QStringList extensions;
QFormatScheme *s;
QLanguageDefinition *d;
QCodeCompletionEngine *e;
};
QLanguageFactory(QFormatScheme *fmt, QObject *p = nullptr);
virtual ~QLanguageFactory();
QStringList languages() const;
QStringList fileFilters() const;
const LangData &languageData(const QString &lang);
void addDefinitionPath(const QString &path);
inline QFormatScheme *defaultFormatScheme() const {
return m_defaultFormatScheme;
}
public slots:
void addLanguage(const LangData &d);
void addCompletionEngine(QCodeCompletionEngine *e);
virtual void setLanguage(QEditor *e, const QString &f);
private:
QStringList m_languages;
QHash<QString, LangData> m_data;
QList<QCodeCompletionEngine *> m_unusedEngines;
QFormatScheme *m_defaultFormatScheme;
};
#endif // _QLANGUAGE_FACTORY_H_

View File

@ -1,566 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qlinemarksinfocenter.h"
/*!
\file qlinemarksinfocenter.cpp
\brief Implementation of QLineMarksInfoCenter
\see QLineMarksInfoCenter
*/
/*!
\ingroup language
@{
\class QLineMarksInfoCenter
\brief A class managing line marks accross all managed editors
QLineMarksInfoCenter provides mean to read/write line marks on managed
editors but also to serialize and deserialize that data.
*/
#include "qcodeedit.h"
#include "qeditor.h"
#include "qdocument.h"
#include "qdocument_p.h"
#include "qdocumentline.h"
#include <QDataStream>
#include <QDomDocument>
#include <QFile>
#define QLINE_MARKS_DUMP_VERSION 1
#define QLINE_MARKS_DUMP_VERSION_MIN 1
QLineMarksInfoCenter *QLineMarksInfoCenter::m_instance = 0;
QLineMarksInfoCenter *QLineMarksInfoCenter::instance() {
if (!m_instance)
m_instance = new QLineMarksInfoCenter;
return m_instance;
}
void QLineMarksInfoCenter::destroy() {
if (m_instance)
delete m_instance;
m_instance = 0;
}
QLineMarksInfoCenter::QLineMarksInfoCenter() : QObject() {
qRegisterMetaType<QLineMark>("QLineMark");
}
QLineMarksInfoCenter::~QLineMarksInfoCenter() {}
/*!
\return the list of line marks set on a given file
*/
QLineMarkList QLineMarksInfoCenter::marks(const QString &file, int filterID) {
QLineMarkList l;
bool check = !file.isEmpty();
for (auto &m : m_lineMarks) {
if (!check || (m.file == file)) {
if (filterID < 0 || (filterID >= 0 && m.mark == filterID)) {
l << QLineMark(file, m.line->line() + 1, m.mark);
}
}
}
return l;
}
/*!
\brief Remove all line marks on all files
*/
void QLineMarksInfoCenter::clear() {
for (auto &m : m_lineMarks) {
removeLineMark(m);
}
}
/*!
\brief Remove all line marks on a given file
*/
void QLineMarksInfoCenter::removeMarks(const QString &file) {
for (auto &m : m_lineMarks)
if (m.file == file)
removeLineMark(m);
}
/*!
\brief Add a line mark
If the target file is not found the toggling will be delayed.
*/
void QLineMarksInfoCenter::addLineMark(const QLineMark &mark) {
QEditor *e = QCodeEdit::managed(mark.file);
if (!e) {
m_delayed << mark;
return;
}
QDocumentLine l = e->document()->line(mark.line - 1);
if (!l.isValid())
return;
e->setCursor(QDocumentCursor(e->document(), mark.line - 1));
l.addMark(mark.mark);
}
/*!
\brief Remove a line mark
If the target file is not found the addition will be delayed.
*/
void QLineMarksInfoCenter::toggleLineMark(const QLineMark &mark) {
QEditor *e = QCodeEdit::managed(mark.file);
if (!e) {
m_delayed << mark;
return;
}
QDocumentLine l = e->document()->line(mark.line - 1);
if (!l.isValid())
return;
// e->setCursor(QDocumentCursor(e->document(), mark.line - 1));
l.toggleMark(mark.mark);
}
/*!
\brief Toggle a line mark
If the target file is not found the removal will be delayed.
*/
void QLineMarksInfoCenter::removeLineMark(const QLineMark &mark) {
QEditor *e = QCodeEdit::managed(mark.file);
if (!e)
return;
QDocumentLine l = e->document()->line(mark.line - 1);
if (!l.isValid())
return;
l.removeMark(mark.mark);
// e->setCursor(QDocumentCursor(l));
}
/*!
\brief Add a line mark
*/
void QLineMarksInfoCenter::addLineMark(const QLineMarkHandle &mark) {
QDocumentLine l(mark.line);
if (l.isValid())
l.addMark(mark.mark);
}
/*!
\brief Toggle a line mark
*/
void QLineMarksInfoCenter::toggleLineMark(const QLineMarkHandle &mark) {
QDocumentLine l(mark.line);
if (l.isValid())
l.toggleMark(mark.mark);
}
/*!
\brief Remove a line mark
*/
void QLineMarksInfoCenter::removeLineMark(const QLineMarkHandle &mark) {
QDocumentLine l(mark.line);
if (l.isValid())
l.removeMark(mark.mark);
}
/*!
\brief Flush all delayed line marks addition/removal/toggling for a
given file
*/
void QLineMarksInfoCenter::flush(const QString &file) {
QLineMarkList::iterator i = m_delayed.begin();
while (i != m_delayed.end()) {
if (i->file == file) {
addLineMark(*i);
i = m_delayed.erase(i);
} else {
++i;
}
}
}
/*!
\brief Load serialized line marks data from a file
*/
void QLineMarksInfoCenter::loadMarks(const QString &f) {
QFile file(f);
if (!file.open(QFile::ReadOnly))
return;
QDataStream stream(&file);
int version;
stream >> version;
if (version < QLINE_MARKS_DUMP_VERSION_MIN) {
qWarning("QLineMarksInfoCenter : dump file version mismatch");
return;
} else if (version > QLINE_MARKS_DUMP_VERSION) {
qWarning("QLineMarksInfoCenter : dump file version mismatch");
return;
}
QLineMark mark;
while (!stream.atEnd()) {
stream >> mark;
addLineMark(mark);
}
}
/*!
\brief Write serialized line marks data to a file
*/
void QLineMarksInfoCenter::saveMarks(const QString &f) {
QFile file(f);
if (!file.open(QFile::WriteOnly))
return;
QDataStream stream(&file);
stream << QLINE_MARKS_DUMP_VERSION;
foreach (QLineMarkHandle mark, m_lineMarks) {
stream << mark.line->line() + 1;
stream << mark.file;
stream << QLineMarksInfoCenter::instance()->markTypeId(mark.mark);
// stream << mark;
}
}
QDataStream &operator>>(QDataStream &d, QLineMark &m) {
int line;
QString file, mark;
d >> line;
d >> file;
d >> mark;
m.line = line;
m.file = file;
m.mark = QLineMarksInfoCenter::instance()->markTypeId(mark);
return d;
}
QDataStream &operator<<(QDataStream &d, const QLineMark &m) {
int line = m.line;
QString file = m.file,
mark = QLineMarksInfoCenter::instance()->markTypeId(m.mark);
d << line;
d << file;
d << mark;
return d;
}
/*!
\brief Load line marks definition from a file
*/
void QLineMarksInfoCenter::loadMarkTypes(const QString &f) {
QFile file(f);
if (!file.open(QFile::ReadOnly | QFile::Text))
return;
// TODO : prefer QXmlStreamReader when building against Qt 4.3.0
QDomDocument doc;
doc.setContent(&file);
QDomNodeList l = doc.documentElement().childNodes();
for (int i = 0; i < l.count(); i++) {
QDomElement e = l.at(i).toElement();
if (e.isNull() || (e.tagName() != "mark"))
continue;
QLineMarkType t;
QDomNodeList c = e.childNodes();
// qDebug("mark {");
for (int j = 0; j < c.count(); j++) {
QDomElement attr = c.at(j).toElement();
if (attr.isNull())
continue;
const QString field = attr.tagName();
const QString value = attr.firstChild().toText().data();
// qDebug("\t%s = %s;", qPrintable(field), qPrintable(value));
const bool flag = (value == "true") || value.toUInt();
if (field == "id") {
t.id = value;
} else if (field == "user") {
t.user = flag;
} else if (field == "focus") {
t.focus = flag;
} else if (field == "icon") {
t.icon = QPixmap(value);
} else if (field == "color") {
// t.color = QColor(value);
/*
color value MUST be a valid value for
QColor::setNamedColor() with one exception though : an alpha
channel indication (unsupported by QColor::setNamedColor())
can be prepended using '@' followed by a sequence of hex
digits (preferabily two of them...)
examples :
#ff0c80
#ff0c80@80
blue
blue@10
*/
if (value.contains('@')) {
t.color = QColor(
value.section('@', 0, 0, QString::SectionSkipEmpty));
t.color.setAlpha(
value.section('@', 1, 1, QString::SectionSkipEmpty)
.toUInt(0, 16));
} else {
t.color = QColor(value);
}
} else if (field == "priority") {
t.priority = value.toUInt();
} else if (field == "persistency") {
t.persistency = value.toUInt();
} else if (field == "rule") {
t.rules << value;
}
}
m_lineMarkTypes << t;
// qDebug("};");
}
}
/*!
\brief int -> string mark type identifier conversion
*/
QString QLineMarksInfoCenter::markTypeId(int id) {
return ((id >= 0) && (id < m_lineMarkTypes.count()))
? m_lineMarkTypes.at(id).id
: QString();
}
/*!
\brief string -> int mark type identifier conversion
*/
int QLineMarksInfoCenter::markTypeId(const QString &id) {
for (int idx = 0; idx < m_lineMarkTypes.count(); ++idx)
if (m_lineMarkTypes.at(idx).id == id)
return idx;
return -1;
}
/*!
\return The mark type definition associated with a given id
*/
QLineMarkType QLineMarksInfoCenter::markType(int id) {
return ((id >= 0) && (id < m_lineMarkTypes.count()))
? m_lineMarkTypes.at(id)
: QLineMarkType();
}
/*!
\return the mark type definition associated with a given id
*/
QLineMarkType QLineMarksInfoCenter::markType(const QString &id) {
foreach (QLineMarkType t, m_lineMarkTypes)
if (t.id == id)
return t;
return QLineMarkType();
}
/*!
\return A list of available mark types
\param context context filter (no filtering is performed if empty)
*/
QStringList QLineMarksInfoCenter::availableMarkTypes(const QString &context) {
QStringList l;
foreach (QLineMarkType t, m_lineMarkTypes) {
if (context.size() &&
(!t.user ||
(t.rules.contains("#out") && !t.rules.contains(context)) ||
(t.rules.contains("#in") && t.rules.contains("!" + context)))) {
// qDebug("mark[%s] mismatched", qPrintable(t.id));
} else {
l << t.id;
}
}
return l;
}
/*!
\return the mark that has the highest priority among a list of marks
*/
int QLineMarksInfoCenter::priority(const QList<int> &marks) {
int higher = -1;
int mark = marks.isEmpty() ? -1 : marks.at(0);
for (int i = 0; i < m_lineMarkTypes.count(); ++i) {
if (marks.contains(i) && (m_lineMarkTypes.at(i).priority > higher)) {
mark = i;
higher = m_lineMarkTypes.at(i).priority;
}
}
return mark;
}
/*!
\return the mark that has the highest priority among a list of marks
*/
QString QLineMarksInfoCenter::priority(const QStringList &marks) {
QString mark;
int higher = -1;
foreach (QLineMarkType t, m_lineMarkTypes) {
if (marks.contains(t.id) && (t.priority > higher)) {
mark = t.id;
higher = t.priority;
}
}
return (mark.size() || !marks.count()) ? mark : marks.at(0);
}
/*!
\brief Useless for now
*/
QList<QStringList> QLineMarksInfoCenter::marksLayout(const QString &context) {
QList<QStringList> l;
for (auto &id : availableMarkTypes(context)) {
l << QStringList(id);
}
return l;
}
/*!
\internal
*/
void QLineMarksInfoCenter::cursorMoved(QEditor *e) {
foreach (const QLineMarkHandle &lmh, m_lineMarks) {
QLineMarkType t = markType(lmh.mark);
if ((e->fileName() != lmh.file) ||
(e->document() != lmh.line->document()) || (t.persistency == 2))
continue;
if (!t.persistency || (lmh.line != e->cursor().line().handle())) {
removeLineMark(lmh);
cursorMoved(e);
break;
}
}
}
/*!
\internal
*/
void QLineMarksInfoCenter::lineDeleted(QDocumentLineHandle *h) {
auto i = m_lineMarks.begin();
while (i != m_lineMarks.end()) {
if (i->line == h) {
QLineMark mrk(i->file, i->line->line() + 1, i->mark);
i = m_lineMarks.erase(i);
emit lineMarkRemoved(mrk);
} else {
++i;
}
}
}
/*!
\brief Entry point for changes in documents
Every document notify through this function a change in its line
marks...
*/
void QLineMarksInfoCenter::markChanged(const QString &f,
QDocumentLineHandle *line, int mark,
bool on) {
const QLineMarkHandle m(f, line, mark);
bool in = m_lineMarks.contains(m);
const QLineMark mrk(f, line->line() + 1, mark);
if (!on && in) {
m_lineMarks.removeAll(m);
emit lineMarkRemoved(mrk);
} else if (on && !in) {
m_lineMarks << m;
emit lineMarkAdded(mrk);
}
/*
foreach ( const QLineMarkHandle& h, m_lineMarks )
{
qDebug("\t%s:%i [%i]", qPrintable(h.file), h.line->line() + 1,
h.mark);
}
*/
}
/*! @} */

View File

@ -1,184 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QLINE_MARKS_INFO_CENTER_H_
#define _QLINE_MARKS_INFO_CENTER_H_
/*!
\file qlinemarksinfocenter.h
\brief Definition of the QLineMarksInfoCenter class.
\see QLineMarksInfoCenter
*/
/*!
\defgroup language Language framework
*/
#include "qce-config.h"
#include <QColor>
#include <QMetaType>
#include <QObject>
#include <QPixmap>
#include <QStringList>
class QEditor;
class QDataStream;
class QDocumentLineHandle;
struct QLineMark {
inline QLineMark() : line(-1) {}
inline QLineMark(const QString &f, int l, int m)
: mark(m), line(l), file(f) {}
inline bool operator==(const QLineMark &m) {
return (line == m.line) && (file == m.file) && (mark == m.mark);
}
inline bool operator!=(const QLineMark &m) {
return (line != m.line) || (file != m.file) || (mark != m.mark);
}
int mark;
int line;
QString file;
};
Q_DECLARE_METATYPE(QLineMark)
typedef QList<QLineMark> QLineMarkList;
Q_DECLARE_TYPEINFO(QLineMark, Q_MOVABLE_TYPE);
struct QLineMarkHandle {
inline QLineMarkHandle() : line(0) {}
inline QLineMarkHandle(QLineMarkHandle const &) = default;
inline QLineMarkHandle(const QString &f, QDocumentLineHandle *l, int m)
: mark(m), line(l), file(f) {}
inline bool operator==(const QLineMarkHandle &m) const {
return (line == m.line) && (file == m.file) && (mark == m.mark);
}
inline bool operator!=(const QLineMarkHandle &m) const {
return (line != m.line) || (file != m.file) || (mark != m.mark);
}
int mark;
QDocumentLineHandle *line;
QString file;
};
Q_DECLARE_METATYPE(QLineMarkHandle)
typedef QList<QLineMarkHandle> QLineMarkHandleList;
Q_DECLARE_TYPEINFO(QLineMarkHandle, Q_MOVABLE_TYPE);
QCE_EXPORT QDataStream &operator>>(QDataStream &d, QLineMark &m);
QCE_EXPORT QDataStream &operator<<(QDataStream &d, const QLineMark &m);
struct QLineMarkType {
inline QLineMarkType()
: user(false), focus(false), priority(-1), persistency(0) {}
bool user;
bool focus;
QString id;
QPixmap icon;
QColor color;
int priority;
int persistency;
QStringList rules;
};
Q_DECLARE_METATYPE(QLineMarkType)
typedef QList<QLineMarkType> QLineMarkTypeList;
Q_DECLARE_TYPEINFO(QLineMarkType, Q_MOVABLE_TYPE);
class QCE_EXPORT QLineMarksInfoCenter : public QObject {
friend class QEditor;
friend class QCodeEdit;
Q_OBJECT
public:
static QLineMarksInfoCenter *instance();
static void destroy();
QLineMarkList marks(const QString &file = QString(), int filterID = -1);
QString markTypeId(int id);
int markTypeId(const QString &id);
QLineMarkType markType(int id);
QLineMarkType markType(const QString &id);
int priority(const QList<int> &marks);
QString priority(const QStringList &marks);
QStringList availableMarkTypes(const QString &context = QString());
QList<QStringList> marksLayout(const QString &context = QString());
public slots:
void loadMarks(const QString &f);
void saveMarks(const QString &f);
void loadMarkTypes(const QString &f);
void clear();
void removeMarks(const QString &file);
void addLineMark(const QLineMark &mark);
void toggleLineMark(const QLineMark &mark);
void removeLineMark(const QLineMark &mark);
void addLineMark(const QLineMarkHandle &mark);
void toggleLineMark(const QLineMarkHandle &mark);
void removeLineMark(const QLineMarkHandle &mark);
void lineDeleted(QDocumentLineHandle *h);
void flush(const QString &file);
signals:
void lineMarkAdded(const QLineMark &mark);
void lineMarkRemoved(const QLineMark &mark);
protected:
QLineMarksInfoCenter();
virtual ~QLineMarksInfoCenter();
protected slots:
void cursorMoved(QEditor *e);
void markChanged(const QString &f, QDocumentLineHandle *h, int mark,
bool on);
private:
QLineMarkList m_delayed;
QLineMarkHandleList m_lineMarks;
QLineMarkTypeList m_lineMarkTypes;
static QLineMarksInfoCenter *m_instance;
};
#endif // !_QLINE_MARKS_INFO_CENTER_H_

View File

@ -1,96 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _LIGHT_VECTOR_H_
#define _LIGHT_VECTOR_H_
#include <qglobal.h>
/*!
\file light_vector.h
\brief Definition of the light_vector class
*/
template <typename T>
class light_vector {
public:
light_vector() : m_data(0), size(0) {}
~light_vector() { free(m_data); }
light_vector &operator=(const light_vector &o) {
size = o.size;
m_data = o.m_data;
return *this;
}
light_vector &operator<<(const T &v) {
append(v);
return *this;
}
inline size_t length() const { return size; }
inline size_t count() const { return size; }
inline T *data() { return m_data; }
void alloc(int pos, size_t n) {
size += n;
m_data = !m_data ? (T *)malloc(size * sizeof(T))
: (T *)realloc(m_data, size * sizeof(T));
for (auto i = size - 1; (i > pos) && (i >= n); --i)
m_data[i] = m_data[i - n];
// for ( int i = pos; (i < (pos + n)) && ((i + n) < size); ++i )
// m_data[i + n] = m_data[i];
}
inline void prepend(const T &v) { insert(0, v); }
void insert(int i, const T &v) {
i = qBound(0, i, (int)size);
alloc(i, 1);
m_data[i] = v;
}
void append(const T &v) {
++size;
m_data = !m_data ? (T *)malloc(size * sizeof(T))
: (T *)realloc(m_data, size * sizeof(T));
m_data[size - 1] = v;
}
inline const T &at(size_t i) { return *(m_data + i); }
inline T &operator[](size_t i) { return *(m_data + i); }
bool contains(const T &v) const {
for (int i = 0; i < size; i++)
if (m_data[i] == v)
return true;
return false;
}
private:
T *m_data;
size_t size;
};
#endif // _LIGHT_VECTOR_H_

View File

@ -1,941 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qnfa.h"
/*!
\file qnfa.cpp
\brief Implementation of the core QNFA syntax engine
*/
#include <QHash>
#include <QList>
quint32 QNFA::_count = 0;
static QList<QNFA *> _deleted;
QNFA::QNFA() : type(Char), assertion(0), actionid(0) {
out.next = 0;
++_count;
// qDebug("alloc(0x%x) => QNFA syntax[%i];", this, _count);
}
QNFA::~QNFA() {
--_count;
// some nfa nodes are shared... gotta make sure they are free'd once only
_deleted << this;
// qDebug("free(0x%x) => QNFA syntax[%i];", this, _count);
tree.clear();
if ((type & CxtBeg) && out.branch) {
delete out.branch;
out.branch = 0;
}
if (out.next && !_deleted.contains(out.next)) {
delete out.next;
out.next = 0;
}
}
QNFABranch::~QNFABranch() {
// qDebug("branch to %i nodes", count());
for (int i = 0; i < count(); ++i) {
if (at(i) && !_deleted.contains(at(i))) {
delete (*this)[i];
(*this)[i] = 0;
}
}
}
inline bool isWord(QChar c) {
return c.isLetterOrNumber() || (c.unicode() == '_');
}
static bool match(QChar cc, QNFA *chain) {
bool found = true;
quint16 cu = cc.unicode();
bool notEmpty = chain->c.count();
if (notEmpty && (chain->c.at(0) == '\0'))
found = false;
if (notEmpty)
if (chain->c.contains(cu))
return found;
int ass = chain->assertion;
if (ass) {
if (cc.isDigit()) {
if (ass & Digit)
return found;
} else {
if (ass & NonDigit)
return found;
if (cc.isSpace()) {
if (ass & Space)
return found;
} else {
if (ass & NonSpace)
return found;
if (cc.isLetterOrNumber() || (cu == '_')) {
if (ass & Word)
return found;
} else {
if (ass & NonWord)
return found;
}
}
}
}
return !found;
}
void match(QNFAMatchContext *lexer, const QChar *d, int length,
QNFAMatchNotifier notify) {
if (!lexer || !lexer->context) {
// qWarning("get off you scum!");
return;
}
// restore message buffering
notify.clear();
int olvls = lexer->parents.count(), nlvls = 0, lvls = olvls;
if (lvls)
notify.startBuffering();
//
quint16 c = 0;
const QChar *di = d;
QNFA *chain = 0, *start = 0;
int index = 0, lastCxt = 0, len, idx;
bool bFound, bEscape = false, bEscaped = false;
bool wPrev = false, wCur = false;
while (index < length) {
bFound = false;
bEscaped = false;
// bEscape &= !lexer->meaningless.contains(d[index].unicode());
// while ( lexer->meaningless.contains(d[index].unicode()) && ((index +
// 1) < length) )
// ++index;
if (index >= length)
break;
c = di->unicode();
wCur = isWord(*di);
int plainIndex = -1, plainMatch, plainLength;
// try fast plain matching
if (!(wPrev && wCur)) {
// qDebug("trying plain...");
// len = 0;
idx = index;
QCharTree::const_iterator it, match, end;
it = lexer->context->tree.constFind(c);
if (it != lexer->context->tree.constEnd()) {
// qDebug("plain on %c", c);
do {
++di;
++idx;
end = it->next.constEnd();
match = it->next.constFind(0);
if (idx < length) {
c = di->unicode();
it = it->next.constFind(c);
} else {
it = end;
}
if (it == end) {
if ((match != end) && !isWord(*di)) {
// word boundary found
// corresponding token end found
wPrev = isWord(*(di - 1));
bFound = true;
if (match->value.action & 0x40000000) {
// try regexps before notifying
plainIndex = index;
plainLength = idx - index;
plainMatch = match->value.action;
// qDebug("ambiguity.");
} else {
notify(index, idx - index, match->value.action);
index = idx;
}
// qDebug("next step : %c", d[index].toLatin1());
// bMonitor = true;
}
break;
}
} while (idx < length);
if (bFound) {
bEscape = false;
if (plainIndex == -1)
continue;
bFound = false;
}
di -= idx - index;
}
}
// fallback on regexp-like NFA-based matching
QNFABranch *children = lexer->context->out.branch;
if (children) {
// qDebug("trying %i sub nfas on %c", children->count(),
// d[index].toLatin1());
auto max = children->count();
for (decltype(max) i = 0; i < max; ++i) {
len = 0;
idx = index;
start = chain = children->at(i);
// qDebug("%ith attempt on %c", i, d[index + len].toLatin1());
while ((idx < length) || (chain->type & Match)) {
bEscaped = false;
if (chain->type & Match) {
if ((chain->assertion & WordEnd) && (idx < length) &&
isWord(*di) && isWord(*(di - 1))) {
// qDebug("end assertion failed...");
break;
}
// qDebug("matched to end");
if (chain->type & CxtBeg) {
// qDebug("entering context : 0x%x", chain);
++nlvls;
bool notifySub = notify.bufferLevel();
if (notifySub) {
// pop one message buffer
notify.stopBuffering();
}
// notify content of previous context until nest
notify(lastCxt, index - lastCxt,
lexer->context->actionid | 0x80000000);
if (notifySub) {
// notify sub matches so far to avoid tricky
// handling later on
notify.flush();
// notify.startBuffering();
}
// notify begin marker
notify(index, len,
start->actionid ? start->actionid
: chain->actionid);
// update context stack
lexer->parents.push(lexer->context);
lexer->context = chain;
// update nest index
lastCxt = idx;
// push a message buffer
notify.startBuffering();
} else if (chain->type & CxtEnd) {
// qDebug("leaving context :");
if (lexer->parents.isEmpty())
qFatal("context nesting problem");
if (bEscape) {
// not really end : escape found...
bEscape = false;
bEscaped = true;
} else {
if (nlvls)
--nlvls;
else
--lvls;
// pop one message buffer
notify.stopBuffering();
// notify context content from last nest
notify(lastCxt, index - lastCxt,
lexer->context->actionid | 0x80000000);
// flush sub matches
notify.flush();
// update context stack
lexer->context = lexer->parents.pop();
if (lexer->parents.count())
notify.startBuffering();
// update nest index
lastCxt = idx;
// notify end marker
notify(index, len, chain->actionid);
// qDebug("cxt notif...");
if (chain->type & Exclusive)
index = idx;
--index;
--di;
bFound = true;
break;
}
} else if (chain->type & CxtEsc) {
// qDebug("matched %s", qPrintable(QString(index,
// len)));
// notify(index, len, chain->actionid);
bEscape = !bEscape;
} else {
// qDebug("matched %s", qPrintable(QString(d +
// index, len)));
if (plainIndex != -1 && plainLength >= len) {
break;
}
notify(index, len, chain->actionid);
bEscape = false;
}
bFound = true;
index = idx;
--index;
--di;
// qDebug("next step : %c", d[index + 1].toLatin1());
// bMonitor = true;
break;
} else {
// "regular" nfa match (no match yet...)
if ((chain->assertion & WordStart) && (idx >= 1) &&
(isWord(*(di - 1)) && isWord(*di))) {
// qDebug("beg assertion failed...");
break;
}
QChar cc = *di;
bool found = match(cc, chain);
if (!(chain->assertion & ZeroOrOne) &&
!(chain->assertion & ZeroOrMore) && !found) {
// if ( cc.toLatin1() == ')' )
// qDebug("mismatch : %c != %c", cc.toLatin1(),
// chain->c.at(0));
break;
}
if (found) {
// qDebug("%c", d[index + len].toLatin1());
if ((chain->assertion & OneOrMore) ||
(chain->assertion & ZeroOrMore)) {
do {
++di;
++len;
++idx;
} while ((idx < length) && match(*di, chain));
} else {
++len;
++idx;
++di;
}
} else {
// qDebug("! %c", d[index + len].toLatin1());
}
chain = chain->out.next;
}
}
if (bFound)
break;
di -= len;
}
}
if (!bFound) {
if (plainIndex != -1) {
notify(plainIndex, plainLength, plainMatch);
index = plainIndex + plainLength;
di += plainLength;
continue;
}
bEscape = false;
//++index;
wPrev = wCur;
} else {
wPrev = isWord(*di);
}
++index;
++di;
}
// flush messages
if (!notify.bufferLevel())
return;
// qDebug("%i context nests", notify.bufferLevel());
// qDebug("[%i;+00[ : 0x%x", lastCxt, lexer->context->actionid |
// 0x80000000);
// pop down one buffer
notify.stopBuffering();
// notify overlapping context so far
notify(lastCxt, length - lastCxt, lexer->context->actionid | 0x80000000);
// notify sub matches
notify.flush();
// make sure we leave a blank notifier...
notify.clear();
// preserve escape power...
if (bEscaped)
return;
// some existing left AND new one(s)
if ((olvls == lvls) && nlvls)
++lvls;
// close stay-on-line contexts, if any
QStack<QNFA *>::iterator it = lexer->parents.begin() + lvls;
while (it != lexer->parents.end()) {
if ((*it)->type & StayOnLine) {
// qDebug("staid...");
it = lexer->parents.erase(it);
} else {
++it;
}
}
if ((lexer->context->type & StayOnLine) && nlvls && lexer->parents.count())
lexer->context = lexer->parents.pop();
}
QNFA *lexer() {
QNFA *lex = new QNFA;
lex->type = ContextBegin;
lex->out.branch = new QNFABranch;
return lex;
}
QNFA *sharedContext(const QString &start, QNFA *other, bool cs) {
QNFA *nfa, *end,
*beg = sequence(start.constData(), start.length(), &end, cs);
nfa = new QNFA;
nfa->type = ContextBegin;
nfa->out.branch = other->out.branch;
end->out.next = nfa;
return beg;
}
QNFA *context(const QString &start, const QString &stop, const QString &,
int action, QNFA **handler, bool cs) {
QNFA *nfa, *end,
*beg = sequence(start.constData(), start.length(), &end, cs);
nfa = new QNFA;
nfa->type = ContextBegin;
nfa->actionid = action;
nfa->out.branch = new QNFABranch;
if (handler)
*handler = nfa;
// else
// qDebug("no handler set [0x%x]", nfa);
end->out.next = nfa;
end = nfa;
QNFA *endmark,
*begendmark = sequence(stop.constData(), stop.length(), &endmark, cs);
nfa = new QNFA;
nfa->type = ContextEnd;
nfa->actionid = action;
endmark->out.next = nfa;
// end->out->branch->append(endmark);
addNFA(end, begendmark);
return beg;
}
void addWord(QNFA *lexer, const QString &w, int action, bool cs) {
if (!lexer || !(lexer->type & CxtBeg) || !lexer->out.branch)
return;
// try using the fastest way if possible
QString pt;
if (plain(w, &pt) && cs) {
addWord(lexer->tree, pt, action, cs);
return;
}
// fallback on (fast) regexp-like NFA-based semi-compiled parsing
QNFA *nfa, *word, *end;
word = sequence(w.constData(), w.length(), &end, cs);
word->assertion |= WordStart;
nfa = new QNFA;
nfa->type = Match;
nfa->assertion = WordEnd;
nfa->actionid = action;
end->out.next = nfa;
// lexer->out.branch->append(word);
addNFA(lexer, word);
}
void addSequence(QNFA *lexer, const QString &w, int action, bool cs) {
if (!lexer || !(lexer->type & CxtBeg) || !lexer->out.branch) {
return;
}
QNFA *seq, *end, *nfa;
seq = sequence(w.constData(), w.length(), &end, cs);
nfa = new QNFA;
nfa->type = Match;
nfa->actionid = action;
end->out.next = nfa;
// lexer->out.branch->append(seq);
addNFA(lexer, seq);
}
QNFA *sequence(const QChar *d, int length, QNFA **end, bool cs) {
QNFA *nfa, *set = 0, *prev = 0, *first = 0;
for (int i = 0; i < length; ++i) {
QChar c = d[i];
if (c == QLatin1Char('\\')) {
c = d[++i];
if (c == QLatin1Char('n')) {
c = '\n';
} else if (c == QLatin1Char('t')) {
c = '\t';
} else if (c == QLatin1Char('r')) {
c = '\r';
}
if (set) {
set->c << c.unicode();
} else {
nfa = new QNFA;
nfa->c << c.unicode();
if (prev)
prev->out.next = nfa;
prev = nfa;
}
} else if (c == QLatin1Char('$')) {
// char classes
c = d[++i];
if (set) {
if (c == QLatin1Char('s'))
set->assertion |= Space;
else if (c == QLatin1Char('S'))
set->assertion |= NonSpace;
else if (c == QLatin1Char('d'))
set->assertion |= Digit;
else if (c == QLatin1Char('D'))
set->assertion |= NonDigit;
else if (c == QLatin1Char('w'))
set->assertion |= Word;
else if (c == QLatin1Char('W'))
set->assertion |= NonWord;
else
set->c << QLatin1Char('$').unicode() << c.unicode();
} else {
nfa = new QNFA;
if (c == QLatin1Char('s'))
nfa->assertion |= Space;
else if (c == QLatin1Char('S'))
nfa->assertion |= NonSpace;
else if (c == QLatin1Char('d'))
nfa->assertion |= Digit;
else if (c == QLatin1Char('D'))
nfa->assertion |= NonDigit;
else if (c == QLatin1Char('w'))
nfa->assertion |= Word;
else if (c == QLatin1Char('W'))
nfa->assertion |= NonWord;
else {
nfa->c << QLatin1Char('$').unicode();
--i;
}
if (prev)
prev->out.next = nfa;
prev = nfa;
}
} else if (c == QLatin1Char('[')) {
if (set) {
set->c << c.unicode();
// qWarning("Nested sets are not supported (and useless
// BTW)...");
continue;
}
// enter set...
set = new QNFA;
// qDebug("set start");
} else if (c == QLatin1Char(']')) {
if (!set) {
qWarning("Unmatched set closing marker");
continue;
}
// leave set...
if (prev)
prev->out.next = set;
prev = set;
set = 0;
// qDebug("set end");
/*
} else if ( c == QLatin1Char('(') ) {
// allow trivial groups
QList<int> cuts;
int idx = i, nest = 1;
while ( nest && (++idx < length) )
{
if ( d[idx] == '\\' )
{
++idx;
continue;
} else if ( d[idx] == '(' ) {
++nest;
} else if ( d[idx] == ')' ) {
--nest;
} else if ( (nest == 1) && (d[idx] == '|') ) {
cuts << idx;
} else if ( d[idx] == '[' ) {
while ( ++idx < length )
{
if ( d[idx] == '\\' )
{
++idx;
continue;
} else if ( d[idx] == ']' ) {
break;
}
}
}
}
*/
} else if (set) {
if ((c == QLatin1Char('^')) && !set->c.count()) {
set->c << '\0';
continue;
}
quint16 prev =
set->c.count() ? set->c.at(set->c.length() - 1) : '\0';
if ((c == '-') && (prev != '\0') && ((i + 1) < length)) {
quint16 cse = d[++i].unicode();
for (quint16 csi = prev + 1; csi <= cse; ++csi) {
QChar csc(csi);
if (c.isLetter() && !cs)
set->c << c.toLower().unicode()
<< c.toUpper().unicode();
else
set->c << csi;
}
} else {
if (c.isLetter() && !cs)
set->c << c.toLower().unicode() << c.toUpper().unicode();
else
set->c << c.unicode();
}
// qDebug("set << %c", c.toLatin1());
} else if (c == QLatin1Char('+')) {
if (prev)
prev->assertion |= OneOrMore;
} else if (c == QLatin1Char('*')) {
if (prev)
prev->assertion |= ZeroOrMore;
} else if (c == QLatin1Char('?')) {
if (prev)
prev->assertion |= ZeroOrOne;
} else {
nfa = new QNFA;
if (c.isLetter() && !cs) {
nfa->c << c.toLower().unicode() << c.toUpper().unicode();
} else {
nfa->c << c.unicode();
}
if (prev)
prev->out.next = nfa;
prev = nfa;
}
if (!first)
first = prev;
}
if (end) {
*end = prev;
}
return first;
}
bool plain(const QString &word, QString *dest) {
if (dest)
dest->clear();
for (int i = 0; i < word.length(); i++) {
QChar c = word.at(i);
if (c == QLatin1Char('\\')) {
if (dest && ((i + 1) < word.length())) {
c = word.at(++i);
if (c == QLatin1Char('n'))
dest->append('\n');
else if (c == QLatin1Char('t'))
dest->append('\t');
else if (c == QLatin1Char('r'))
dest->append('\r');
else
dest->append(c);
}
} else if (c == QLatin1Char('[') || c == QLatin1Char(']') ||
c == QLatin1Char('+') || c == QLatin1Char('*') ||
c == QLatin1Char('?') || c == QLatin1Char('$')) {
if (dest)
dest->clear();
return false;
} else {
if (dest)
dest->append(c);
}
}
return true;
}
void addWord(QCharTree &tree, const QString &w, int action, bool cs) {
// qDebug("Adding word to char tree : %s", qPrintable(w));
if (cs) {
quint16 u = w.at(0).unicode();
QCharTree::iterator it = tree.find(u), tmp;
if (it == tree.end())
it = tree.insert(u, QCharTreeNode(u));
for (int i = 1; i < w.length(); i++) {
u = w.at(i).unicode();
// qDebug("char %c", w.at(i).toLatin1());
tmp = it->next.find(u);
if (tmp == it->next.end())
tmp = it->next.insert(u, QCharTreeNode(u));
it = tmp;
}
// add action handler
QCharTreeNode node;
node.value.action = action;
it->next[0] = node;
} else if (0) {
QChar c = w.at(0);
quint16 u = c.unicode();
QCharTree::iterator it, tmp;
QList<QCharTree::iterator> l, ltmp;
if (c.isLetter()) {
u = c.toLower().unicode();
tmp = tree.find(u);
if (tmp == tree.end())
tmp = tree.insert(u, QCharTreeNode(u));
l << tmp;
u = c.toUpper().unicode();
tmp = tree.find(u);
if (tmp == tree.end())
tmp = tree.insert(u, QCharTreeNode(u));
l << tmp;
} else {
tmp = tree.find(u);
if (tmp == tree.end())
tmp = tree.insert(u, QCharTreeNode(u));
l << tmp;
}
for (int i = 1; i < w.length(); ++i) {
c = w.at(i);
QList<QChar> lc;
if (c.isLetter())
lc << c.toLower() << c.toUpper();
else
lc << c;
foreach (c, lc) {
u = c.unicode();
foreach (it, l) {
tmp = it->next.find(u);
if (tmp == it->next.end())
tmp = it->next.insert(u, QCharTreeNode(u));
ltmp << tmp;
}
}
l = ltmp;
}
// add action handler
QCharTreeNode node;
node.value.action = action;
foreach (it, l)
it->next[0] = node;
}
}
void squeeze(QNFA *nfa) {
squeeze(nfa->tree);
if (nfa->type & Match) {
if (nfa->out.branch)
for (int i = 0; i < nfa->out.branch->count(); ++i)
squeeze(nfa->out.branch->at(i));
} else if (nfa->out.next) {
squeeze(nfa->out.next);
}
}
void squeeze(QCharTreeLevel &lvl) {
lvl.squeeze();
QCharTreeLevel::iterator it = lvl.begin();
while (it != lvl.end())
squeeze((it++)->next);
}

View File

@ -1,259 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _Q_NFA_H_
#define _Q_NFA_H_
/*!
\file qnfa.h
\brief Definition of the core QNFA syntax engine
*/
#include <QChar>
#include <QHash>
#include <QList>
#include <QStack>
#include <QString>
#include "light_vector.h"
struct QNFA;
typedef light_vector<quint16> QNFASet;
class QNFABranch : public light_vector<QNFA *> {
public:
~QNFABranch();
};
enum NFAType {
Char = 0,
Match = 1,
CxtBeg = 2,
CxtEnd = 4,
CxtEsc = 8,
ContextBegin = Match | CxtBeg,
ContextEnd = Match | CxtEnd,
EscapeSeq = Match | CxtEsc,
Escaped = 16,
Exclusive = 32,
StayOnLine = 64,
Reserved = 128
};
enum NFAAssertion {
NoAssertion = 0,
One = 0, // default standard
ZeroOrOne = 1, // ?
ZeroOrMore = 2, // *
OneOrMore = 4, // +
WordStart = 8,
WordEnd = 16,
Word = 32,
NonWord = 64,
Digit = 128,
NonDigit = 256,
Space = 512,
NonSpace = 1024,
CaseSensitive = 2048
};
struct QCharTreeNode;
typedef QHash<quint16, QCharTreeNode> QCharTreeLevel;
struct QCharTreeNode {
inline QCharTreeNode(quint16 v = 0) { value.unicode = v; }
inline QCharTreeNode(const QCharTreeNode &o) {
value = o.value;
next = o.next;
}
union {
int action;
quint16 unicode;
} value;
QCharTreeLevel next;
};
Q_DECLARE_TYPEINFO(QCharTreeNode, Q_MOVABLE_TYPE);
typedef QCharTreeLevel QCharTree;
struct QNFA {
QNFA();
~QNFA();
QNFASet c;
QCharTree tree;
union {
QNFA *next;
QNFABranch *branch;
} out;
quint8 type;
quint16 assertion;
int actionid;
static quint32 _count;
};
struct QNFAMatchContext {
inline QNFAMatchContext(QNFA *root = 0) : context(root) {}
inline QNFAMatchContext &operator=(QNFAMatchContext *c) {
if (c) {
context = c->context;
parents = c->parents;
meaningless = c->meaningless;
} else {
reset();
}
return *this;
}
inline QNFAMatchContext &operator=(const QNFAMatchContext &c) {
context = c.context;
parents = c.parents;
meaningless = c.meaningless;
return *this;
}
inline void reset() {
context = 0;
while (parents.count())
context = parents.pop();
}
QNFA *context;
QNFASet meaningless;
QStack<QNFA *> parents;
};
class QNFAMatchHandler {
public:
virtual ~QNFAMatchHandler() {}
virtual void matched(int pos, int len, int action) = 0;
};
class QNFAMatchNotifier {
private:
struct Command {
inline Command(int p, int len, int act)
: pos(p), length(len), action(act) {}
int pos;
int length;
int action;
};
typedef QList<Command> CommandList;
public:
inline QNFAMatchNotifier(QNFAMatchHandler *h) : handler(h) {}
inline QNFAMatchNotifier &operator=(const QNFAMatchNotifier &n) {
handler = n.handler;
return *this;
}
inline void operator()(int pos, int len, int action) {
if (handler && (m_buffers.isEmpty() || m_pending.count()))
handler->matched(pos, len, action);
else
m_buffers.top() << Command(pos, len, action);
}
inline int bufferLevel() const { return m_buffers.count(); }
inline void startBuffering() { m_buffers.push(CommandList()); }
inline void stopBuffering() { m_pending = m_buffers.pop(); }
inline void flush() {
foreach (Command c, m_pending)
handler->matched(c.pos, c.length, c.action);
m_pending.clear();
}
inline void clear() {
m_pending.clear();
m_buffers.clear();
}
private:
QNFAMatchHandler *handler;
CommandList m_pending;
QStack<CommandList> m_buffers;
};
void match(QNFAMatchContext *lexer, const QChar *d, int length,
QNFAMatchNotifier notify);
inline void match(QNFAMatchContext *lexer, const QString &s,
QNFAMatchNotifier notify) {
match(lexer, s.constData(), s.length(), notify);
}
QNFA *lexer();
void squeeze(QNFA *nfa);
void squeeze(QCharTreeLevel &lvl);
QNFA *sharedContext(const QString &start, QNFA *other, bool cs);
QNFA *context(const QString &start, const QString &stop, const QString &escape,
int action, QNFA **handler = 0, bool cs = true);
inline void addNFA(QNFA *context, QNFA *nfa) {
context->out.branch->append(nfa);
}
bool plain(const QString &word, QString *dest);
void addWord(QCharTree &tree, const QString &w, int action, bool cs);
void addWord(QNFA *lexer, const QString &w, int action, bool cs);
void addSequence(QNFA *lexer, const QString &w, int action, bool cs);
QNFA *sequence(const QChar *d, int length, QNFA **end, bool cs);
inline QNFA *sequence(const QString &s, QNFA **end, bool cs) {
return sequence(s.constData(), s.length(), end, cs);
}
#endif //!_Q_NFA_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,151 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QNFA_DEFINITION_H_
#define _QNFA_DEFINITION_H_
/*!
\file qnfadefinition.h
\brief Definition of the QNFADefinition class.
*/
#include "qlanguagedefinition.h"
#include "qlanguagefactory.h"
#include <QHash>
#include <QPointer>
#include <QStringList>
struct QNFA;
class QParenthesis;
class QFile;
class QDomDocument;
class QNFAAction {
public:
enum {
NoAction = 0,
FormatMask = 0x00000fff,
ParenMask = 0x00fff000,
Highlight = 0x01000000,
Indent = 0x02000000,
ParenOpen = 0x04000000,
ParenClose = 0x08000000,
MatchParen = 0x10000000,
Fold = 0x20000000,
Ambiguous = 0x40000000,
Content = 0x80000000
};
inline static int format(int id) { return id & FormatMask; }
inline static int parenthesis(int id) { return id & ParenMask; }
};
class QCE_EXPORT QNFADefinition : public QLanguageDefinition {
public:
QNFADefinition();
virtual ~QNFADefinition();
virtual QString language() const;
virtual QStringList extensions() const;
virtual int tokenize(QDocument *d, int line, int count);
virtual QString singleLineComment() const;
virtual QString defaultLineMark() const;
virtual void clearMatches(QDocument *d);
virtual void match(QDocumentCursor &c);
virtual QString indent(const QDocumentCursor &c);
virtual bool unindent(const QDocumentCursor &c, const QString &ktxt);
virtual void expand(QDocument *d, int line);
virtual void collapse(QDocument *d, int line);
virtual int blockFlags(QDocument *d, int line, int depth) const;
static void load(QFile *f, QLanguageFactory::LangData *d, QFormatScheme *s);
static void load(const QString &file, QLanguageFactory::LangData *d,
QFormatScheme *s);
static void load(const QDomDocument &doc, QLanguageFactory::LangData *d,
QFormatScheme *s);
static void addContext(const QString &id, QNFA *nfa);
static void addEmbedRequest(const QString &lang, QNFA *dest);
static void shareEmbedRequests(QNFA *src, QNFA *dest, qsizetype offset);
private:
bool m_indentFold;
QString m_language, m_defaultMark, m_singleLineComment;
QStringList m_extensions;
QNFA *m_root;
QHash<QPointer<QDocument>, int> m_matchGroups;
static QHash<QString, int> m_paren;
static QHash<QString, QNFA *> m_contexts;
struct PMatch {
PMatch() : type(Invalid) {
line[0] = -1;
line[1] = -1;
column[0] = -1;
column[1] = -1;
length[0] = 0;
length[1] = 0;
}
enum Type { Invalid, Match, Mismatch };
char type;
int line[2];
int column[2];
int length[2];
};
void matchOpen(QDocument *d, PMatch &m);
void matchClose(QDocument *d, PMatch &m);
int findBlockEnd(QDocument *d, int line, bool *open = 0);
static void flushEmbedRequests(const QString &lang);
struct EmbedRequest {
inline EmbedRequest(QNFA *nfa, qsizetype idx)
: index(idx), target(nfa) {}
qsizetype index;
QNFA *target;
};
typedef QList<EmbedRequest> EmbedRequestList;
static QHash<QString, EmbedRequestList> m_pendingEmbeds;
};
#endif // !_QNFA_DEFINITION_H_

View File

@ -1,420 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
/*!
\file xml2qnfa.cpp
\brief Implementation of the QNFA builder (fetch syntax engine data from
XML files)
*/
#include "qnfa.h"
#include "qnfadefinition.h"
#include "qformatscheme.h"
#include <QDomDocument>
#include <QDomElement>
#include <QDomText>
#include <QVariant>
/*
<QNFA>
<word></word>
<sequence></sequence>
<context>
<start></start>
<stop></stop>
<escape></escape>
...
</context>
</QNFA>
*/
QString *_singleLineCommentTarget = 0;
bool stringToBool(const QString &s, bool previous) {
if (s.isEmpty())
return previous;
return ((s == "true") || (s == "enabled")) ||
((s != "false") && (s != "disabled") && QVariant(s).toBool());
}
int pid(const QString &s, QHash<QString, int> &pids) {
if (pids.contains(s))
return pids.value(s);
int id = (pids.count() + 1) << 12;
pids[s] = id;
return id;
}
int action(QDomElement c, QFormatScheme *f, QHash<QString, int> &pids,
int fid = 0) {
QString paren, spid, spt, sfid;
sfid = c.attribute("format");
if (sfid.length()) {
fid |= QNFAAction::Highlight | QNFAAction::format(f->id(sfid));
}
paren = c.attribute("parenthesis");
if (paren.length()) {
spid = paren.section(':', 0, -2);
spt = paren.section(':', -1, -1);
if (spt.endsWith("@nomatch")) {
spt.chop(8);
} else {
fid |= QNFAAction::MatchParen;
}
if (spid.length()) {
/*qDebug("paren : [%s|%s] => 0x%x",
qPrintable(spid), qPrintable(spt),
(spt == "open" ? QNFAAction::ParenOpen :
QNFAAction::ParenClose) | pid(spid, pids));
*/
if (spt == "open")
fid |= QNFAAction::ParenOpen;
else if (spt == "close")
fid |= QNFAAction::ParenClose;
else if (spt == "boundary")
fid |= QNFAAction::ParenOpen | QNFAAction::ParenClose;
fid |= QNFAAction::parenthesis(pid(spid, pids));
/*
qDebug("paren : [%s|%s] => 0x%x",
qPrintable(spid), qPrintable(spt),
fid & QNFAAction::ParenMask);
*/
}
}
if (stringToBool(c.attribute("indent"), false))
fid |= QNFAAction::Indent;
if (stringToBool(c.attribute("fold"), false))
fid |= QNFAAction::Fold;
// TODO : determine ambiguity automatically
if (stringToBool(c.attribute("ambiguous"), false))
fid |= QNFAAction::Ambiguous;
return fid;
}
void copy(const QCharTreeLevel &src, QCharTreeLevel &dest) {
QCharTreeLevel::const_iterator it = src.constBegin();
while (it != src.constEnd()) {
// qDebug("copying char tree level %c", QChar(it.key()).toLatin1());
if (!dest.contains(it.key()))
dest[it.key()] = *it;
else
copy(it->next, dest[it.key()].next);
++it;
}
}
void embed(QNFA *src, QNFA *dest, qsizetype idx = 0) {
QNFA *nfa;
const auto n = src->out.branch->count();
// dest->out.branch->alloc(idx, n);
// qDebug("\tembedding %i children", n);
for (size_t i = 0; i < n; ++i) {
nfa = src->out.branch->at(i);
if (nfa->type & Reserved)
continue;
// qDebug("\t\teffectively embedding 0x%x at %i", nfa, idx);
dest->out.branch->insert(idx++, nfa);
}
copy(src->tree, dest->tree);
}
void fillContext(QNFA *cxt, QDomElement e, QFormatScheme *f,
QHash<QString, int> &pids, bool cs);
void fillContext(QNFA *cxt, QDomNodeList l, QFormatScheme *f,
QHash<QString, int> &pids, bool cs);
void addToContext(QNFA *cxt, QDomElement c, int fid, QFormatScheme *f,
QHash<QString, int> &pids, const QStringList &pref,
const QStringList &suff, bool cs) {
QString tag = c.tagName();
if (!c.hasChildNodes() && tag != "embed")
return;
cs = stringToBool(c.attribute("caseSensitive"), cs);
if ((tag == "start") || (tag == "stop") || (tag == "escape")) {
return;
} else if (tag == "word") {
// qDebug("adding word : %s",
// qPrintable(c.firstChild().toText().data()));
const QString value = c.firstChild().toText().data();
if (pref.isEmpty() && suff.isEmpty()) {
addWord(cxt, value, fid, cs);
} else if (pref.count()) {
foreach (const QString &p, pref) {
if (suff.isEmpty()) {
addWord(cxt, p + value, fid, cs);
} else {
foreach (const QString &s, suff) {
addWord(cxt, p + value + s, fid, cs);
}
}
}
} else {
foreach (const QString &s, suff) {
addWord(cxt, value + s, fid, cs);
}
}
} else if (tag == "sequence") {
const QString value = c.firstChild().toText().data();
// qDebug("adding sequence : %s [0x%x]", qPrintable(value), cxt);
if (pref.isEmpty() && suff.isEmpty()) {
addSequence(cxt, value, fid, cs);
} else if (pref.count()) {
foreach (const QString &p, pref) {
if (suff.isEmpty()) {
addSequence(cxt, p + value, fid, cs);
} else {
foreach (const QString &s, suff) {
addSequence(cxt, p + value + s, fid, cs);
}
}
}
} else {
foreach (const QString &s, suff) {
addSequence(cxt, value + s, fid, cs);
}
}
} else if (tag == "list") {
QDomNodeList children = c.childNodes();
QStringList prefixes, suffixes;
// qDebug("starting list");
for (int j = 0; j < children.count(); ++j) {
QDomElement cc = children.at(j).toElement();
if (cc.isNull())
continue;
const QString role = cc.tagName();
const QString value = cc.firstChild().toText().data();
if (role == "prefix")
prefixes << value;
else if (role == "suffix")
suffixes << value;
else
addToContext(cxt, cc, action(cc, f, pids, fid), f, pids,
prefixes, suffixes, cs);
}
// qDebug("ending list");
} else if (tag == "embed") {
QNFADefinition::addEmbedRequest(c.attribute("target"), cxt);
} else if (tag == "context") {
QNFA *nfa, *start = 0, *hstart = 0, *cstart = 0, *stop = 0, *hstop = 0,
*escape = 0, *hescape = 0;
QList<QNFA *> lStart, lStop, lEscape;
QString attr;
int defact = action(c, f, pids);
QDomNodeList children = c.childNodes();
QString _id = c.attribute("id");
bool trans = stringToBool(c.attribute("transparency"), false);
bool stay = stringToBool(c.attribute("stayOnLine"), false);
for (int j = 0; j < children.count(); ++j) {
QDomElement child = children.at(j).toElement();
if (child.isNull() || !child.hasChildNodes())
continue;
bool tcs = stringToBool(child.attribute("caseSensitive"), cs);
int act = action(child, f, pids);
if (!(act & QNFAAction::Highlight))
act |= QNFAAction::Highlight | QNFAAction::format(defact);
const QString role = child.tagName();
const QString value = child.firstChild().toText().data();
if (role == "start") {
start = sequence(value, &hstart, tcs);
start->actionid = act;
// start->type |= Reserved;
lStart << start;
if (!cstart) {
cstart = new QNFA;
cstart->type = ContextBegin | (stay ? StayOnLine : 0);
cstart->actionid = defact;
cstart->out.branch = new QNFABranch;
// only the first sequence comes
if (_singleLineCommentTarget && (_id == "comment/single"))
*_singleLineCommentTarget = value;
}
hstart->out.next = cstart;
hstart->actionid = act;
// hstart = nfa;
// qDebug("cxt start seq : %s [0x%x, 0x%x]", qPrintable(value),
// start, nfa);
} else if (role == "stop") {
stop = sequence(value, &hstop, tcs);
stop->actionid = act;
stop->type |= Reserved;
lStop << stop;
nfa = new QNFA;
nfa->type = ContextEnd;
nfa->actionid = act;
// nfa->out.branch = new QNFABranch;
hstop->out.next = nfa;
hstop->actionid = act;
hstop = nfa;
attr = child.attribute("exclusive");
if (attr.isEmpty() || (attr == "true") || attr.toUInt())
hstop->type |= Exclusive;
// qDebug("cxt stop seq : %s [0x%x]", qPrintable(value), act);
} else if (role == "escape") {
escape = sequence(value, &hescape, tcs);
escape->type |= Reserved;
lEscape << escape;
nfa = new QNFA;
nfa->type = EscapeSeq;
nfa->actionid = action(child, f, pids);
// nfa->out.branch = new QNFABranch;
hescape->out.next = nfa;
// hescape = nfa;
}
}
if (hstart) {
// qDebug("starting cxt %s:0x%x [0x%x]",
// qPrintable(c.attribute("id")), cstart, cxt);
foreach (escape, lEscape) {
// cstart->type |= Escaped;
addNFA(cstart, escape);
}
// qDebug("after esc : %i", cstart->out.branch->count());
foreach (stop, lStop)
addNFA(cstart, stop);
// qDebug("after stop : %i", cstart->out.branch->count());
} else {
cstart = new QNFA;
cstart->type = ContextBegin | (stay ? StayOnLine : 0);
cstart->actionid = defact;
cstart->out.branch = new QNFABranch;
}
fillContext(cstart, c, f, pids, cs);
if (c.hasAttribute("id")) {
QNFADefinition::addContext(
c.ownerDocument().documentElement().attribute("language") +
":" + _id,
cstart);
} else {
// qDebug("unregistered context");
}
// qDebug("after sub : %i", cstart->out.branch->count());
if (trans) {
QNFADefinition::shareEmbedRequests(cxt, cstart,
cstart->out.branch->length());
embed(cxt, cstart, cstart->out.branch->length());
}
if (hstart) {
foreach (start, lStart)
addNFA(cxt, start);
// qDebug("ending cxt");
} else {
}
// fillContext(subcxt, c, f, pids);
} else {
// qDebug("unhandled tag : %s", qPrintable(tag));
}
}
void fillContext(QNFA *cxt, QDomElement e, QFormatScheme *f,
QHash<QString, int> &pids, bool cs) {
cs = stringToBool(e.attribute("caseSensitive"), cs);
fillContext(cxt, e.childNodes(), f, pids, cs);
}
void fillContext(QNFA *cxt, QDomNodeList l, QFormatScheme *f,
QHash<QString, int> &pids, bool cs) {
// qDebug("filling context from %i nodes", l.count());
for (int i = 0; i < l.count(); i++) {
QDomElement c = l.at(i).toElement();
if (c.isNull())
continue;
addToContext(cxt, c, action(c, f, pids), f, pids, QStringList(),
QStringList(), cs);
}
// qDebug("context filled");
}

View File

@ -1,359 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qpanellayout.h"
/*!
\file qpanellayout.cpp
\brief Implementation of the QPanelLayout class.
*/
#include "qeditor.h"
#include "qpanel.h"
/*!
\class QPanelLayout
\brief A specialized layout taking care of panel display
The panel layout is specialized in several ways :
<ul>
<li>It only operates on specific widgets (which inherit QPanel)</li>
<li>It can only layout widgets in the viewport margins of a QEditor (could work
with any QAbstractScrollArea if a single method was made public instead of
protected...) so it does not qualify as a "real" layout (contrary to grid/box
layouts)</li> <li>It positions widgets on the border of the editor in the same
way the Border Layout example does (most of the layout code actually comes from
there).</li> <li>It provides serialization/deserialization of its layout
structure</li>
</ul>
*/
/*
The layouting code is inspired from a Qt4 example : Border Layout
*/
/*!
\brief ctor
*/
QPanelLayout::QPanelLayout(QEditor *p) : QLayout(p), m_parent(p) {
setSpacing(0);
}
/*!
\brief ctor
\param layout structure to deserailize
*/
QPanelLayout::QPanelLayout(const QString &layout, QEditor *p)
: QLayout(p), m_parent(p) {
setSpacing(0);
addSerialized(layout);
}
/*!
\brief dtor
*/
QPanelLayout::~QPanelLayout() {
QLayoutItem *l;
while ((l = QPanelLayout::takeAt(0)))
delete l;
}
/*!
\return A serialized layout strucure
*/
QString QPanelLayout::serialized() const {
/*
Scheme :
QPanelLayout::Position '{' comma-separated list of identifiers '}'
*/
QHash<int, QString> posMap;
for (int i = 0; i < m_list.size(); ++i) {
PanelWrapper *wrapper = m_list.at(i);
Position position = wrapper->position;
QPanel *panel = qobject_cast<QPanel *>(wrapper->item->widget());
if (!panel)
continue;
if (!posMap.contains(position)) {
posMap[position] =
QString::number(position) + "{" + panel->id() + "}";
} else {
QString &ref = posMap[position];
ref.insert(ref.length() - 2, QStringLiteral(",") + panel->id());
}
}
auto values = posMap.values();
return values.join("");
}
/*!
\brief Add the content of a serialized layout structure
*/
void QPanelLayout::addSerialized(const QString &layout) {
// qDebug("layout : %s", qPrintable(layout));
int last = 0, i = 0;
bool inList = false;
Position position = West;
while (i < layout.length()) {
if (inList) {
if (layout.at(i) == '}')
inList = false;
if (!inList || (layout.at(i) == ',')) {
QPanel *panel =
QPanel::panel(layout.mid(last, i - last), m_parent);
if (panel) {
panel->attach(m_parent);
addWidget(panel, position);
// qDebug("\tpanel : %s", qPrintable(layout.mid(last, i -
// last)));
}
last = i + 1;
}
} else if (layout.at(i) == '{') {
inList = true;
auto pos = layout.mid(last, i - last);
position = Position(pos.toInt());
// qDebug("position : %i [%s]", position,
// qPrintable(layout.mid(last, i - last)));
last = i + 1;
}
++i;
}
update();
}
/*!
\return the list of panels managed by the layout
*/
QList<QPanel *> QPanelLayout::panels() const {
QList<QPanel *> l;
foreach (PanelWrapper *w, m_list) {
QPanel *p = qobject_cast<QPanel *>(w->item->widget());
if (p)
l << p;
}
return l;
}
/*!
\return the count of managed panels
*/
int QPanelLayout::count() const { return m_list.count(); }
/*!
\internal
*/
bool QPanelLayout::hasHeightForWidth() const { return false; }
/*!
\internal
*/
Qt::Orientations QPanelLayout::expandingDirections() const {
return Qt::Horizontal | Qt::Vertical;
}
/*!
\internal
*/
QSize QPanelLayout::sizeHint() const { return calculateSize(SizeHint); }
/*!
\internal
*/
QSize QPanelLayout::minimumSize() const { return calculateSize(MinimumSize); }
/*!
\internal
*/
void QPanelLayout::addItem(QLayoutItem *item) { add(item, West); }
/*!
\brief Add a panel at a given position
*/
void QPanelLayout::addWidget(QWidget *widget, Position position) {
add(new QWidgetItem(widget), position);
}
/*!
\internal
*/
QLayoutItem *QPanelLayout::itemAt(int idx) const {
PanelWrapper *wrapper = m_list.value(idx);
if (wrapper)
return wrapper->item;
else
return 0;
}
/*!
\internal
*/
QLayoutItem *QPanelLayout::takeAt(int idx) {
if ((idx >= 0) && (idx < m_list.size())) {
PanelWrapper *layoutStruct = m_list.takeAt(idx);
Q_ASSERT(layoutStruct);
if (!layoutStruct)
return 0;
QLayoutItem *li = layoutStruct->item;
delete layoutStruct;
return li;
}
return 0;
}
/*!
\internal
*/
void QPanelLayout::setGeometry(const QRect &r) {
// qDebug("laying out %i panels", count());
QScrollBar *vb = m_parent->verticalScrollBar(),
*hb = m_parent->horizontalScrollBar();
QRect rect(r.x(), r.y(),
r.width() - (vb->isVisibleTo(m_parent) ? vb->width() : 0),
r.height() - (hb->isVisibleTo(m_parent) ? hb->height() : 0));
int i, eastWidth = 0, westWidth = 0, northHeight = 0, southHeight = 0,
centerHeight = 0;
QLayout::setGeometry(rect);
for (i = 0; i < m_list.size(); ++i) {
PanelWrapper *wrapper = m_list.at(i);
QLayoutItem *item = wrapper->item;
Position position = wrapper->position;
if (item->isEmpty())
continue;
if (position == North) {
item->setGeometry(QRect(rect.x(), rect.y() + northHeight,
rect.width(), item->sizeHint().height()));
northHeight += item->geometry().height() + spacing();
} else if (position == South) {
int ht = item->sizeHint().height();
if (item->hasHeightForWidth()) {
ht = item->heightForWidth(rect.width());
}
item->setGeometry(QRect(item->geometry().x(), item->geometry().y(),
rect.width(), ht));
southHeight += item->geometry().height() + spacing();
item->setGeometry(QRect(
rect.x(), rect.y() + rect.height() - southHeight + spacing(),
item->geometry().width(), item->geometry().height()));
}
}
centerHeight = rect.height() - northHeight - southHeight;
for (i = 0; i < m_list.size(); ++i) {
PanelWrapper *wrapper = m_list.at(i);
QLayoutItem *item = wrapper->item;
Position position = wrapper->position;
if (item->isEmpty())
continue;
if (position == West) {
item->setGeometry(QRect(rect.x() + westWidth,
rect.y() + northHeight,
item->sizeHint().width(), centerHeight));
westWidth += item->geometry().width() + spacing();
} else if (position == East) {
item->setGeometry(QRect(item->geometry().x(), item->geometry().y(),
item->sizeHint().width(), centerHeight));
eastWidth += item->geometry().width() + spacing();
item->setGeometry(
QRect(rect.x() + rect.width() - eastWidth + spacing(),
rect.y() + northHeight, item->geometry().width(),
item->geometry().height()));
}
}
m_parent->setPanelMargins(westWidth, rect.y() + northHeight, eastWidth,
southHeight);
}
/*!
\internal
*/
void QPanelLayout::add(QLayoutItem *item, Position position) {
QPanel *p;
if ((p = qobject_cast<QPanel *>(item->widget()))) {
// p->setParent(m_parent);
p->setVisible(p->defaultVisibility());
}
m_list.append(new PanelWrapper(item, position));
}
/*!
\internal
*/
QSize QPanelLayout::calculateSize(SizeType sizeType) const {
QSize totalSize;
for (int i = 0; i < m_list.size(); ++i) {
QSize itemSize;
PanelWrapper *wrapper = m_list.at(i);
Position position = wrapper->position;
if (sizeType == MinimumSize)
itemSize = wrapper->item->minimumSize();
else // ( sizeType == SizeHint )
itemSize = wrapper->item->sizeHint();
if ((position == North) ||
(position == South)) // || (position == Center) )
totalSize.rheight() += itemSize.height();
if ((position == West) ||
(position == East)) // || (position == Center) )
totalSize.rwidth() += itemSize.width();
}
return totalSize;
}

View File

@ -1,84 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QPANEL_LAYOUT_H_
#define _QPANEL_LAYOUT_H_
#include "qce-config.h"
/*!
\file qpanellayout.h
\brief Definition of the QPanelLayout class
*/
#include <QLayout>
#include <QList>
#include <QPointer>
class QPanel;
class QEditor;
class QCE_EXPORT QPanelLayout : public QLayout {
Q_OBJECT
public:
enum Position { West, North, South, East };
QPanelLayout(QEditor *p);
QPanelLayout(const QString &layout, QEditor *p);
virtual ~QPanelLayout();
virtual int count() const;
virtual bool hasHeightForWidth() const;
virtual Qt::Orientations expandingDirections() const;
virtual QSize sizeHint() const;
virtual QSize minimumSize() const;
virtual QLayoutItem *itemAt(int idx) const;
virtual QLayoutItem *takeAt(int idx);
QString serialized() const;
void addSerialized(const QString &layout);
QList<QPanel *> panels() const;
public slots:
virtual void addItem(QLayoutItem *item);
virtual void setGeometry(const QRect &rect);
void add(QLayoutItem *item, Position position);
void addWidget(QWidget *widget, Position position);
private:
QPointer<QEditor> m_parent;
struct PanelWrapper {
PanelWrapper(QLayoutItem *i, Position p) {
item = i;
position = p;
}
QLayoutItem *item;
Position position;
};
enum SizeType { MinimumSize, SizeHint };
QSize calculateSize(SizeType sizeType) const;
QList<PanelWrapper *> m_list;
};
#endif // _QPANEL_LAYOUT_H_

View File

@ -1,160 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qreliablefilewatch.h"
/*!
\file qreliablefilewatch.cpp
\brief Implementation of the QReliableFileWatch class.
*/
#include <QFile>
#include <QTimerEvent>
/*!
\class QReliableFileWatch
\brief A specialized file monitor that works around some issues in
QFileSystemWatcher
*/
QReliableFileWatch::QReliableFileWatch(QObject *p) : QFileSystemWatcher(p) {
connect(this, SIGNAL(fileChanged(QString)), this,
SLOT(sourceChanged(QString)));
}
QReliableFileWatch::~QReliableFileWatch() {}
void QReliableFileWatch::addWatch(const QString &file, QObject *recipient) {
QHash<QString, Watch>::iterator it = m_targets.find(file);
if (it != m_targets.end()) {
it->recipients << recipient;
} else {
QFile f(file);
Watch w;
w.state = Clean;
w.size = f.size();
w.recipients << recipient;
m_targets[file] = w;
addPath(file);
}
}
void QReliableFileWatch::removeWatch(QObject *recipient) {
removeWatch(QString(), recipient);
}
void QReliableFileWatch::removeWatch(const QString &file, QObject *recipient) {
QHash<QString, Watch>::iterator it = m_targets.find(file);
if (it == m_targets.end()) {
if (!recipient)
return;
// given recipient stop watching any file
it = m_targets.begin();
while (it != m_targets.end()) {
int n = it->recipients.removeAll(recipient);
if (n && it->recipients.isEmpty()) {
// no more recipients watching this file
removePath(it.key());
it = m_targets.erase(it);
} else {
++it;
}
}
} else {
if (recipient) {
// given recipient stops watching given file
it->recipients.removeAll(recipient);
if (it->recipients.isEmpty()) {
// no more recipients watching this file
removePath(it.key());
m_targets.erase(it);
}
} else {
// stop watching given file at all
m_targets.erase(it);
}
}
}
void QReliableFileWatch::timerEvent(QTimerEvent *e) {
if (e->timerId() != m_timer.timerId())
return QFileSystemWatcher::timerEvent(e);
int postponedEmissions = 0;
QHash<QString, Watch>::iterator it = m_targets.begin();
while (it != m_targets.end()) {
if (it->state & Duplicate) {
// postpone signal emission...
++postponedEmissions;
it->state = Recent;
} else if (it->state & Recent) {
// send signal
it->state = Clean;
QFile f(it.key());
if (f.size() == it->size) {
// TODO : avoid signal emission if checksum match
// DO this in editor or here?
}
// qDebug("%s emission.", qPrintable(it.key()));
it->recipients.removeAll(nullptr);
foreach (QObject *r, it->recipients)
QMetaObject::invokeMethod(r, "fileChanged",
Q_ARG(QString, it.key()));
// it = m_state.erase(it);
}
++it;
}
if (postponedEmissions) {
// qDebug("%i postponed emissions", postponedEmissions);
m_timer.start(20, this);
}
}
void QReliableFileWatch::sourceChanged(const QString &filepath) {
m_timer.stop();
QHash<QString, Watch>::iterator it = m_targets.find(filepath);
if (it == m_targets.end())
return;
// qDebug("%s modified.", qPrintable(filepath));
if (it->state) {
it->state = Recent | Duplicate;
} else {
it->state = Recent;
}
m_timer.start(20, this);
}

View File

@ -1,66 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QRELIABLE_FILE_WATCH_H_
#define _QRELIABLE_FILE_WATCH_H_
#include "qce-config.h"
/*!
\file qreliablefilewatch.h
\brief Definition of the QReliableFileWatch class
*/
#include <QFileSystemWatcher>
#include <QHash>
#include <QPointer>
#include <QTimer>
class QCE_EXPORT QReliableFileWatch : protected QFileSystemWatcher {
friend class QPointer<QReliableFileWatch>;
Q_OBJECT
public:
QReliableFileWatch(QObject *p = nullptr);
virtual ~QReliableFileWatch();
public slots:
void addWatch(const QString &file, QObject *recipient);
void removeWatch(QObject *recipient);
void removeWatch(const QString &file, QObject *recipient);
protected:
virtual void timerEvent(QTimerEvent *e);
private slots:
void sourceChanged(const QString &filepath);
private:
enum State { Clean = 0, Recent = 1, Duplicate = 2 };
struct Watch {
char state;
qint64 size;
QList<QPointer<QObject>> recipients;
};
QBasicTimer m_timer;
QHash<QString, Watch> m_targets;
};
#endif // !_QRELIABLE_FILE_WATCH_H_

View File

@ -1,273 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qfoldpanel.h"
/*!
\file qfoldpanel.cpp
\brief Implementation of the QFoldPanel class.
\see QFoldPanel
*/
#include "qeditor.h"
#include "qdocument.h"
#include "qdocumentline.h"
#include "qlanguagedefinition.h"
#include <QBitmap>
#include <QMouseEvent>
#include <QPainter>
#include <QScrollBar>
#include <QStack>
/*!
\ingroup widgets
@{
*/
/*!
\class QFoldPanel
\brief A panel that draw fold indicators and provide fold/unfold actions
to the user
*/
/*!
\brief Constructor
*/
QFoldPanel::QFoldPanel(QWidget *p) : QPanel(p) { setFixedWidth(12); }
/*!
\brief Empty destructor
*/
QFoldPanel::~QFoldPanel() {}
/*!
*/
QString QFoldPanel::type() const { return "Fold indicators"; }
QString QFoldPanel::name() const { return tr("Fold Panel"); }
/*!
*/
void QFoldPanel::mousePressEvent(QMouseEvent *e) {
if (!editor() || !editor()->languageDefinition() ||
(e->button() != Qt::LeftButton)) {
QPanel::mousePressEvent(e);
return;
}
bool act = false;
QDocument *doc = editor()->document();
QLanguageDefinition *def = editor()->languageDefinition();
for (int i = 0; i < m_rects.count(); ++i) {
if (!m_rects.at(i).contains(e->pos()))
continue;
int ln = m_lines.at(i);
QDocumentLine b = doc->line(ln);
if (b.hasFlag(QDocumentLine::CollapsedBlockStart))
def->expand(doc, ln);
else if (def->blockFlags(doc, ln, 0) & QLanguageDefinition::Collapsible)
def->collapse(doc, ln);
act = true;
}
if (act)
editor()->setFocus();
else
QPanel::mousePressEvent(e);
}
/*!
*/
void QFoldPanel::paint(QPainter *p, QEditor *e) {
QDocument *doc = editor()->document();
QLanguageDefinition *def = e->languageDefinition();
if (!def || !doc) {
return;
}
m_rects.clear();
m_lines.clear();
bool bVisible = false; //,
// inCursorBlock = false;
QDocumentLine block;
const QFontMetrics fm(doc->font());
int n, pos, depth = 0, max = doc->lines(), ls = fm.lineSpacing(),
pageBottom = e->viewport()->height(),
contentsY = e->verticalOffset();
pos = -contentsY;
// qDebug("beg pos : %i", pos);
for (n = 0; n < max; ++n) {
if (pos > pageBottom)
break;
block = doc->line(n);
if (block.isHidden()) {
continue;
}
int len = ls * block.lineSpan();
int flags = def->blockFlags(doc, n, depth);
short open = QCE_FOLD_OPEN_COUNT(flags);
short close = QCE_FOLD_CLOSE_COUNT(flags);
bVisible = ((pos + len) >= 0);
int oldDepth = depth;
depth -= close;
if (depth < 0)
depth = 0;
depth += open;
if (open) {
if (flags & QLanguageDefinition::Collapsed) {
int bound = (ls - 8) / 2;
int mid = pos + len - ls / 6;
// outermost block folded : none of the opening is actually
// opened
depth -= open;
if (bVisible) {
// draw icon
if (bound > 0 && oldDepth > 0) {
p->drawLine(7, pos, 7, pos + bound);
}
if (close) {
p->drawLine(7, pos + 8 + bound, 7, mid);
p->drawLine(7, mid, 12, mid);
}
m_lines << n;
m_rects << drawIcon(p, e, 3, pos + bound, true);
}
int sub = open;
// qDebug("%i : +%i", n, open);
while (sub > 0 && ((n + 1) < max)) {
++n;
block = doc->line(n);
if (!block.isHidden()) {
if (bVisible)
p->drawLine(7, pos + 8 + bound, 7, pos + len);
--n;
break;
}
int sflags = def->blockFlags(doc, n, depth + 1);
short sopen = QCE_FOLD_OPEN_COUNT(sflags);
short sclose = QCE_FOLD_CLOSE_COUNT(sflags);
sub -= sclose;
if (sub <= 0)
break;
sub += sopen;
}
depth += sub;
if (bVisible && depth > 0) {
if (close)
p->drawLine(7, mid, 7, pos + len);
else
p->drawLine(7, pos + 8 + bound, 7, pos + len);
}
} else {
if (bVisible) {
int bound = (ls - 8) / 2;
if (oldDepth > 0 && bound > 0)
p->drawLine(7, pos, 7, pos + bound);
m_lines << n;
m_rects << drawIcon(p, e, 3, pos + bound, false);
int mid = pos + len - ls / 6;
if (close)
p->drawLine(7, mid, 12, mid);
if (bound > 0)
p->drawLine(7, pos + 8 + bound, 7, pos + len);
}
}
} else if ((oldDepth > 0) && bVisible) {
if (close) {
int mid = pos + len - ls / 6;
p->drawLine(7, pos, 7, mid);
p->drawLine(7, mid, 12, mid);
if (depth > 0)
p->drawLine(7, pos, 7, pos + len);
} else {
p->drawLine(7, pos, 7, pos + len);
}
}
pos += len;
}
}
QRect QFoldPanel::drawIcon(QPainter *p, QEditor *, int x, int y,
bool toExpand) {
QRect symbolRect(x, y, 8, 8);
// p->save();
// p->setRenderHint(QPainter::Antialiasing);
p->drawRect(symbolRect);
// p->restore();
if (toExpand) {
p->drawLine(x + 2, y + 4, x + 6, y + 4);
p->drawLine(x + 4, y + 2, x + 4, y + 6);
} else {
p->drawLine(x + 2, y + 4, x + 6, y + 4);
}
return symbolRect;
}
/*! @} */

View File

@ -1,55 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QFOLD_PANEL_H_
#define _QFOLD_PANEL_H_
#include "qpanel.h"
/*!
\file qfoldpanel.h
\brief Definition of the QFoldPanel class.
\see QFoldPanel
*/
class QDocumentLine;
class QCE_EXPORT QFoldPanel : public QPanel {
Q_OBJECT
public:
Q_PANEL(QFoldPanel, "Fold Panel")
QFoldPanel(QWidget *p = nullptr);
virtual ~QFoldPanel();
virtual QString type() const;
virtual QString name() const;
protected:
virtual void mousePressEvent(QMouseEvent *e);
virtual void paint(QPainter *p, QEditor *e);
QRect drawIcon(QPainter *p, QEditor *e, int x, int y, bool expand);
private:
QList<QRect> m_rects;
QList<int> m_lines;
};
QCE_AUTO_REGISTER(QFoldPanel)
#endif // _QFOLD_PANEL_H_

View File

@ -1,102 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qlinechangepanel.h"
/*!
\file qlinechangepanel.cpp
\brief Implementation of the QLineChangePanel class.
*/
#include "qeditor.h"
#include "qdocument.h"
#include "qdocumentline.h"
#include <QContextMenuEvent>
#include <QIcon>
#include <QMenu>
#include <QPainter>
#include <QScrollBar>
/*!
\ingroup widgets
@{
*/
/*!
\class QLineMarkPanel
\brief A specific panel in charge of drawing line numbers of an editor
\see QEditorInterface
*/
/*!
\brief Constructor
*/
QLineChangePanel::QLineChangePanel(QWidget *p) : QPanel(p) { setFixedWidth(4); }
/*!
\brief Empty destructor
*/
QLineChangePanel::~QLineChangePanel() {}
/*!
*/
QString QLineChangePanel::type() const { return "Line changes"; }
QString QLineChangePanel::name() const { return tr("Line Change Panel"); }
/*!
\internal
*/
void QLineChangePanel::paint(QPainter *p, QEditor *e) {
if (!e || !e->document())
return;
const QFontMetrics fm(e->document()->font());
int n, posY, as = fm.ascent(), ls = fm.lineSpacing(),
pageBottom = e->viewport()->height(),
contentsY = e->verticalOffset();
QDocument *d = e->document();
n = d->lineNumber(contentsY);
posY = 2 + d->y(n) - contentsY;
for (;; ++n) {
// qDebug("n = %i; pos = %i", n, posY);
QDocumentLine line = d->line(n);
if (line.isNull() || ((posY - as) > pageBottom))
break;
if (line.isHidden())
continue;
int span = line.lineSpan();
if (d->isLineModified(line)) {
p->fillRect(1, posY, 2, ls * span, Qt::red);
} else if (d->hasLineEverBeenModified(line)) {
p->fillRect(1, posY, 2, ls * span, Qt::green);
}
posY += ls * span;
}
}
/*! @} */

View File

@ -1,51 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QLINE_CHANGE_PANEL_H_
#define _QLINE_CHANGE_PANEL_H_
/*!
\file qlinechangepanel.h
\brief Definition of the QLineChangePanel class.
\see QLineChangePanel
*/
#include "qpanel.h"
#include <QHash>
#include <QIcon>
class QDocumentLine;
class QCE_EXPORT QLineChangePanel : public QPanel {
Q_OBJECT
public:
Q_PANEL(QLineChangePanel, "Line Change Panel")
QLineChangePanel(QWidget *p = nullptr);
virtual ~QLineChangePanel();
virtual QString type() const;
virtual QString name() const;
protected:
virtual void paint(QPainter *p, QEditor *e);
};
QCE_AUTO_REGISTER(QLineChangePanel)
#endif // _QLINE_CHANGE_PANEL_H_

View File

@ -1,198 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qlinemarkpanel.h"
/*!
\file qlinemarkpanel.cpp
\brief Implementation of the QLineMarkPanel class.
*/
#include "qeditor.h"
#include "qdocument.h"
#include "qdocumentline.h"
#include "qlanguagedefinition.h"
#include "qlinemarksinfocenter.h"
#include <QContextMenuEvent>
#include <QIcon>
#include <QMenu>
#include <QMessageBox>
#include <QPainter>
#include <QScrollBar>
/*!
\ingroup widgets
@{
*/
/*!
\class QLineMarkPanel
\brief A specific panel in charge of drawing line marks of an editor
*/
/*!
\brief Constructor
*/
QLineMarkPanel::QLineMarkPanel(QWidget *p) : QPanel(p) { setFixedWidth(18); }
/*!
\brief Empty destructor
*/
QLineMarkPanel::~QLineMarkPanel() {}
/*!
*/
QString QLineMarkPanel::type() const { return "Line marks"; }
/*!
\internal
*/
void QLineMarkPanel::paint(QPainter *p, QEditor *e) {
if (!e || !e->document())
return;
m_rects.clear();
m_lines.clear();
QDocument *d = e->document();
int maxMarksPerLine = d->maxMarksPerLine();
setFixedWidth(maxMarksPerLine ? maxMarksPerLine * 16 + 2 : 18);
const QFontMetrics fm(d->font());
int n, posY, as = fm.ascent(), ls = fm.lineSpacing(),
pageBottom = e->viewport()->height(),
contentsY = e->verticalOffset();
// QString txt;
// const QFontMetrics sfm(fontMetrics());
QLineMarksInfoCenter *mic = QLineMarksInfoCenter::instance();
n = d->lineNumber(contentsY);
posY = 2 + d->y(n) - contentsY;
// qDebug("first = %i; last = %i", first, last);
// qDebug("beg pos : %i", posY);
// qDebug("<session>");
for (;; ++n) {
// qDebug("n = %i; pos = %i", n, posY);
QDocumentLine line = d->line(n);
if (line.isNull() || ((posY - as) > pageBottom))
break;
if (line.isHidden())
continue;
m_lines << n;
m_rects << QRect(0, posY, width(), ls);
if (maxMarksPerLine) {
int count = 1;
QList<int> lm = line.marks();
foreach (int id, lm) {
QPixmap pix = mic->markType(id).icon;
if (pix.isNull())
continue;
int h = qMin(pix.height(), ls), w = qMin(pix.width(), 16),
x = count, y = posY + ((ls - h) >> 1);
p->drawPixmap(x, y, w, h, pix);
count += 16;
}
}
posY += ls * line.lineSpan();
}
// qDebug("</session>");
// setFixedWidth(sfm.width(txt) + 5);
}
/*!
\internal
*/
void QLineMarkPanel::mousePressEvent(QMouseEvent *e) {
// if ( !editor() || !editor()->document() || !editor()->marker() )
// {
// return QPanel::mousePressEvent(e);
// }
//
QPanel::mousePressEvent(e);
e->accept();
}
/*!
\internal
*/
void QLineMarkPanel::mouseReleaseEvent(QMouseEvent *e) {
if (!editor() || !editor()->document() || !editor()->languageDefinition()) {
QPanel::mouseReleaseEvent(e);
return;
}
// QMessageBox::warning(0, 0, "clik.");
e->accept();
for (int i = 0; i < m_rects.count(); ++i) {
if (m_rects.at(i).contains(e->pos())) {
auto ln = m_lines.at(i);
auto l = editor()->document()->line(ln);
emit onToggleMark(ln);
break;
}
}
QPanel::mouseReleaseEvent(e);
}
/*!
\internal
*/
void QLineMarkPanel::contextMenuEvent(QContextMenuEvent *e) {
if (!editor() || !editor()->document()) {
e->ignore();
return;
}
/*
QTextBlock b;
QMarker *m = editor()->marker();
QTextDocument *d = editor()->document();
e->accept();
QHash<int, QRect>::iterator i;
for ( i = rects.begin(); i != rects.end(); i++ )
{
b = d->findBlock(i.key());
if ( i->contains( e->pos() ) )
return m->menu(b, e->globalPos());
}
*/
}
/*! @} */

View File

@ -1,60 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QLINE_MARK_PANEL_H_
#define _QLINE_MARK_PANEL_H_
/*!
\file qlinemarkpanel.h
\brief Definition of the QLineMarkPanel class.
\see QLineMarkPanel
*/
#include "qpanel.h"
#include <QHash>
#include <QIcon>
class QDocumentLine;
class QCE_EXPORT QLineMarkPanel : public QPanel {
Q_OBJECT
public:
Q_PANEL(QLineMarkPanel, "Line Mark Panel")
QLineMarkPanel(QWidget *p = nullptr);
virtual ~QLineMarkPanel();
virtual QString type() const;
signals:
void onToggleMark(int lineIndex);
protected:
virtual void paint(QPainter *p, QEditor *e);
virtual void mousePressEvent(QMouseEvent *e);
virtual void mouseReleaseEvent(QMouseEvent *e);
virtual void contextMenuEvent(QContextMenuEvent *e);
private:
QList<QRect> m_rects;
QList<int> m_lines;
};
QCE_AUTO_REGISTER(QLineMarkPanel)
#endif // _QLINE_MARK_PANEL_H_

View File

@ -1,237 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qlinenumberpanel.h"
/*!
\file qlinenumberpanel.cpp
\brief Implementation of the QLineNumberPanel class
\see QLineNumberPanel
*/
#include <QPainter>
#include <QScrollBar>
#include "qdocument.h"
#include "qdocument_p.h"
#include "qdocumentline.h"
#include "qeditor.h"
/*!
\ingroup widgets
@{
*/
/*!
\class QLineNumberPanel
\brief A specific panel in charge of drawing line numbers of an editor
*/
/*!
\brief Constructor
*/
QLineNumberPanel::QLineNumberPanel(QWidget *p) : QPanel(p), m_verbose(false) {
setFixedWidth(20);
setObjectName("lineNumberPanel");
}
/*!
\brief Empty destructor
*/
QLineNumberPanel::~QLineNumberPanel() {}
/*!
*/
QString QLineNumberPanel::type() const {
return QStringLiteral("Line numbers");
}
QString QLineNumberPanel::name() const { return tr("Line Number Panel"); }
/*!
*/
bool QLineNumberPanel::isVerboseMode() const { return m_verbose; }
/*!
*/
void QLineNumberPanel::setVerboseMode(bool y) {
m_verbose = y;
update();
}
void QLineNumberPanel::setFont_slot(const QFont &font) { setFont(font); }
/*!
*/
void QLineNumberPanel::editorChange(QEditor *e) {
if (editor()) {
disconnect(editor(), SIGNAL(cursorPositionChanged()), this,
SLOT(update()));
disconnect(editor()->document(), SIGNAL(fontChanged(QFont)), this,
SLOT(setFont_slot(QFont)));
}
if (e) {
setFixedWidth(fontMetrics().horizontalAdvance(
QString::number(e->document()->lines())) +
5);
connect(e, &QEditor::cursorPositionChanged, this,
QOverload<>::of(&QLineNumberPanel::update));
connect(e->document(), &QDocument::fontChanged, this,
&QLineNumberPanel::setFont_slot);
}
}
/*!
*/
void QLineNumberPanel::paint(QPainter *p, QEditor *e) {
/*
possible Unicode caracter for wrapping arrow :
0x21B3
0x2937
*/
QFont f(font());
// f.setWeight(QFont::Bold);
const QFontMetrics sfm(f);
bool specialFontUsage = false;
QFont specialFont(font());
#ifndef WIN32
static const QChar wrappingArrow(0x2937);
const QFontMetrics specialSfm(sfm);
#if QT_VERSION >= 0x050000 && defined Q_OS_MAC && (QT_VERSION < 0x050200)
if (!specialSfm.inFont(wrappingArrow)) {
specialFontUsage = true;
specialFont.setFamily("Gothic Regular");
// specialSfm(specialFont);
}
#endif
#else
// 0xC4 gives a decent wrapping arrow in Wingdings fonts, availables on all
// windows systems
// this is a hackish fallback to workaround Windows issues with Unicode...
static const QChar wrappingArrow(0xC4);
specialFont.setFamily("Wingdings");
const QFontMetrics specialSfm(specialFont);
specialFontUsage = true;
#endif
int max = e->document()->lines();
if (max < 100)
max = 100; // always reserve 3 line number columns to avoid ugly jumping
// of width
QString s_width = QString::number(max);
s_width.fill('6');
const int panelWidth = sfm.horizontalAdvance(s_width) + 5;
setFixedWidth(panelWidth);
int n, posY, as = QFontMetrics(e->document()->font()).ascent(),
ls = e->document()->lineSpacing(),
pageBottom = e->viewport()->height(),
contentsY = e->verticalOffset();
QString txt;
QDocument *d = e->document();
const int cursorLine = e->cursor().lineNumber();
n = d->lineNumber(contentsY);
posY = as + 2 + d->y(n) - contentsY;
// qDebug("first = %i; last = %i", first, last);
// qDebug("beg pos : %i", posY);
for (;; ++n) {
// qDebug("n = %i; pos = %i", n, posY);
QDocumentLine line = d->line(n);
if (line.isNull() || ((posY - as) > pageBottom))
break;
if (line.isHidden())
continue;
bool draw = true;
if (!m_verbose) {
draw = !((n + 1) % 10) || !n || !line.marks().empty();
}
txt = QString::number(n + 1);
if (n == cursorLine) {
draw = true;
p->save();
QFont f = p->font();
f.setBold(true);
f.setUnderline(true);
p->setFont(f);
}
if (draw) {
p->drawText(width() - 2 - sfm.horizontalAdvance(txt), posY, txt);
if (specialFontUsage) {
if (line.lineSpan() > 1) {
p->save();
specialFont.setBold(n ==
cursorLine); // todo: only get bold on
// the current wrapped line
p->setFont(specialFont);
}
}
for (int i = 1; i < line.lineSpan(); ++i)
p->drawText(width() - 2 -
specialSfm.horizontalAdvance(wrappingArrow),
posY + i * ls, wrappingArrow);
if (specialFontUsage) {
if (line.lineSpan() > 1)
p->restore();
}
} else {
int yOff = posY - (as + 1) + ls / 2;
if ((n + 1) % 5)
p->drawPoint(width() - 5, yOff);
else
p->drawLine(width() - 7, yOff, width() - 2, yOff);
}
if (n == cursorLine) {
p->restore();
}
posY += ls * line.lineSpan();
}
// p->setPen(Qt::DotLine);
// p->drawLine(width()-1, 0, width()-1, pageBottom);
// setFixedWidth(sfm.width(txt) + 5);
}
/*! @} */
QSize QLineNumberPanel::sizeHint() const { return QSize(_fixWidth, 0); }

View File

@ -1,60 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QLINE_NUMBER_PANEL_H_
#define _QLINE_NUMBER_PANEL_H_
/*!
\file qlinenumberpanel.h
\brief Definition of the QLineNumberPanel class
\see QLineNumberPanel
*/
#include "qpanel.h"
class QCE_EXPORT QLineNumberPanel : public QPanel {
Q_OBJECT
public:
Q_PANEL(QLineNumberPanel, "Line Number Panel")
QLineNumberPanel(QWidget *p = nullptr);
virtual ~QLineNumberPanel();
bool isVerboseMode() const;
virtual QString type() const;
virtual QString name() const;
virtual QSize sizeHint() const;
public slots:
void setVerboseMode(bool y);
void setFont_slot(const QFont &font);
protected:
virtual void editorChange(QEditor *e);
virtual void paint(QPainter *p, QEditor *e);
bool m_verbose;
int mutable m_minWidth = 0;
int _fixWidth = 0;
};
QCE_AUTO_REGISTER(QLineNumberPanel)
#endif // _QLINE_NUMBER_PANEL_H_

View File

@ -1,266 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qpanel.h"
/*!
\file qpanel.cpp
\brief Implementation of the QPanel class
\see QPanel
*/
#include "qcodeedit.h"
#include "qeditor.h"
#include "qpanellayout.h"
#include <QFont>
#include <QFontMetrics>
#include <QPaintEvent>
#include <QPainter>
#include <QScrollBar>
#include <QApplication>
#include <QMouseEvent>
/*!
\ingroup widgets
@{
\class QPanel
\brief Helper class for panels displayed by QCodeEdit
*/
QHash<QString, QPanelCreator *> &QPanel::creators() {
static QHash<QString, QPanelCreator *> _c;
return _c;
}
QPanel *QPanel::panel(const QString &id, QWidget *p) {
if (!creators().contains(id))
return nullptr;
return creators().value(id)->panel(p);
}
void QPanel::registerCreator(QPanelCreator *c) { creators()[c->id()] = c; }
static int _panels = 0;
/*!
\brief Constructor
If the parent is a text editor, it is automatically connected to the
panel
*/
QPanel::QPanel(QWidget *p)
: QWidget(p), m_defaultVisibility(true), m_shownOnce(false) {
QEditor *e = qobject_cast<QEditor *>(p);
if (e)
attach(e);
++_panels;
}
/*!
\brief Destructor
*/
QPanel::~QPanel() {
--_panels;
// if ( !_panels )
// qDebug("Panels cleared.");
}
QString QPanel::name() const { return type(); }
/*!
*/
QEditor *QPanel::editor() { return m_editor; }
/*!
\brief Connect the panel to a text editor
*/
void QPanel::attach(QEditor *e) {
if (m_editor) {
disconnect(m_editor->document(), SIGNAL(formatsChanged()), this,
SLOT(update()));
disconnect(m_editor->document(), SIGNAL(contentsChanged()), this,
SLOT(update()));
disconnect(m_editor->verticalScrollBar(), SIGNAL(valueChanged(int)),
this, SLOT(update()));
}
QPanel::editorChange(e);
m_editor = e;
setParent(e);
if (m_editor) {
connect(m_editor->document(), SIGNAL(formatsChanged()), this,
SLOT(update()));
connect(m_editor->document(), SIGNAL(contentsChanged()), this,
SLOT(update()));
connect(m_editor->verticalScrollBar(), SIGNAL(valueChanged(int)), this,
SLOT(update()));
}
}
/*!
\brief
*/
bool QPanel::shallShow() const {
return m_shownOnce ? isHidden() : m_defaultVisibility;
}
/*!
\brief
*/
bool QPanel::defaultVisibility() const { return m_defaultVisibility; }
/*!
\brief
*/
void QPanel::setDefaultVisibility(bool on) { m_defaultVisibility = on; }
/*!
\brief Callback
Each time attach() is called, this function is called as well so that
the panel can fine tune its behaviour according to the editor monitored.
\note the Default implementation does nothing...
*/
void QPanel::editorChange(QEditor *) {}
bool QPanel::forward(QMouseEvent *e) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QPoint pos, globalPos = e->globalPosition().toPoint()
#else
QPoint pos, globalPos = e->globalPos()
#endif
,
ref = editor()->viewport()->pos();
if (editor()->viewport()->parentWidget())
ref = editor()->viewport()->parentWidget()->mapToGlobal(ref);
globalPos.setX(qBound(ref.x(), globalPos.x(), ref.x() + editor()->width()));
globalPos.setY(
qBound(ref.y(), globalPos.y(), ref.y() + editor()->height()));
pos = editor()->viewport()->mapFromGlobal(globalPos);
QMouseEvent fw(e->type(), pos, globalPos, e->button(), e->buttons(),
e->modifiers());
bool ok = qApp->sendEvent(editor()->viewport(), &fw) && fw.isAccepted();
// qDebug("forwarding mouse event : (%i, %i) => %i", pos.x(), pos.y(), ok);
return ok;
}
/*!
\internal
*/
void QPanel::mouseMoveEvent(QMouseEvent *e) {
if (!editor())
return;
if (forward(e))
e->accept();
else
QWidget::mouseMoveEvent(e);
}
/*!
\internal
*/
void QPanel::mousePressEvent(QMouseEvent *e) {
if (!editor())
return;
if (forward(e))
e->accept();
else
QWidget::mousePressEvent(e);
}
/*!
\internal
*/
void QPanel::mouseReleaseEvent(QMouseEvent *e) {
if (!editor())
return;
if (forward(e))
e->accept();
else
QWidget::mouseReleaseEvent(e);
}
/*!
\internal
*/
void QPanel::showEvent(QShowEvent *e) {
m_shownOnce = true;
QWidget::showEvent(e);
}
/*!
\internal
*/
void QPanel::hideEvent(QHideEvent *e) {
QCodeEdit *ce = QCodeEdit::manager(editor());
if (ce)
ce->panelLayout()->update();
QWidget::hideEvent(e);
}
/*!
\internal
*/
void QPanel::paintEvent(QPaintEvent *e) {
QWidget::paintEvent(e);
if (!m_editor || !m_editor->document()) {
e->ignore();
return;
}
e->accept();
QPainter p(this);
paint(&p, m_editor);
}
/*!
\internal
*/
void QPanel::paint(QPainter *, QEditor *) {}
/* @} */

View File

@ -1,114 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QPANEL_H_
#define _QPANEL_H_
/*!
\file qpanel.h
\brief Definition of the QPanel class
\see QPanel
\defgroup widgets
*/
#include "qce-config.h"
#include <QHash>
#include <QPointer>
#include <QWidget>
class QPainter;
class QPaintEvent;
class QEditor;
class QPanelCreator;
class QCE_EXPORT QPanel : public QWidget {
Q_OBJECT
public:
QPanel(QWidget *p = nullptr);
virtual ~QPanel();
virtual QString id() const = 0;
virtual QString type() const = 0;
virtual QString name() const;
QEditor *editor();
void attach(QEditor *e);
virtual bool shallShow() const;
bool defaultVisibility() const;
void setDefaultVisibility(bool on);
static QPanel *panel(const QString &id, QWidget *p = nullptr);
static void registerCreator(QPanelCreator *c);
protected:
virtual bool forward(QMouseEvent *e);
virtual void editorChange(QEditor *e);
virtual void mouseMoveEvent(QMouseEvent *e);
virtual void mousePressEvent(QMouseEvent *e);
virtual void mouseReleaseEvent(QMouseEvent *e);
virtual void showEvent(QShowEvent *e);
virtual void hideEvent(QHideEvent *e);
virtual void paintEvent(QPaintEvent *e);
virtual void paint(QPainter *p, QEditor *e);
private:
QPointer<QEditor> m_editor;
bool m_defaultVisibility, m_shownOnce;
static QHash<QString, QPanelCreator *> &creators();
};
class QPanelCreator {
public:
virtual ~QPanelCreator() {}
virtual QString id() const = 0;
virtual QPanel *panel(QWidget *p) = 0;
};
#define Q_PANEL(T, SID) \
public: \
class Creator : public QPanelCreator { \
public: \
virtual QString id() const { return SID; } \
\
virtual QPanel *panel(QWidget *p) { return new T(p); } \
\
static QPanelCreator *instance() { \
static Creator global; \
return &global; \
} \
\
Creator() {} \
virtual ~Creator() {} \
}; \
\
QString id() const { return SID; } \
\
static void _register() { QPanel::registerCreator(Creator::instance()); }
#define Q_PANEL_ID(T) T::Creator::instance()->id()
#define Q_CREATE_PANEL(T) QPanel::panel(Q_PANEL_ID(T))
#endif // _QPANEL_H_

View File

@ -1,416 +0,0 @@
/*!
\mainpage QCodeEdit manual
<h2>Sumarry :</h2>
<ol>
<li>\subpage intro "Introduction"</li>
<li>\subpage license "License"</li>
<li>\subpage tutorial "Tutorial"</li>
<li>\subpage qce_examples "Examples"</li>
</ol>
*/
/*!
\page intro Introduction
%QCodeEdit is a library offering an advanced text editing framework ready to use in other Qt apps.
The goals of QCodeEdit are :
<ul>
<li>Flexibility</li>
<li>Performance</li>
<li>Usability</li>
</ul>
Flexibility is achieved by splitting the library in logical components that can be used (almost)
independently. The document-related classes for instances don't need an editor to be around (it
is a bit similar to a model/view approach in that way). Two other important features of %QCodeEdit
have been designed to maximize flexibility : the syntax engine and the panel system.
<ul>
<li>the \ref QDocument "document" contains the data to be edited. It is made of \ref QDocumentLine "lines"
and can be manipulated using \ref QDocumentCursor "cursors".</li>
<li>the \ref QEditor "editor" is a simple widget which allows edition of the document through mouse and
keyboard interaction.</li>
<li>the syntax engine add new functionalities to both the \ref QDocument "document" and \ref QEditor "editor", such
as syntax highlighting, brace matching, code folding, auto indenting, (un)commenting... The builtin
implementation generates language definitions on-the-fly from XML files specifying the structure of
the language in a hierarchical and very intuitive way.</li>
<li>the \ref QPanel "panels" are simple widgets which can be attached to the \ref QEditor "editor" using a
\ref QCodeEdit "manager". Builtin panels include : line numbers, fold indicators, line marks, line changes,
editor status and search/replace. It is of course possible to create new panels very easily.</li>
</ul>
<table width="100%" border="0" frame="void"><tr width="100%">
<td align="left"></td>
<td align="right">\ref license "[Next:License]"</td>
</tr></table>
*/
/*!
\page license License
<table width="100%" border="0" frame="void"><tr width="100%">
<td align="left">\ref intro "[Previous:Introduction]"</td>
<td align="right">\ref tutorial "[Next:Tutorial]"</td>
</tr></table>
\verbinclude GPL.txt
<table width="100%" border="0" frame="void"><tr width="100%">
<td align="left">\ref intro "[Previous:Introduction]"</td>
<td align="right">\ref tutorial "[Next:Tutorial]"</td>
</tr></table>
*/
/*!
\page tutorial Tutorial
<table width="100%" border="0" frame="void"><tr width="100%">
<td align="left">\ref license "[Previous:License]"</td>
<td align="right">\ref qce_examples "[Next:Examples]"</td>
</tr></table>
Sumarry :
<ol>
<li>\ref install "Installation"</li>
<li>\ref start "Getting started"</li>
<li>\ref qce_examples "Examples"</li>
</ol>
\section install Installation
Installing %QCodeEdit is really simple.
\subsection install-source Building from sources
-# Make sure you have Qt4 installed and a supported compiler
-# Get %QCodeEdit sources : http://sourceforge.net/projects/edyuk/files
-# Uncompress the archive into the directory of your choice
-# Step into that directory and open a shell and type :\verbatim $ qmake && make \endverbatim
-# Once the compilation is finished type : \verbatim $ su -c "make install" \endverbatim
\subsection install-win Windows : Using the binary installer
-# Make sure you have Qt4 installed
-# Get %QCodeEdit windows installer : http://sourceforge.net/projects/edyuk/files
-# Run it
\section start Getting started
%QCodeEdit API has been modelled after that of QTextEdit/QTextDocument so porting should be relatively easy.
\n\n
The demo application gives a quick overview of what comes "for free" with %QCodeEdit and how to set it up
quickly. Some explanations are given below.
\n\n
For those interested in using some more advanced features of %QCodeEdit, the \ref qce_examples "examples" section awaits you.
\n\n
Above all, you need to configure your project to use %QCodeEdit. There are several possible ways of doing that :
<ul>
<li>Embedding %QCodeEdit code into your application : simply copy the lib directory where you want and add
a proper include directive inside your project (probably something like : include(lib/lib.pri) )</li>
<li>Using the installed %QCodeEdit library : simply add CONFIG += qcodeedit to your project and qmake will
take care of everything, provided %QCodeEdit has been installed properly beforehand</li>
<li>Tweaking your project files by hand : if you choose this way you probably don't need any advice on the
topic. Just inspect the qcodeedit.prf file to figure out what "tweaks" are required.</li>
</ul>
Here is the code, taken from the demo application, used to setup QCodeEdit :
\code
m_formats = new QFormatScheme("qxs/formats.qxf", this);
QDocument::setDefaultFormatScheme(m_formats);
QLineMarksInfoCenter::instance()->loadMarkTypes("qxs/marks.qxm");
m_languages = new QLanguageFactory(m_formats, this);
m_languages->addDefinitionPath("qxs");
\endcode
It is quite simple really. First we load a format scheme from a file and set
it as the default format scheme used by documents to draw themselves when no
other is provided.
\n\n
It used to be necessary when the format scheme was common to all languages.
However, in newer version of QCodeEdit (starting with 2.2) this is only
a recommended operation to prevent highlighting from being useless when some
languages do not come with their own format scheme.
\n\n
Then we load the line marks definition. Lines marks can be customized in any
way you like through the use of such a file or even directly using the various
methods provided by QLineMarksInfoCenter. Again, this is not required but
highly recommended, if you want to take advantage of %QCodeEdit features.
\n\n
Finally we create a language factory and feed it with a path to search for
language definitions. This language factory can later be used to easily
adjust the language definition of a \ref QDocument "document" / \ref QEditor "editor".
All the files recognized as language definitions within the given path will
be loaded and support for a set of languages will be added automagically :)
Now, lets create a neat widget with which the user will be able to actually edit some text :
\code
m_editControl = new QCodeEdit(this);
m_editControl
->addPanel("Line Mark Panel", QCodeEdit::West, true)
->setShortcut(QKeySequence("F6"));
m_editControl
->addPanel("Line Number Panel", QCodeEdit::West, true)
->setShortcut(QKeySequence("F11"));
m_editControl
->addPanel("Fold Panel", QCodeEdit::West, true)
->setShortcut(QKeySequence("F9"));
m_editControl
->addPanel("Line Change Panel", QCodeEdit::West, true)
m_editControl
->addPanel("Status Panel", QCodeEdit::South, true);
m_editControl
->addPanel("Search Replace Panel", QCodeEdit::South);
\endcode
So creating a managed editor only takes one line. All the rest is just about adding fancy
\ref QPanel "panels" to make the editor more user/friendly.
As you can see the QCodeEdit::addPanel() method returns a QAction object which behaves in
the exact same way the toggle view action of a QDockWidget do : un/check it to hide/show
the panel.
\n\n
Some of these toggle view actions are given shortcuts to make it easier to show them.
The boolean argument passed to addPanel() specifies whether the toggle view action should
be added to the context menu of the \ref QEditor "editor".
\n\n
If you think it takes too much space you can also specify the panel layout in its
serialized form. The code below has the exact same effect as the one above except that it
does not bother creating actions, let alone setting shortcuts.
\code
m_editControl = new QCodeEdit(
"0{Line Mark Panel, Line Number Panel, Fold Panel, Line Change Panel}"
"2{Status Panel, Search Replace Panel}",
this
);
\endcode
Ok, real good, but we still haven't loaded a file... Here's how to proceed :
\code
m_languages->setLanguage(m_editControl->editor(), filename);
m_editControl->editor()->load(filename);
\endcode
The first step is to set the proper \ref QLanguageDefinition "language definition" for the
\ref QEditor "editor". This is achieved by a single call to the \ref QLanguageFactory "language factory"
we created earlier. We pass it the filename but a simple suffix or even a language name
would work just as well.
\n\n
At last, we load the content of the file into the editor. The user can now edit it (once the
widget will be displayed of course...)
<table width="100%" border="0" frame="void"><tr width="100%">
<td align="left">\ref license "[Previous:License]"</td>
<td align="right">\ref qce_examples "[Next:Examples]"</td>
</tr></table>
*/
/*!
\page qce_examples Examples
<table width="100%" border="0" frame="void"><tr width="100%">
<td align="left">\ref tutorial "[Previous:Tutorial]"</td>
<td align="right"></td>
</tr></table>
<h2>Sumarry :</h2>
<ol>
<li>\ref exSyntax "Creating a custom syntax file"</li>
</ol>
\section exSyntax Syntax files
Syntax file creation is rather straightforward once you know how they are structured.
The purpose of this small example is to cover that topic as extensively as possible.
<h3>Core concepts</h3>
There are two fundamental notions in QCE syntax files : contexts and "regular" matches.
The concept of context is extremely powerful while remaining extremely simple. The syntax
engine enters a context when a given start token is matched and it leaves it when a stop
token is matched. Within a context there can be any number of contexts and "regular" matches.
contexts are typically used to match comments, strings or other special blocks of code.
"Regular" matches are what one would expect them to be : simple tokens. They can be matched
from either regular expressions or plain strings. Start and stop tokens of context are
"regular" matches in a way, except that they also trigger the context enter/leave event.
<h3>Syntax file structure</h3>
Now, on to the analysis of the structure of a syntax file.
The root element of the document is a &lt;QNFA&gt; tag. It provides various informations
in its attributes.
<ul>
<li><b>language</b> : this attribute specifies the name of the language supported by
the syntax file.</li>
<li><b>extensions</b> : this attribute specifies the file extensions matched by this
language.</li>
<li><b>defaultLineMark</b> : this (optional) attribute specifies the name of the default
line mark to be set on a line when clicking on the line mark panel (if any). If none
is provided, "bookmark" is used.</li>
</ul>
The QNFA tag represents the root context of the language. It can contain any number of the
following tags :
<ul>
<li><b>context</b> : defines a context. To be valid, requires children tags of type
<b>start</b> and <b>stop</b>.</li>
<li><b>sequence</b> : defines a "regular" match. The value of this element is always
assumed to be a regexp (no internal optimizations attempt for plain strings).</li>
<li><b>word</b> : defines a "regular" match. The value of this element is checked to
determine whether it can be matched as a plain string (internal optimizations).
Additionally, this element will ONLY be matched at word boundaries. For instance,
if the value of a word element is for, it will not be matched in "foreach" while
it would have been, if declared using a <b>sequence</b> tag.</li>
<li><b>list</b> : this is a "meta-element" used to group regular matches and give
them the same attributes as they are propagated from the this element to its children.
Subrouping (nesting <b>list</b> elements) is NOT supported.</li>
<li><b>embed</b> : this is a "meta-element" which allows embedding of other languages
or contexts to help reducing duplication of content and make maintenance of syntax
files easier. The embedding target is specified through the <i>target</i> attribute.</li>
</ul>
Additionally, the following tags are valid inside a <b>context</b> block (and, again, their
number isn't limited). Also note that, while ordering of all tags above within a context DO
matter, ordering of the tags below DO NOT matter.
<ul>
<li><b>start</b> : defines a context start token as a "regular" match (remarks made about
the <b>word</b> tag apply to this one as well).</li>
<li><b>stop</b> : defines a context stop token as a "regular" match (remarks made about
the <b>word</b> tag apply to this one as well).</li>
<li><b>escape</b> : defines a special token as a "regular" match (remarks made about
the <b>sequence</b> tag apply to this one as well). This element is used for the
very common case of escape sequences which may prevent a stop token from being one.
In most case it is however recommended to favor explicit escape match through a
<b>sequence</b>, for instance in C-like strings the following construct is used :
\code <sequence id="escape" format="escapeseq" >\\[nrtvf\\"'\n\n]</sequence> \endcode
</li>
</ul>
All these tags, except <b>embed</b>, support the following attributes :
<ul>
<li><b>format</b> : specifies the format to be applied to the matches (highlighting).
This property is propagated.</li>
<li><b>id</b> : assign an identifer to the element. This is only used for contexts
at the moment however and the only "external" use of it occurs in the <b>embed</b>
tag.</li>
</ul>
Additionally all tags, except <b>context</b> and <b>list</b>, support the following
extra attributes :
<ul>
<li><b>exclusive</b> : Indicate that the token may be matched multiple times.
For instance some contexts have the same end token (a newline in many cases)
and the innermost context must not prevent its parenth from matching the newline
and exiting. This attribute is reserved to <b>start</b> and <b>stop</b> tag
of a context. Valid values are "true", "false", "1" or "0".</li>
<li><b>parenthesis</b> : specifies that the element is a parenthesis. The concept
of parenthesis actually extends way beyond simple parentheses. Parentheses are
tokens that may be matched (brace matching), delimit foldable block or trigger
indentation.
The value of this attribute is a string formatted as follows :
"$id:$type[@nomatch]". Where $id is the identifier for the parenthesis
and type is its type, which can be either "open", "close" or "boundary".
Finally the "@nomatch", if present, indicate that the parenthesis should
not be taken into account for brace matching. The square brackets indicate
that it is optional and should not be used in a syntax file.
While the "open" and "close" type of parenthesis are quite easy to understand,
the "boundary" require more details. It indicates a parenthesis that acts as both
"open" and "close". Typical use of such parentheses happen in C++ for visibility
keywords (public, protected, private) or in Latex for chapter tags, section tags
and so on. There are of course many more cases where this type of parenthesis is
the right choice but there is no point in listing them all.</li>
<li><b>fold</b> : element will delimit foldable block(s).
Valid values are "true", "false", "1" or "0".</li>
<li><b>indent</b> : element will trigger indentation.
Valid values are "true", "false", "1" or "0".</li>
</ul>
The <b>context</b> tag however supports the following extra attributes :
<ul>
<li><b>transparency</b> : specifies whether the contexts and matches declared
before this context should also be matched inside that context (with no need
to declare them again). Valid values are "true", "false", "1" or "0".</li>
<li><b>stayOnLine</b> : this attribute is provided to handle special cases
of context nesting where the innermost context may span over several lines
whereas the outer contexts cannot, e.g in C, comments are accepted inside
preprocessor directives. This attribute indicates that no matter what happens
to subcontexts, this context will not span beyond the line it started in.</li>
</ul>
<h3>Regexp format</h3>
The regexp format used by QCE is near to that used by QRegExp but with some slight
variations.
First of all, a list of QRegExp features not supported in syntax files :
<ul>
<li>grouping and alternation (ban parentheses and | from your mind).</li>
<li>Assertions (such as word boundaries)</li>
<li>lookahead operators</li>
<li>'.' to match any character</li>
</ul>
Then, character classes (word, space, digit and their negation) use the same
"specific character" (respectively w, s, d and uppercase) but a different
prefix character ($ instead of \).
C-style escaping is used. Simple C escapes (for newlines and tab) are converted
properly and C-style escaping is used to escape control characters.
Sets and negated sets are supported, using the same syntax as QRegExp.
Regular regexp operator '?', '*' and '+' are supported.
A revision of the syntax format may bring grouping and alternation support (and
possibly other niceties) in a future version but as this would break backward
compat (due to escaping issues among other things) and require a rewrite of the
syntax engine a new (but very similar) syntax file format would be used.
<h3>Getting your hands dirty (coming soon)</h3>
Now that the fundamentals have been covered, let's use them to create a small
syntax file for an imaginary language.
More examples availables in the qxs/ directory where all syntax files reside.
<!--
\section ex2 Completion (coming ?soon?)
More on this topic in a future version.
-->
*/

2
3rdparty/qwindowkit vendored

@ -1 +1 @@
Subproject commit 782a52020a9823bb7dc744ab20849f2558b64652
Subproject commit a1c500e1dd254445e7bc153f4e0f049cabab35a0

View File

@ -87,7 +87,7 @@ option(BUILD_STATIC "Build the static library" TRUE)
add_subdirectory(3rdparty/cpptrace)
add_subdirectory(3rdparty/QHexView)
add_subdirectory(3rdparty/qcodeedit2)
add_subdirectory(3rdparty/WingCodeEdit)
add_subdirectory(3rdparty/Qt-Advanced-Docking-System)
add_subdirectory(3rdparty/AngelScript/sdk/angelscript/projects/cmake)
add_subdirectory(3rdparty/QJsonModel)
@ -173,9 +173,13 @@ set(DIALOG_SRC
src/dialog/historydeldialog.ui
src/dialog/crashreport.h
src/dialog/crashreport.cpp
src/dialog/crashreport.ui)
src/dialog/crashreport.ui
src/dialog/showtextdialog.cpp
src/dialog/aboutsoftwaredialog.h)
set(CONTROL_SRC
src/control/codeedit.h
src/control/codeedit.cpp
src/control/editorview.h
src/control/editorview.cpp
src/control/toast.h
@ -195,11 +199,6 @@ set(CONTROL_SRC
src/control/qtableviewext.cpp
src/control/qlistviewext.h
src/control/qlistviewext.cpp
src/control/qcodecompletionwidget.h
src/control/qcodecompletionwidget_p.h
src/control/qcodecompletionwidget.cpp
src/control/codeedit.h
src/control/codeedit.cpp
src/control/asobjtreewidget.h
src/control/asobjtreewidget.cpp
src/control/qtlonglongspinbox.cpp
@ -254,14 +253,10 @@ set(CLASS_SRC
src/class/ascompletion.h
src/class/asbuilder.h
src/class/asbuilder.cpp
src/class/qdocumentsearch.cpp
src/class/qdocumentsearch.h
src/class/ascontextmgr.h
src/class/ascontextmgr.cpp
src/class/qcodenode.cpp
src/class/qcodenode.h
src/class/langservice.h
src/class/langservice.cpp
src/class/clangformatmanager.h
src/class/clangformatmanager.cpp
src/class/aspreprocesser.h
@ -284,7 +279,8 @@ set(CLASS_SRC
src/class/pluginsystem.h
src/class/pluginsystem.cpp
src/class/inspectqtloghelper.h
src/class/inspectqtloghelper.cpp)
src/class/inspectqtloghelper.cpp
src/class/codeinfotip.h)
set(INTERNAL_PLG_SRC
src/class/wingangelapi.h src/class/wingangelapi.cpp
@ -341,7 +337,10 @@ set(SETTING_SRC
src/settings/othersettingsdialog.ui
src/settings/clangformatsetdialog.h
src/settings/clangformatsetdialog.cpp
src/settings/clangformatsetdialog.ui)
src/settings/clangformatsetdialog.ui
src/settings/qeditconfig.h
src/settings/qeditconfig.cpp
src/settings/qeditconfig.ui)
set(SCRIPT_ADDON_SRC
src/scriptaddon/scriptqstring.h
@ -357,24 +356,6 @@ set(SCRIPT_ADDON_SRC
src/scriptaddon/scriptfile.cpp
src/scriptaddon/scriptfile.h)
set(CODEEDIT_WIDGET
src/qcodeeditwidget/qgotolinepanel.h
src/qcodeeditwidget/qgotolinepanel.cpp
src/qcodeeditwidget/qgotolinepanel.ui
src/qcodeeditwidget/qsearchreplacepanel.h
src/qcodeeditwidget/qsearchreplacepanel.cpp
src/qcodeeditwidget/qsearchreplacepanel.ui
src/qcodeeditwidget/qeditconfig.h
src/qcodeeditwidget/qeditconfig.cpp
src/qcodeeditwidget/qeditconfig.ui
src/qcodeeditwidget/qformatconfig.h
src/qcodeeditwidget/qformatconfig.cpp
src/qcodeeditwidget/qformatconfig.ui
src/qcodeeditwidget/qdocumentswaptextcommand.h
src/qcodeeditwidget/qdocumentswaptextcommand.cpp
src/qcodeeditwidget/formatconfigmodel.h
src/qcodeeditwidget/formatconfigmodel.cpp)
# localization support
file(
GLOB_RECURSE TS_FILES
@ -394,7 +375,6 @@ set(TRANSLATION_PATH
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QConsoleWidget
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QHexView
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QJsonModel
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/qcodeedit2
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/Qt-Advanced-Docking-System/src
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QWingRibbon
${CMAKE_CURRENT_SOURCE_DIR}/src)
@ -471,7 +451,6 @@ set(PROJECT_SOURCES
${SETTING_SRC}
${SCRIPT_ADDON_SRC}
${ANGEL_SCRIPT_ADDON}
${CODEEDIT_WIDGET}
${QM_FILES}
theme/breeze.qrc
resources.qrc)
@ -520,7 +499,7 @@ target_link_libraries(
QtSingleApplication::QtSingleApplication
WingPlugin
QHexView
QCodeEditor2
WingCodeEdit
QJsonModel
angelscript
qtadvanceddocking-qt${QT_VERSION_MAJOR})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

BIN
images/viewtxt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -85,8 +85,6 @@
<file>images/scheme.png</file>
<file>images/script.png</file>
<file>images/scriptdbg/bp.png</file>
<file>images/scriptdbg/bpdis.png</file>
<file>images/scriptdbg/conbp.png</file>
<file>images/scriptdbg/delbp.png</file>
<file>images/scriptdbg/error.png</file>
<file>images/scriptdbg/hitbp.png</file>
@ -108,6 +106,7 @@
<file>images/unover.png</file>
<file>images/unsaved.png</file>
<file>images/update.png</file>
<file>images/viewtxt.png</file>
<file>images/wiki.png</file>
<file>images/win.png</file>
<file>images/workspace.png</file>
@ -119,12 +118,6 @@
<file>src/components.md</file>
<file>src/translist.md</file>
</qresource>
<qresource prefix="/qcodeedit">
<file alias="as.qnfa">src/qxs/as.qnfa</file>
<file alias="as_dark.qxf">src/qxs/as_dark.qxf</file>
<file alias="as_light.qxf">src/qxs/as_light.qxf</file>
<file alias="marks.qxm">src/qxs/marks.qxm</file>
</qresource>
<qresource prefix="/qeditor">
<file alias="copy.png">images/copy.png</file>
<file alias="cut.png">images/cut.png</file>
@ -136,7 +129,6 @@
<file alias="undo.png">images/undo.png</file>
</qresource>
<qresource prefix="/completion">
<file>images/completion/CTvirtuals.png</file>
<file>images/completion/CVKeyword.png</file>
<file>images/completion/CVclass.png</file>
<file>images/completion/CVenum.png</file>
@ -160,4 +152,7 @@
<file>images/completion/CVunion.png</file>
<file>images/completion/classnew.png</file>
</qresource>
<qresource prefix="/WingScript/Angelscript/syntax">
<file alias="angelscript.xml">src/angelscript.xml</file>
</qresource>
</RCC>

164
src/angelscript.xml Normal file
View File

@ -0,0 +1,164 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language>
<language name="AngelScript" section="Sources" version="19" kateversion="5.79" extensions="*.as;*.angelscript" indenter="cstyle" style="C++"
author="wingsummer" license="GPL" priority="99" >
<highlighting>
<list name="keywords">
<item>abstract</item>
<item>and</item>
<item>break</item>
<item>case</item>
<item>cast</item>
<item>catch</item>
<item>class</item>
<item>const</item>
<item>continue</item>
<item>default</item>
<item>delete</item>
<item>do</item>
<item>else</item>
<item>enum</item>
<item>explicit</item>
<item>external</item>
<item>false</item>
<item>final</item>
<item>float</item>
<item>for</item>
<item>from</item>
<item>funcdef</item>
<item>function</item>
<item>get</item>
<item>if</item>
<item>import</item>
<item>in</item>
<item>inout</item>
<item>interface</item>
<item>is</item>
<item>mixin</item>
<item>namespace</item>
<item>not</item>
<item>null</item>
<item>or</item>
<item>out</item>
<item>override</item>
<item>private</item>
<item>property</item>
<item>protected</item>
<item>return</item>
<item>set</item>
<item>shared</item>
<item>super</item>
<item>switch</item>
<item>this</item>
<item>true</item>
<item>try</item>
<item>typedef</item>
<item>while</item>
<item>xor</item>
</list>
<list name="types">
<item>void</item>
<item>bool</item>
<item>uint</item>
<item>uint8</item>
<item>uint16</item>
<item>uint32</item>
<item>uint64</item>
<item>int</item>
<item>double</item>
<item>int8</item>
<item>int16</item>
<item>int32</item>
<item>int64</item>
<item>auto</item>
</list>
<contexts>
<context attribute="Normal Text" lineEndContext="#stay" name="Normal">
<keyword attribute="Keyword" context="#stay" String="keywords"/>
<keyword attribute="Data Type" context="#stay" String="types" />
<Float attribute="Float" context="Float Suffixes"/>
<HlCOct attribute="Octal" context="#stay"/>
<HlCHex attribute="Hex" context="#stay"/>
<Int attribute="Decimal" context="Int Suffixes"/>
<HlCChar attribute="Char" context="#stay"/>
<StringDetect attribute="Text Block" context="TextBlock" String="&quot;&quot;&quot;"/>
<DetectChar attribute="String" context="String" char="&quot;"/>
<Detect2Chars attribute="Comment" context="MatchComment" char="/" char1="/" lookAhead="true"/>
<Detect2Chars attribute="Comment" context="MatchComment" char="/" char1="*" lookAhead="true" />
<DetectChar attribute="Symbol" context="#stay" char="{" beginRegion="block1"/>
<DetectChar attribute="Symbol" context="#stay" char="}" endRegion="block1"/>
<RegExpr attribute="Data Type" context="#stay" String="\bauto(?=\s+\w+)"/>
<RegExpr attribute="Keyword" context="#stay" String="\b(?=\s+(?:class|interface|void)|(?=\s+(?:return|break))|(?:set|get)(?=\s*[;{])|(?=\s*::\s*\w+))"/>
<RegExpr attribute="Function" context="#stay" String="\b[_\w][_\w\d]*(?=[\s]*[(])" />
<DetectChar attribute="Symbol" context="Member" char="."/>
<AnyChar attribute="Symbol" context="#stay" String=":!%&amp;()+,-/*&lt;=&gt;?[]|~^&#59;"/>
<DetectChar attribute="Macro" context="Macro" char="#"/>
</context>
<context name="Float Suffixes" attribute="Float" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
<AnyChar String="dDfFmM" attribute="Float" context="#pop"/>
</context>
<context name="Int Suffixes" attribute="Decimal" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
<StringDetect attribute="Decimal" context="#pop" String="UL" insensitive="true"/>
<StringDetect attribute="Decimal" context="#pop" String="LU" insensitive="true"/>
<AnyChar attribute="Decimal" context="#pop" String="ULul"/>
</context>
<context attribute="String" lineEndContext="#pop" name="String">
<DetectChar context="StringEscapedChar" char="\" lookAhead="1"/>
<DetectChar attribute="String" context="#pop" char="&quot;"/>
</context>
<context attribute="String" lineEndContext="#pop" name="StringEscapedChar">
<HlCStringChar attribute="String Char" context="#pop"/>
<RegExpr attribute="String Char" context="#pop" String="\\u+[0-9a-fA-F]{4}"/>
<RegExpr attribute="Error" context="#pop" String="\\(u+[0-9a-fA-F]*|.)?"/>
</context>
<context attribute="Text Block" lineEndContext="#stay" name="TextBlock">
<DetectChar context="StringEscapedChar" char="\" lookAhead="1"/>
<StringDetect attribute="Text Block" context="#pop" String="&quot;&quot;&quot;"/>
</context>
<context attribute="Normal Text" lineEndContext="#pop" name="Member" fallthrough="true" fallthroughContext="#pop">
<RegExpr attribute="Function" context="#pop" String="\b[_\w][_\w\d]*(?=[\s]*)" />
</context>
<context attribute="Comment" lineEndContext="#pop" name="Commentar 1">
<IncludeRules context="##Comments"/>
</context>
<context attribute="Comment" lineEndContext="#stay" name="Commentar 2">
<Detect2Chars attribute="Comment" context="#pop" char="*" char1="/" endRegion="BlockComment"/>
<IncludeRules context="##Comments"/>
</context>
<context name="MatchComment" attribute="Normal Text" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
<IncludeRules context="##Doxygen" />
<Detect2Chars attribute="Comment" context="#pop!Commentar 1" char="/" char1="/" />
<Detect2Chars attribute="Comment" context="#pop!Commentar 2" char="/" char1="*" beginRegion="BlockComment" />
</context>
<context attribute="Decimal" lineEndContext="#pop" name="Decimal"/>
<context attribute="Macro" lineEndContext="#pop" name="Macro">
<Detect2Chars attribute="Comment" context="LineComment" char="/" char1="/"/>
<Detect2Chars attribute="Comment" context="BlockComment" char="/" char1="*" beginRegion="Comment"/>
</context>
</contexts>
<itemDatas>
<itemData name="Normal Text" defStyleNum="dsNormal"/>
<itemData name="Keyword" defStyleNum="dsKeyword"/>
<itemData name="Function" defStyleNum="dsFunction"/>
<itemData name="Data Type" defStyleNum="dsDataType"/>
<itemData name="Decimal" defStyleNum="dsDecVal"/>
<itemData name="Octal" defStyleNum="dsBaseN"/>
<itemData name="Hex" defStyleNum="dsBaseN"/>
<itemData name="Float" defStyleNum="dsFloat"/>
<itemData name="Char" defStyleNum="dsChar"/>
<itemData name="String" defStyleNum="dsString"/>
<itemData name="Text Block" defStyleNum="dsString"/>
<itemData name="String Char" defStyleNum="dsSpecialChar"/>
<itemData name="Comment" defStyleNum="dsComment"/>
<itemData name="Symbol" defStyleNum="dsOperator"/>
<itemData name="Macro" defStyleNum="dsPreprocessor"/>
</itemDatas>
</highlighting>
<general>
<comments>
<comment name="singleLine" start="//" position="afterwhitespace"/>
<comment name="multiLine" start="/*" end="*/" region="BlockComment" />
</comments>
<keywords casesensitive="1" />
</general>
</language>

View File

@ -29,8 +29,8 @@ QString AngelObjString::stringToString(void *obj, asDebugger *dbg) {
Q_UNUSED(dbg);
// We know the received object is a string
QString *val = reinterpret_cast<QString *>(obj);
return *val;
QString val = *reinterpret_cast<QString *>(obj);
return val;
}
QString AngelObjString::arrayToString(void *obj, asDebugger *dbg) {

View File

@ -37,6 +37,8 @@
#include "utilities.h"
#include "wingmessagebox.h"
#include <KSyntaxHighlighting/Repository>
AppManager *AppManager::_instance = nullptr;
AppManager::AppManager(int &argc, char *argv[])
@ -81,6 +83,10 @@ AppManager::AppManager(int &argc, char *argv[])
SkinManager::instance();
// add angelscript highlight support
auto &repo = WingCodeEdit::syntaxRepo();
repo.addCustomSearchPath(QStringLiteral(":/WingScript/Angelscript"));
auto dontSplash = set.dontUseSplash();
SplashDialog *splash = nullptr;
@ -136,7 +142,7 @@ AppManager::AppManager(int &argc, char *argv[])
AppManager::~AppManager() {
InspectQtLogHelper::instance().destory();
ClangFormatManager::instance().save();
CommandHistoryManager::save(QConsoleWidget::history().strings_);
// CommandHistoryManager::save(QConsoleWidget::history().strings_);
_w->deleteLater();
_w = nullptr;

View File

@ -18,8 +18,6 @@
#include "ascompletion.h"
#include "qasparser.h"
#include "qdocumentcursor.h"
#include "qdocumentline.h"
#include <QDir>
#include <QLibraryInfo>
@ -29,340 +27,301 @@
#include <QTimer>
#include <QtDebug>
#include "control/qcodecompletionwidget.h"
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, DOT_TRIGGER, ("."))
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, DBL_COLON_TRIGGER, ("::"))
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, LEFT_PARE_TRIGGER, ("("))
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, SEMI_COLON_TRIGGER, (";"))
AsCompletion::AsCompletion(asIScriptEngine *engine, QObject *p)
: QCodeCompletionEngine(p), parser(engine), _engine(engine),
pPopup(new QCodeCompletionWidget()) {
AsCompletion::AsCompletion(asIScriptEngine *engine, WingCodeEdit *p)
: WingCompleter(p), parser(engine), _engine(engine) {
Q_ASSERT(engine);
addTrigger(*DOT_TRIGGER);
addTrigger(*DBL_COLON_TRIGGER);
// unleash the power of call tips
addTrigger(*LEFT_PARE_TRIGGER);
// clear the tips
addTrigger(*SEMI_COLON_TRIGGER);
setTrigWordLen(3);
setTriggerList({*DOT_TRIGGER, *DBL_COLON_TRIGGER,
// unleash the power of call tips
*LEFT_PARE_TRIGGER,
// clear the tips
*SEMI_COLON_TRIGGER});
setTriggerAmount(3);
}
AsCompletion::~AsCompletion() {}
QCodeCompletionEngine *AsCompletion::clone() {
AsCompletion *e = new AsCompletion(_engine, pPopup->editor());
// void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger)
// {
// auto txt = c.line().text();
// if (txt.isEmpty()) {
// emit onFunctionTip(this, {});
// return;
// }
for (auto &t : triggers())
e->addTrigger(t);
// if (trigger == *SEMI_COLON_TRIGGER) {
// emit onFunctionTip(this, {});
// return;
// }
connect(e, &AsCompletion::onFunctionTip, this,
&AsCompletion::onFunctionTip);
// auto off = 0;
// auto offcur = c.document()->property("console");
// if (!offcur.isNull() && offcur.isValid()) {
// auto cur = offcur.value<QDocumentCursor>();
// if (cur.isValid()) {
// off = cur.columnNumber();
// }
// } else {
// // TODO: PRs are welcomed !!!
// // If this software is well-known or brings me lots of
// // financial support, I will implement it myself.
emit cloned(e);
// // parse current code
// // auto codes = c.document()->text(true, false);
// // parser.parse(codes, this->editor()->fileName());
return e;
}
// // QList<QCodeNode *> nodes = parser.codeNodes();
// }
QString AsCompletion::language() const { return QStringLiteral("AngelScript"); }
// auto code = txt.mid(off, c.columnNumber() - off).toUtf8();
// auto len = code.length();
QStringList AsCompletion::extensions() const {
QStringList l;
// QList<QCodeNode *> nodes;
l << "as"
<< "angelscript";
// if (len < trigWordLen() && trigger != *DOT_TRIGGER) {
// emit onFunctionTip(this, {});
// pPopup->hide();
// return;
// }
return l;
}
// auto p = code.data();
// auto end = p + len;
void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger) {
auto txt = c.line().text();
if (txt.isEmpty()) {
emit onFunctionTip(this, {});
return;
}
// struct Token {
// qsizetype pos;
// asETokenClass type;
// QByteArray content;
// };
if (trigger == *SEMI_COLON_TRIGGER) {
emit onFunctionTip(this, {});
return;
}
// // parse the tokens
// QVector<Token> tokens;
// qsizetype pos = 0;
// for (; p < end;) {
// asUINT tokenLen = 0;
// auto tt = _engine->ParseToken(p, len, &tokenLen);
// if (tt == asTC_WHITESPACE) {
// p += tokenLen;
// pos += tokenLen;
// continue;
// }
// Token token;
// token.pos = pos;
// token.type = tt;
// token.content = QByteArray(p, tokenLen);
// tokens << token;
// p += tokenLen;
// pos += tokenLen;
// }
auto off = 0;
auto offcur = c.document()->property("console");
if (!offcur.isNull() && offcur.isValid()) {
auto cur = offcur.value<QDocumentCursor>();
if (cur.isValid()) {
off = cur.columnNumber();
}
} else {
// TODO: PRs are welcomed !!!
// If this software is well-known or brings me lots of
// financial support, I will implement it myself.
// auto getNamespace = [](const QVector<Token> &tokens) -> QByteArrayList {
// auto rbegin = tokens.rbegin();
// auto rend = tokens.rend();
// parse current code
// auto codes = c.document()->text(true, false);
// parser.parse(codes, this->editor()->fileName());
// QByteArrayList nss;
// bool semiFlag = true;
// auto p = rbegin;
// for (; p != rend; ++p) {
// if (semiFlag) {
// if (p->type != asTC_IDENTIFIER) {
// break;
// } else {
// nss.prepend(p->content);
// semiFlag = false;
// }
// } else {
// if (p->content != *DBL_COLON_TRIGGER) {
// break;
// }
// semiFlag = true;
// }
// }
// return nss;
// };
// QList<QCodeNode *> nodes = parser.codeNodes();
}
// QByteArray fn;
auto code = txt.mid(off, c.columnNumber() - off).toUtf8();
auto len = code.length();
// QFlags<QCodeCompletionWidget::FilterFlag> filter(
// QCodeCompletionWidget::FilterFlag::Public |
// QCodeCompletionWidget::FilterFlag::KeepAllFunctions |
// QCodeCompletionWidget::FilterFlag::KeepAllSub);
QList<QCodeNode *> nodes;
// if (tokens.isEmpty()) {
// pPopup->hide();
// return;
// }
if (len < trigWordLen() && trigger != *DOT_TRIGGER) {
emit onFunctionTip(this, {});
pPopup->hide();
return;
}
// QString prefix;
// auto etoken = tokens.back();
auto p = code.data();
auto end = p + len;
// // if trigger is empty, it's making editing
// if (trigger.isEmpty()) {
// // it can not be any trigger, so take the last as prefix
// prefix = etoken.content;
// tokens.removeLast();
// if (tokens.isEmpty()) {
// applyEmptyNsNode(nodes);
// } else {
// etoken = tokens.back(); // checking later
// }
// }
struct Token {
qsizetype pos;
asETokenClass type;
QByteArray content;
};
// if (nodes.isEmpty()) {
// if (etoken.type == asTC_KEYWORD) {
// // only support these
// auto cur = c;
// cur.setColumnNumber(off + etoken.pos);
// if (etoken.content == *DBL_COLON_TRIGGER) {
// complete(cur, *DBL_COLON_TRIGGER);
// pPopup->setCursor(c);
// pPopup->setPrefix(prefix);
// return;
// } else if (etoken.content == *DOT_TRIGGER) {
// complete(cur, *DOT_TRIGGER);
// pPopup->setCursor(c);
// pPopup->setPrefix(prefix);
// return;
// } else {
// applyEmptyNsNode(nodes);
// }
// } else if (etoken.type != asTC_IDENTIFIER) {
// pPopup->hide();
// return;
// }
// parse the tokens
QVector<Token> tokens;
qsizetype pos = 0;
for (; p < end;) {
asUINT tokenLen = 0;
auto tt = _engine->ParseToken(p, len, &tokenLen);
if (tt == asTC_WHITESPACE) {
p += tokenLen;
pos += tokenLen;
continue;
}
Token token;
token.pos = pos;
token.type = tt;
token.content = QByteArray(p, tokenLen);
tokens << token;
p += tokenLen;
pos += tokenLen;
}
// if (trigger == *DOT_TRIGGER) {
// nodes = parser.classNodes();
// } else if (etoken.content.length() >= trigWordLen()) {
// // completion for a.b.c or a::b.c or a::b::c.d or ::a::b.c
// if (trigger == *DBL_COLON_TRIGGER) {
// auto ns = getNamespace(tokens);
// auto idx = tokens.length() - ns.length() * 2;
// if (idx >= 0) {
// if (tokens.at(idx).content == *DOT_TRIGGER) {
// pPopup->hide();
// return;
// }
// }
// nodes = lookupNamespace(ns);
// if (nodes.isEmpty()) {
// return;
// }
// } else if (trigger == *LEFT_PARE_TRIGGER) {
// // the first is function name, an identifier
// fn = etoken.content;
// tokens.removeLast();
// if (!tokens.isEmpty()) {
// if (tokens.back().content == *DBL_COLON_TRIGGER) {
// tokens.removeLast();
// }
// }
// auto ns = getNamespace(tokens);
// auto idx = tokens.length() - ns.length() * 2 + 1;
// if (idx >= 0 && idx < tokens.length()) {
// if (tokens.at(idx).content == *DOT_TRIGGER) {
// pPopup->hide();
// return;
// }
// }
// nodes = lookupNamespace(ns);
// if (nodes.isEmpty()) {
// applyEmptyNsNode(nodes);
// }
// QString tip;
// for (auto &n : nodes) {
// for (auto &f : n->children()) {
// if (f->type() != QCodeNode::Function ||
// f->role(QCodeNode::Name) != fn) {
// continue;
// }
auto getNamespace = [](const QVector<Token> &tokens) -> QByteArrayList {
auto rbegin = tokens.rbegin();
auto rend = tokens.rend();
// tip = QString::fromUtf8(f->role(QCodeNode::Return)) +
// QLatin1Char(' ') +
// QString::fromUtf8(f->role(QCodeNode::Name)) +
// QString::fromUtf8(f->role(QCodeNode::Arguments))
// .prepend('(')
// .append(')');
// break;
// }
// if (!tip.isEmpty()) {
// break;
// }
// }
QByteArrayList nss;
bool semiFlag = true;
auto p = rbegin;
for (; p != rend; ++p) {
if (semiFlag) {
if (p->type != asTC_IDENTIFIER) {
break;
} else {
nss.prepend(p->content);
semiFlag = false;
}
} else {
if (p->content != *DBL_COLON_TRIGGER) {
break;
}
semiFlag = true;
}
}
return nss;
};
// emit onFunctionTip(this, tip);
// }
// }
// }
QByteArray fn;
// auto cur = c;
// cur.movePosition(trigger.length());
// pPopup->setCursor(cur);
// pPopup->setPrefix(prefix);
// pPopup->setFilter(filter);
// pPopup->setCompletions(nodes);
QFlags<QCodeCompletionWidget::FilterFlag> filter(
QCodeCompletionWidget::FilterFlag::Public |
QCodeCompletionWidget::FilterFlag::KeepAllFunctions |
QCodeCompletionWidget::FilterFlag::KeepAllSub);
if (tokens.isEmpty()) {
pPopup->hide();
return;
}
QString prefix;
auto etoken = tokens.back();
// if trigger is empty, it's making editing
if (trigger.isEmpty()) {
// it can not be any trigger, so take the last as prefix
prefix = etoken.content;
tokens.removeLast();
if (tokens.isEmpty()) {
applyEmptyNsNode(nodes);
} else {
etoken = tokens.back(); // checking later
}
}
if (nodes.isEmpty()) {
if (etoken.type == asTC_KEYWORD) {
// only support these
auto cur = c;
cur.setColumnNumber(off + etoken.pos);
if (etoken.content == *DBL_COLON_TRIGGER) {
complete(cur, *DBL_COLON_TRIGGER);
pPopup->setCursor(c);
pPopup->setPrefix(prefix);
return;
} else if (etoken.content == *DOT_TRIGGER) {
complete(cur, *DOT_TRIGGER);
pPopup->setCursor(c);
pPopup->setPrefix(prefix);
return;
} else {
applyEmptyNsNode(nodes);
}
} else if (etoken.type != asTC_IDENTIFIER) {
pPopup->hide();
return;
}
if (trigger == *DOT_TRIGGER) {
nodes = parser.classNodes();
} else if (etoken.content.length() >= trigWordLen()) {
// completion for a.b.c or a::b.c or a::b::c.d or ::a::b.c
if (trigger == *DBL_COLON_TRIGGER) {
auto ns = getNamespace(tokens);
auto idx = tokens.length() - ns.length() * 2;
if (idx >= 0) {
if (tokens.at(idx).content == *DOT_TRIGGER) {
pPopup->hide();
return;
}
}
nodes = lookupNamespace(ns);
if (nodes.isEmpty()) {
return;
}
} else if (trigger == *LEFT_PARE_TRIGGER) {
// the first is function name, an identifier
fn = etoken.content;
tokens.removeLast();
if (!tokens.isEmpty()) {
if (tokens.back().content == *DBL_COLON_TRIGGER) {
tokens.removeLast();
}
}
auto ns = getNamespace(tokens);
auto idx = tokens.length() - ns.length() * 2 + 1;
if (idx >= 0 && idx < tokens.length()) {
if (tokens.at(idx).content == *DOT_TRIGGER) {
pPopup->hide();
return;
}
}
nodes = lookupNamespace(ns);
if (nodes.isEmpty()) {
applyEmptyNsNode(nodes);
}
QString tip;
for (auto &n : nodes) {
for (auto &f : n->children()) {
if (f->type() != QCodeNode::Function ||
f->role(QCodeNode::Name) != fn) {
continue;
}
tip = QString::fromUtf8(f->role(QCodeNode::Return)) +
QLatin1Char(' ') +
QString::fromUtf8(f->role(QCodeNode::Name)) +
QString::fromUtf8(f->role(QCodeNode::Arguments))
.prepend('(')
.append(')');
break;
}
if (!tip.isEmpty()) {
break;
}
}
emit onFunctionTip(this, tip);
}
}
}
auto cur = c;
cur.movePosition(trigger.length());
pPopup->setCursor(cur);
pPopup->setPrefix(prefix);
pPopup->setFilter(filter);
pPopup->setCompletions(nodes);
if (!pPopup->isCompleting()) {
pPopup->popup();
}
}
void AsCompletion::applyEmptyNsNode(QList<QCodeNode *> &nodes) {
if (_emptyNsNodes.isEmpty()) {
for (auto &n : parser.headerNodes()) {
auto name = n->qualifiedName();
if (name.isEmpty()) {
// only one group for empty namespace
_emptyNsNodes << n;
break;
}
}
_emptyNsNodes.append(parser.keywordNode());
}
nodes = _emptyNsNodes;
}
// void AsCompletion::parse(const QDocumentCursor &c) {
// auto codes = c.document()->text();
// // asBuilder builder;
// if (!pPopup->isCompleting()) {
// pPopup->popup();
// }
// }
QList<QCodeNode *> AsCompletion::lookupNamespace(const QByteArrayList &ns) {
QList<QCodeNode *> nodes;
// void AsCompletion::applyEmptyNsNode(QList<QCodeNode *> &nodes) {
// if (_emptyNsNodes.isEmpty()) {
// for (auto &n : parser.headerNodes()) {
// auto name = n->qualifiedName();
// if (name.isEmpty()) {
// // only one group for empty namespace
// _emptyNsNodes << n;
// break;
// }
// }
// _emptyNsNodes.append(parser.keywordNode());
// }
if (ns.isEmpty()) {
return nodes;
}
// nodes = _emptyNsNodes;
// }
auto headers = parser.headerNodes();
auto r =
std::find_if(headers.begin(), headers.end(), [&ns](QCodeNode *node) {
return node->role(QCodeNode::Name) == ns.first();
});
if (r != headers.end()) {
auto n = *r;
auto len = ns.size();
// // void AsCompletion::parse(const QDocumentCursor &c) {
// // auto codes = c.document()->text();
// // // asBuilder builder;
// // }
bool found = true;
for (qsizetype i = 1; i < len; ++i) {
auto &c = n->children();
r = std::find_if(c.begin(), c.end(), [&ns, i](QCodeNode *node) {
return node->role(QCodeNode::Name) == ns.at(i);
});
if (r == c.end()) {
found = false;
break;
}
}
// QList<QCodeNode *> AsCompletion::lookupNamespace(const QByteArrayList &ns) {
// QList<QCodeNode *> nodes;
if (found) {
nodes.append(*r);
}
}
// if (ns.isEmpty()) {
// return nodes;
// }
return nodes;
}
// auto headers = parser.headerNodes();
// auto r =
// std::find_if(headers.begin(), headers.end(), [&ns](QCodeNode *node) {
// return node->role(QCodeNode::Name) == ns.first();
// });
// if (r != headers.end()) {
// auto n = *r;
// auto len = ns.size();
QCodeCompletionWidget *AsCompletion::codeCompletionWidget() const {
return pPopup;
}
// bool found = true;
// for (qsizetype i = 1; i < len; ++i) {
// auto &c = n->children();
// r = std::find_if(c.begin(), c.end(), [&ns, i](QCodeNode *node) {
// return node->role(QCodeNode::Name) == ns.at(i);
// });
// if (r == c.end()) {
// found = false;
// break;
// }
// }
void AsCompletion::setEditor(QEditor *e) {
QCodeCompletionEngine::setEditor(e);
pPopup->setEditor(e);
}
// if (found) {
// nodes.append(*r);
// }
// }
// return nodes;
// }

View File

@ -18,35 +18,19 @@
#ifndef _AS_COMPLETION_H_
#define _AS_COMPLETION_H_
#include "WingCodeEdit/wingcompleter.h"
#include "class/qasparser.h"
#include "qcodecompletionengine.h"
class QCodeCompletionWidget;
class AsCompletion : public QCodeCompletionEngine {
class AsCompletion : public WingCompleter {
Q_OBJECT
public:
explicit AsCompletion(asIScriptEngine *engine, QObject *p = nullptr);
explicit AsCompletion(asIScriptEngine *engine, WingCodeEdit *p);
virtual ~AsCompletion();
virtual QCodeCompletionEngine *clone() override;
virtual QString language() const override;
virtual QStringList extensions() const override;
virtual void setEditor(QEditor *e) override;
QCodeCompletionWidget *codeCompletionWidget() const;
signals:
void onFunctionTip(AsCompletion *cp, const QString &content);
protected:
virtual void complete(const QDocumentCursor &c,
const QString &trigger) override;
private:
void applyEmptyNsNode(QList<QCodeNode *> &nodes);
@ -57,7 +41,6 @@ private:
private:
QAsParser parser;
asIScriptEngine *_engine;
QCodeCompletionWidget *pPopup;
QList<QCodeNode *> _emptyNsNodes;
};

35
src/class/codeinfotip.h Normal file
View File

@ -0,0 +1,35 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#ifndef CODEINFOTIP_H
#define CODEINFOTIP_H
#include <QString>
class CodeInfoTip {
public:
enum class Type { Class, Function, Enum, Variable };
public:
QString name;
Type type;
QString nameSpace;
QString args; // only function use
};
#endif // CODEINFOTIP_H

View File

@ -1,107 +0,0 @@
#include "langservice.h"
#include "class/ascompletion.h"
#include "class/skinmanager.h"
#include "qdocument.h"
#include "qeditor.h"
#include "qformat.h"
#include "qformatscheme.h"
#include "utilities.h"
LangService &LangService::instance() {
static LangService ins;
return ins;
}
void LangService::init(ScriptingConsole *console) {
QFormatScheme *format = nullptr;
switch (SkinManager::instance().currentTheme()) {
case SkinManager::Theme::Dark:
format =
new QFormatScheme(QStringLiteral(":/qcodeedit/as_dark.qxf"), this);
break;
case SkinManager::Theme::Light:
format =
new QFormatScheme(QStringLiteral(":/qcodeedit/as_light.qxf"), this);
break;
}
addAdditionalFormat(format);
QDocument::setDefaultFormatScheme(format);
_formatSchemes.insert(defaultSchemeName(), format);
m_language = new QLanguageFactory(format, this);
m_language->addDefinitionPath(QStringLiteral(":/qcodeedit"));
auto engine = console->machine()->engine();
_completion = new AsCompletion(engine, this);
connect(_completion, &AsCompletion::onFunctionTip, this,
[this, console](AsCompletion *cp, const QString &fn) {
QString header;
if (!fn.isEmpty()) {
header = QStringLiteral("<font color=\"gold\">") +
tr("AutoComplete:") + QStringLiteral("</font>");
}
auto editor = cp->editor();
if (editor == console) {
emit onConsoleTip(header + QStringLiteral("<b>") + fn +
QStringLiteral("</b>"));
} else {
emit onScriptEditorTip(header + QStringLiteral("<b>") + fn +
QStringLiteral("</b>"));
}
});
m_language->addCompletionEngine(_completion);
initAdditionalFormatScheme();
}
LangService::LangService() : QObject(nullptr) {}
LangService::~LangService() { qDeleteAll(_formatSchemes); }
void LangService::initAdditionalFormatScheme() {
QDir appDataDir(Utilities::getAppDataPath());
const auto dirName = QStringLiteral("scheme");
appDataDir.mkdir(dirName);
if (appDataDir.exists(dirName)) {
appDataDir.cd(dirName);
for (auto &sch :
appDataDir.entryInfoList({QStringLiteral("*.qxf")}, QDir::Files)) {
auto fmt = new QFormatScheme(sch.absoluteFilePath());
if (fmt->formatCount()) {
addAdditionalFormat(fmt);
_formatSchemes.insert(sch.baseName(), fmt);
} else {
delete fmt;
}
}
}
}
QHash<QString, QFormatScheme *> LangService::formatSchemes() const {
return _formatSchemes;
}
const QString LangService::defaultSchemeName() const { return tr("Default"); }
void LangService::addAdditionalFormat(QFormatScheme *scheme) {
if (scheme) {
QFormat fmt;
fmt.foreground = Qt::red;
scheme->setFormat(QStringLiteral("stderr"), fmt);
fmt.foreground = QColorConstants::Svg::gold;
scheme->setFormat(QStringLiteral("stdwarn"), fmt);
fmt.foreground = Qt::green;
scheme->setFormat(QStringLiteral("stdout"), fmt);
}
}
QLanguageFactory *LangService::languageFactory() const { return m_language; }
void LangService::applyLanguageSerivce(QEditor *editor) {
Q_ASSERT(editor);
m_language->setLanguage(editor, QStringLiteral("AngelScript"));
}

View File

@ -1,49 +0,0 @@
#ifndef LANGSERVICE_H
#define LANGSERVICE_H
#include "class/ascompletion.h"
#include "control/scriptingconsole.h"
#include "qlanguagefactory.h"
#include <QObject>
class LangService : public QObject {
Q_OBJECT
public:
static LangService &instance();
void init(ScriptingConsole *console);
QLanguageFactory *languageFactory() const;
void applyLanguageSerivce(QEditor *editor);
static void addAdditionalFormat(QFormatScheme *scheme);
QHash<QString, QFormatScheme *> formatSchemes() const;
const QString defaultSchemeName() const;
signals:
void onConsoleTip(const QString &tip);
void onScriptEditorTip(const QString &tip);
private:
LangService();
~LangService();
private:
void initAdditionalFormatScheme();
private:
QLanguageFactory *m_language = nullptr;
AsCompletion *_completion = nullptr;
QHash<QString, QFormatScheme *> _formatSchemes;
Q_DISABLE_COPY_MOVE(LangService)
};
#endif // LANGSERVICE_H

View File

@ -1,587 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
/*!
\file qdocumentsearch.cpp
\brief Implementation of QDocumentSearch
*/
#include "qdocumentsearch.h"
/*!
\ingroup document
@{
*/
#include "qdocument.h"
#include "qdocument_p.h"
#include "qdocumentline.h"
#include "qeditor.h"
#include "qformatscheme.h"
#include "wingmessagebox.h"
/*!
\class QDocumentSearch
\brief An helper class to perform search in document
QDocumentSearch offer means to perform complex search in documents.
*/
QDocumentSearch::QDocumentSearch(QEditor *e, const QString &f, Options opt,
const QString &r)
: m_group(-1), m_option(opt), m_string(f), m_replace(r), m_editor(e) {}
QDocumentSearch::~QDocumentSearch() { clearMatches(); }
QDocumentSearch::Options QDocumentSearch::options() const { return m_option; }
/*!
\brief Position of the current match among the indexed matches
*/
int QDocumentSearch::currentMatchIndex() const {
return m_highlight.count() ? m_index : -1;
}
/*!
\brief Number of availables indexed matches
Indexed matches are only available when the whole scope is searched,
i.e when either the HighlightAll option is set to true or when next()
is called with the all parameter set to true.
*/
int QDocumentSearch::indexedMatchCount() const { return m_highlight.count(); }
/*!
\return A cursor pointing to the n-th index match
\param idx index of the match to lookup
The cursor returned, if valid, delimits the match through its selection.
*/
QDocumentCursor QDocumentSearch::match(int idx) const {
return idx >= 0 && idx < m_highlight.count() ? m_highlight.at(idx)
: QDocumentCursor();
}
/*!
\brief Clear matches
This function should be called anytime you perform a search with the
HighlightAll option, once you're done iterating over the matches.
*/
void QDocumentSearch::clearMatches() {
if (!m_editor || !m_editor->document())
return;
// qDebug("clearing matches");
m_cursor = QDocumentCursor();
if (m_group != -1) {
m_editor->document()->clearMatches(m_group);
m_editor->document()->flushMatches(m_group);
m_group = -1;
}
m_highlight.clear();
}
/*!
\return The search pattern
*/
QString QDocumentSearch::searchText() const { return m_string; }
/*!
\brief Set the search pattern
*/
void QDocumentSearch::setSearchText(const QString &f) {
m_string = f;
clearMatches();
}
/*!
\brief Test whether a given option is enabled
*/
bool QDocumentSearch::hasOption(Option opt) const { return m_option & opt; }
/*!
\brief Set a search option
\param opt option to set
\param on whether to enable the option
*/
void QDocumentSearch::setOption(Option opt, bool on) {
if (on)
m_option |= opt;
else
m_option &= ~opt;
if ((opt & QDocumentSearch::HighlightAll) && m_highlight.count()) {
QDocument *d = m_editor->document();
if (m_group != -1 && !on) {
d->clearMatches(m_group);
d->flushMatches(m_group);
m_group = -1;
} else if (m_group == -1 && on) {
m_group = d->getNextGroupId();
QFormatScheme *f = d->formatScheme();
if (!f)
f = QDocument::formatFactory();
if (!f) {
qWarning("No format scheme set to the document and no global "
"default one available.\n"
"-> highlighting of search matches disabled.");
return;
}
int sid = f->id("search");
foreach (const QDocumentCursor &c, m_highlight) {
// QFormatRange r(c.anchorColumnNumber(), c.columnNumber() -
// c.anchorColumnNumber(), sid);
d->addMatch(m_group, c.lineNumber(), c.anchorColumnNumber(),
c.columnNumber() - c.anchorColumnNumber(), sid);
}
// qDebug("%i matches in group %i", indexedMatchCount(), m_group);
d->flushMatches(m_group);
}
} else if ((m_option & QDocumentSearch::HighlightAll) &&
((opt & QDocumentSearch::RegExp) ||
(opt & QDocumentSearch::WholeWords) ||
(opt & QDocumentSearch::CaseSensitive))) {
// matches may have become invalid : update them
clearMatches();
next(false);
}
}
/*!
\return the replacement text
*/
QString QDocumentSearch::replaceText() const { return m_replace; }
/*!
\brief Set the replacement text
*/
void QDocumentSearch::setReplaceText(const QString &r) {
m_replace = r;
clearMatches();
}
/*!
\return The current cursor position
This is useful to examine matches after performing a search.
*/
QDocumentCursor QDocumentSearch::origin() const { return m_origin; }
/*!
\brief Set the cursor
If the related option is set, search will start from that cursor
position
This also changes the cursor()
*/
void QDocumentSearch::setOrigin(const QDocumentCursor &c) {
m_cursor = QDocumentCursor();
if (c == m_origin)
return;
m_origin = c;
clearMatches();
}
/*!
\return The current cursor position
This is useful to examine matches after performing a search.
*/
QDocumentCursor QDocumentSearch::cursor() const { return m_cursor; }
/*!
\brief Set the cursor
If the related option is set, search will start from that cursor
position
*/
void QDocumentSearch::setCursor(const QDocumentCursor &c) { m_cursor = c; }
/*!
\return The scope of the search
An invalid cursor indicate that the scope is the whole document,
otherwise the scope is the selection of the returned cursor.
*/
QDocumentCursor QDocumentSearch::scope() const { return m_scope; }
/*!
\brief Set the search scope
If the given cursor has no selection (a fortiori if it is invalid) then
the scope is the whole document.
*/
void QDocumentSearch::setScope(const QDocumentCursor &c) {
if (c == m_scope)
return;
if (c.hasSelection())
m_scope = c;
else
m_scope = QDocumentCursor();
clearMatches();
}
/*!
\brief Test whether the end of the search scope has been reached
*/
bool QDocumentSearch::end(bool backward) const {
bool absEnd = backward ? m_cursor.atStart() : m_cursor.atEnd();
if (m_scope.isValid() && m_scope.hasSelection()) {
absEnd |= !m_scope.isWithinSelection(m_cursor);
/*
qDebug(
"(%i, %i, %i) %s in {(%i, %i), (%i, %i)}",
m_cursor.lineNumber(),
m_cursor.anchorColumnNumber(),
m_cursor.columnNumber(),
absEnd ? "is not" : "is",
m_scope.selectionStart().lineNumber(),
m_scope.selectionStart().columnNumber(),
m_scope.selectionEnd().lineNumber(),
m_scope.selectionEnd().columnNumber()
);
*/
}
return absEnd;
}
/*!
\brief Perform a search
\param backward whether to go backward or forward
\param all if true, the whole document will be searched first, all
matches recorded and available for further navigation
\note Technically speaking the all parameter make search behave
similarly to the HighlightAll option, except that the former option does not
alter the formatting of the document.
*/
void QDocumentSearch::next(bool backward, bool all) {
if (m_string.isEmpty())
return;
if (!hasOption(Replace) && (all || hasOption(HighlightAll)) &&
m_highlight.count()) {
if (!backward)
++m_index;
// m_index = m_index + (backward ? -1 : 1);
if ((m_index < 0 || m_index >= m_highlight.count())) {
if (hasOption(Silent)) {
m_cursor = QDocumentCursor();
return;
}
int ret = WingMessageBox::question(
m_editor, tr("Failure"),
tr("End of matches reached.\n"
"Restart from the begining ?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (ret == QMessageBox::Yes) {
m_index = backward ? m_highlight.count() : 0;
--m_index;
next(backward);
return;
}
} else {
m_cursor = m_highlight.at(m_index);
if (m_editor && !hasOption(Silent))
m_editor->setCursor(m_cursor);
}
if (backward)
--m_index;
return;
}
if (m_cursor.isNull()) {
m_cursor = m_origin;
}
if (m_cursor.isNull()) {
if (m_scope.isValid() && m_scope.hasSelection()) {
if (backward)
m_cursor = m_scope.selectionEnd();
else
m_cursor = m_scope.selectionStart();
} else if (m_editor) {
m_cursor = QDocumentCursor(m_editor->document());
if (backward)
m_cursor.movePosition(1, QDocumentCursor::End);
} else {
WingMessageBox::warning(nullptr, qAppName(),
tr("Unable to perform search operation"));
}
}
/*
qDebug(
"searching %s from line %i (column %i)",
backward ? "backward" : "forward",
m_cursor.lineNumber(),
m_cursor.columnNumber()
);
*/
m_index = 0;
QRegularExpression m_regexp;
if (hasOption(RegExp)) {
m_regexp = QRegularExpression(m_string);
if (hasOption(CaseSensitive)) {
m_regexp.setPatternOptions(
QRegularExpression::CaseInsensitiveOption);
}
} else if (hasOption(WholeWords)) {
m_regexp =
QRegularExpression(QStringLiteral("\\b%1\\b")
.arg(QRegularExpression::escape(m_string)));
if (hasOption(CaseSensitive)) {
m_regexp.setPatternOptions(
QRegularExpression::CaseInsensitiveOption);
}
} else {
m_regexp = QRegularExpression(QRegularExpression::escape(m_string));
if (hasOption(CaseSensitive)) {
m_regexp.setPatternOptions(
QRegularExpression::CaseInsensitiveOption);
}
}
bool found = false;
QDocumentCursor::MoveOperation move;
QDocument *d = m_editor ? m_editor->document() : m_origin.document();
QFormatScheme *f =
d->formatScheme() ? d->formatScheme() : QDocument::formatFactory();
int sid = f ? f->id("search") : 0;
if (!sid)
qWarning("Highlighting of search matches disabled due to "
"unavailability of a format scheme.");
move =
backward ? QDocumentCursor::PreviousBlock : QDocumentCursor::NextBlock;
QDocumentSelection boundaries;
bool bounded = m_scope.isValid() && m_scope.hasSelection();
// condition only to avoid debug messages...
if (bounded)
boundaries = m_scope.selection();
while (!end(backward)) {
if (backward && !m_cursor.columnNumber()) {
m_cursor.movePosition(1, QDocumentCursor::PreviousCharacter);
continue;
}
int ln = m_cursor.lineNumber();
QDocumentLine l = m_cursor.line();
int coloffset = 0;
QString s = l.text();
if (backward) {
if (bounded && (boundaries.startLine == ln)) {
s = s.mid(boundaries.start);
coloffset = boundaries.start;
}
s = s.left(m_cursor.columnNumber());
} else {
if (bounded && (boundaries.endLine == ln))
s = s.left(boundaries.end);
}
int column = backward
? s.lastIndexOf(m_regexp, m_cursor.columnNumber() - 1)
: s.indexOf(m_regexp, m_cursor.columnNumber());
auto match = m_regexp.match(s);
/*
qDebug("searching %s in %s => %i",
qPrintable(m_regexp.pattern()),
qPrintable(s),
column);
*/
if (column != -1 && (backward || column >= m_cursor.columnNumber())) {
column += coloffset;
if (backward) {
m_cursor.setColumnNumber(column + match.capturedLength());
m_cursor.setColumnNumber(column, QDocumentCursor::KeepAnchor);
/*
m_cursor.movePosition(m_regexp.matchedLength(),
QDocumentCursor::PreviousCharacter,
QDocumentCursor::KeepAnchor);
*/
} else {
m_cursor.setColumnNumber(column);
m_cursor.setColumnNumber(column + match.capturedLength(),
QDocumentCursor::KeepAnchor);
/*
m_cursor.movePosition(m_regexp.matchedLength(),
QDocumentCursor::NextCharacter,
QDocumentCursor::KeepAnchor);
*/
}
if (m_editor && !hasOption(Silent) && !hasOption(HighlightAll))
m_editor->setCursor(m_cursor);
if (hasOption(Replace)) {
bool rep = true;
if (hasOption(Prompt)) {
int ret = WingMessageBox::question(
m_editor, tr("Replacement prompt"),
tr("Shall it be replaced?"),
QMessageBox::Yes | QMessageBox::No |
QMessageBox::Cancel,
QMessageBox::Yes);
if (ret == QMessageBox::Yes) {
rep = true;
} else if (ret == QMessageBox::No) {
rep = false;
} else if (QMessageBox::Cancel) {
// m_cursor.setColumnNumber(m_cursor.columnNumber());
return;
}
}
//
if (rep) {
QString replacement = m_replace;
for (int i = m_regexp.captureCount(); i >= 0; --i)
replacement.replace(QStringLiteral("\\") +
QString::number(i),
match.captured(i));
m_cursor.beginEditBlock();
m_cursor.removeSelectedText();
m_cursor.insertText(replacement);
m_cursor.endEditBlock();
if (backward)
m_cursor.movePosition(
replacement.length(),
QDocumentCursor::PreviousCharacter);
} else {
// qDebug("no rep");
}
} else if (all || hasOption(HighlightAll)) {
if (sid && hasOption(HighlightAll)) {
if (m_group == -1)
m_group = d->getNextGroupId();
d->addMatch(m_group, m_cursor.lineNumber(),
m_cursor.anchorColumnNumber(),
m_cursor.columnNumber() -
m_cursor.anchorColumnNumber(),
sid);
// QFormatRange r(
// m_cursor.anchorColumnNumber(),
// m_cursor.columnNumber() -
// m_cursor.anchorColumnNumber(),
// m_editor->document()->formatScheme()->id("search")
// );
// qDebug("(%i, %i, %i)", r.offset, r.length, r.format);
// m_cursor.line().addOverlay(r);
}
m_highlight << m_cursor;
m_highlight.last().setAutoUpdated(true);
}
found = true;
if (!(all || hasOption(HighlightAll)))
break;
} else {
m_cursor.movePosition(1, move);
}
}
if (!hasOption(Replace) && hasOption(HighlightAll) && m_highlight.count()) {
// qDebug("%i matches in group %i", indexedMatchCount(), m_group);
if (indexedMatchCount()) {
m_editor->document()->flushMatches(m_group);
} else {
m_editor->document()->releaseGroupId(m_group);
m_group = -1;
}
m_index = backward ? m_highlight.count() : 0;
--m_index;
return next(backward);
}
if (!found) {
m_cursor = QDocumentCursor();
if (hasOption(Silent))
return;
int ret = WingMessageBox::question(
m_editor, tr("Failure"),
tr("End of scope reached with no match.\n"
"Restart from the begining ?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (ret == QMessageBox::Yes) {
m_origin = QDocumentCursor();
next(backward);
}
}
}
/*! @} */

View File

@ -1,97 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QDOCUMENT_SEARCH_H_
#define _QDOCUMENT_SEARCH_H_
#include "qce-config.h"
/*!
\file qdocumentsearch.h
\brief Definition of the QDocumentSearch class
*/
#include <QCoreApplication>
#include <QPointer>
#include <QRegularExpression>
#include <QString>
#include "qdocumentcursor.h"
class QEditor;
class QDocumentSearch {
Q_DECLARE_TR_FUNCTIONS(QDocumentSearch)
public:
enum Option {
WholeWords = 1,
CaseSensitive = 2,
RegExp = 4,
Replace = 8,
Prompt = 16,
Silent = 32,
HighlightAll = 64
};
Q_DECLARE_FLAGS(Options, Option);
QDocumentSearch(QEditor *e, const QString &f, Options opt,
const QString &r = QString());
~QDocumentSearch();
int currentMatchIndex() const;
int indexedMatchCount() const;
QDocumentCursor match(int idx) const;
QString searchText() const;
void setSearchText(const QString &f);
Options options() const;
bool hasOption(Option opt) const;
void setOption(Option opt, bool on);
QString replaceText() const;
void setReplaceText(const QString &r);
QDocumentCursor origin() const;
void setOrigin(const QDocumentCursor &c);
QDocumentCursor cursor() const;
void setCursor(const QDocumentCursor &c);
QDocumentCursor scope() const;
void setScope(const QDocumentCursor &c);
void next(bool backward, bool all = false);
private:
bool end(bool backward) const;
void clearMatches();
int m_group;
int m_index;
Options m_option;
QString m_string;
QString m_replace;
QPointer<QEditor> m_editor;
QDocumentCursor m_cursor, m_scope, m_origin;
QList<QDocumentCursor> m_highlight;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QDocumentSearch::Options)
#endif // !_QDOCUMENT_SEARCH_H_

View File

@ -259,7 +259,7 @@ ScriptManager::buildUpRibbonScriptRunner(RibbonButtonGroup *group) {
void ScriptManager::runScript(const QString &filename) {
Q_ASSERT(_console);
_console->setMode(ScriptingConsole::Output);
_console->stdWarn(tr("Excuting:") + filename);
_console->write(tr("Excuting:") + filename);
_console->newLine();
_console->machine()->executeScript(filename);
_console->appendCommandPrompt();

View File

@ -19,7 +19,6 @@
#include "class/logger.h"
#include "class/skinmanager.h"
#include "qeditor.h"
#include "settings/settings.h"
#include <QApplication>
@ -263,83 +262,84 @@ void SettingManager::loadCodeEditorConfig() {
READ_CONFIG_INT_POSITIVE(pointSize, CODEEDIT_FONT_SIZE, dfont.pointSize());
dfont = QFont(fontName, pointSize);
QEditor::setDefaultFont(dfont);
// QEditor::setDefaultFont(dfont);
int tabStop;
READ_CONFIG_INT_POSITIVE(tabStop, CODEEDIT_TABS_WIDTH, 4);
QEditor::setDefaultTabStop(tabStop);
// QEditor::setDefaultTabStop(tabStop);
QDocument::WhiteSpaceMode ws = QDocument::ShowNone;
// QDocument::WhiteSpaceMode ws = QDocument::ShowNone;
bool b;
READ_CONFIG_BOOL(b, CODEEDIT_SHOW_TABS, false);
if (b)
ws |= QDocument::ShowTabs;
// if (b)
// ws |= QDocument::ShowTabs;
READ_CONFIG_BOOL(b, CODEEDIT_SHOW_LEADING_WHITESPACE, false);
if (b)
ws |= QDocument::ShowLeading;
// if (b)
// ws |= QDocument::ShowLeading;
READ_CONFIG_BOOL(b, CODEEDIT_SHOW_TRAILING_WHITESPACE, false);
if (b)
ws |= QDocument::ShowTrailing;
// if (b)
// ws |= QDocument::ShowTrailing;
QEditor::setDefaultShowSpaces(ws);
// QEditor::setDefaultShowSpaces(ws);
int enums;
READ_CONFIG_INT(enums, CODEEDIT_LINE_ENDINGS,
QDocument::LineEnding::Conservative);
// READ_CONFIG_INT(enums, CODEEDIT_LINE_ENDINGS,
// QDocument::LineEnding::Conservative);
auto le =
QDocument::LineEnding(qMin(enums, int(QDocument::LineEnding::Mac)));
QEditor::setDefaultLineEnding(le);
// auto le =
// QDocument::LineEnding(qMin(enums, int(QDocument::LineEnding::Mac)));
// QEditor::setDefaultLineEnding(le);
int flags = QEditor::defaultFlags();
// int flags = QEditor::defaultFlags();
READ_CONFIG_BOOL(b, CODEEDIT_REPLACE_TABS, true);
if (b)
flags |= QEditor::ReplaceTabs;
else
flags &= ~QEditor::ReplaceTabs;
// if (b)
// flags |= QEditor::ReplaceTabs;
// else
// flags &= ~QEditor::ReplaceTabs;
READ_CONFIG_BOOL(b, CODEEDIT_REMOVE_TRAILING, true);
if (b)
flags |= QEditor::RemoveTrailing;
else
flags &= ~QEditor::RemoveTrailing;
// if (b)
// flags |= QEditor::RemoveTrailing;
// else
// flags &= ~QEditor::RemoveTrailing;
READ_CONFIG_BOOL(b, CODEEDIT_PRESERVE_TRAILING_INDENT, false);
if (b)
flags |= QEditor::PreserveTrailingIndent;
else
flags &= ~QEditor::PreserveTrailingIndent;
// if (b)
// flags |= QEditor::PreserveTrailingIndent;
// else
// flags &= ~QEditor::PreserveTrailingIndent;
QEditor::setDefaultFlags(flags);
// QEditor::setDefaultFlags(flags);
}
void SettingManager::saveCodeEditorConfig() {
HANDLE_CONFIG;
auto font = QEditor::defaultFont();
WRITE_CONFIG(CODEEDIT_FONT, font.family());
WRITE_CONFIG(CODEEDIT_FONT_SIZE, font.pointSize());
// auto font = QEditor::defaultFont();
// WRITE_CONFIG(CODEEDIT_FONT, font.family());
// WRITE_CONFIG(CODEEDIT_FONT_SIZE, font.pointSize());
WRITE_CONFIG(CODEEDIT_TABS_WIDTH, QEditor::defaultTabStop());
// WRITE_CONFIG(CODEEDIT_TABS_WIDTH, QEditor::defaultTabStop());
auto showSpaces = QEditor::defaultShowSpaces();
WRITE_CONFIG(CODEEDIT_SHOW_TABS, showSpaces.testFlag(QDocument::ShowTabs));
WRITE_CONFIG(CODEEDIT_SHOW_LEADING_WHITESPACE,
showSpaces.testFlag(QDocument::ShowLeading));
WRITE_CONFIG(CODEEDIT_SHOW_TRAILING_WHITESPACE,
showSpaces.testFlag(QDocument::ShowTrailing));
// auto showSpaces = QEditor::defaultShowSpaces();
// WRITE_CONFIG(CODEEDIT_SHOW_TABS,
// showSpaces.testFlag(QDocument::ShowTabs));
// WRITE_CONFIG(CODEEDIT_SHOW_LEADING_WHITESPACE,
// showSpaces.testFlag(QDocument::ShowLeading));
// WRITE_CONFIG(CODEEDIT_SHOW_TRAILING_WHITESPACE,
// showSpaces.testFlag(QDocument::ShowTrailing));
WRITE_CONFIG(CODEEDIT_LINE_ENDINGS, int(QEditor::defaultLineEnding()));
// WRITE_CONFIG(CODEEDIT_LINE_ENDINGS, int(QEditor::defaultLineEnding()));
int flags = QEditor::defaultFlags();
WRITE_CONFIG(CODEEDIT_REPLACE_TABS, flags & QEditor::ReplaceTabs);
WRITE_CONFIG(CODEEDIT_REMOVE_TRAILING, flags & QEditor::RemoveTrailing);
WRITE_CONFIG(CODEEDIT_PRESERVE_TRAILING_INDENT,
flags & QEditor::PreserveTrailingIndent);
// int flags = QEditor::defaultFlags();
// WRITE_CONFIG(CODEEDIT_REPLACE_TABS, flags & QEditor::ReplaceTabs);
// WRITE_CONFIG(CODEEDIT_REMOVE_TRAILING, flags & QEditor::RemoveTrailing);
// WRITE_CONFIG(CODEEDIT_PRESERVE_TRAILING_INDENT,
// flags & QEditor::PreserveTrailingIndent);
}
void SettingManager::setUsrHideCats(const QStringList &newUsrHideCats) {

View File

@ -5,7 +5,7 @@ The following components are all third-party components used by the software. Th
* [QHexView](https://github.com/Dax89/QHexView/tree/master) (MIT, **FORK** -> AGPL-3.0)
* [QHexEdit2](https://github.com/Simsys/qhexedit2) (GPL, **FORK**)
* [Qt-Advanced-Docking-System](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System) (LGPL)
* [QCodeEditor2](https://sourceforge.net/projects/edyuk) (GPL, **FORK**)
* [WingCodeEdit](https://github.com/Wing-summer/WingCodeEdit) (GPL)
* [QWingRibbon](https://github.com/martijnkoopman/Qt-Ribbon-Widget) (LGPL, **FORK**)
* [QtSingleApplication](https://github.com/qtproject/qt-solutions/tree/master/qtsingleapplication) (BSD-3-Clause)
* [QWindowKit](https://github.com/stdware/qwindowkit) (Apache v2.0)

View File

@ -16,33 +16,5 @@
*/
#include "codeedit.h"
#include "qlinemarkpanel.h"
#include "qlinenumberpanel.h"
#include "qpanellayout.h"
#include "qeditor.h"
CodeEdit::CodeEdit(bool haslineMark, QWidget *parent, bool actions)
: QObject(parent), QCodeEdit(actions, parent) {
auto l = this->panelLayout();
l->setSizeConstraint(QLayout::SetMinimumSize);
auto editor = this->editor();
if (haslineMark) {
auto lineMark = new QLineMarkPanel(editor);
this->addPanel(lineMark, QCodeEdit::West);
connect(lineMark, &QLineMarkPanel::onToggleMark, this,
&CodeEdit::onToggleMark);
}
auto lineNum = new QLineNumberPanel(editor);
lineNum->setVerboseMode(true);
this->addPanel(lineNum, QCodeEdit::West, true);
connect(editor, &QEditor::cursorPositionChanged, lineNum,
QOverload<>::of(&QLineMarkPanel::update));
this->addPanel(QStringLiteral("Fold Panel"), QCodeEdit::West, true);
this->addPanel(QStringLiteral("Line Change Panel"), QCodeEdit::West, true);
this->addPanel(QStringLiteral("Goto Line Panel"), QCodeEdit::South);
this->addPanel(QStringLiteral("Search Replace Panel"), QCodeEdit::South);
}
CodeEdit::CodeEdit(QWidget *parent) : WingCodeEdit(parent) {}

View File

@ -18,18 +18,18 @@
#ifndef CODEEDIT_H
#define CODEEDIT_H
#include "qcodeedit.h"
#include "WingCodeEdit/wingcodeedit.h"
#include <QObject>
class CodeEdit : public QObject, public QCodeEdit {
class CodeEdit : public WingCodeEdit {
Q_OBJECT
public:
explicit CodeEdit(bool haslineMark, QWidget *parent = nullptr,
bool actions = true);
explicit CodeEdit(QWidget *parent = nullptr);
signals:
void onToggleMark(int lineIndex);
void contentModified(bool b);
private:
};
#endif // CODEEDIT_H

View File

@ -1,573 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qcodecompletionwidget.h"
#include "qcodecompletionwidget_p.h"
#include "qdocument.h"
#include "qdocumentcursor.h"
#include "qdocumentline.h"
#include "qeditor.h"
#include "class/qcodenode.h"
#include "class/ascompletion.h"
#include <QApplication>
#include <QFocusEvent>
#include <QKeyEvent>
#include <QRegularExpression>
#include <QScrollBar>
constexpr auto PADDING = 3;
QCodeCompletionWidget::QCodeCompletionWidget(QEditor *p)
: QListView(nullptr), offset(PADDING) {
// setWindowFlags(Qt::FramelessWindowHint | Qt::SubWindow);
setBatchSize(10);
setMovement(Static);
setFlow(TopToBottom);
setLayoutMode(Batched);
setUniformItemSizes(true);
setEditTriggers(NoEditTriggers);
setSelectionMode(SingleSelection);
QWidget::setCursor(Qt::ArrowCursor);
// just to get rid of warnings...
qRegisterMetaType<QItemSelection>("QItemSelection");
hide();
setEditor(p);
pModel = new QCodeCompletionModel(this);
setModel(pModel);
connect(pModel, &QCodeCompletionModel::changed, this,
&QCodeCompletionWidget::changed);
connect(this, &QCodeCompletionWidget::activated, this,
&QCodeCompletionWidget::complete);
}
void QCodeCompletionWidget::changed() {
if (!isVisible())
return;
verticalScrollBar()->setSliderPosition(0);
horizontalScrollBar()->setSliderPosition(0);
reset();
adjustGeometry();
show();
setFocus();
setCurrentIndex(pModel->index(0, 0));
}
void QCodeCompletionWidget::adjustGeometry() {
QEditor *e = editor();
QWidget *o = e->viewport();
QDocumentCursor cursor = e->cursor();
QDocumentLine line = cursor.line();
const QRect lrect = e->lineRect(cursor.lineNumber());
const QFontMetrics fm = e->document()->fontMetrics();
int h = 0, w = 300, ls = fm.lineSpacing(), y = lrect.y(),
x = line.cursorToX(cursor.columnNumber() + offset);
int off = (cursor.columnNumber() + offset) - line.length();
if (off > 0)
x += off * fm.horizontalAdvance(' ');
x -= e->horizontalScrollBar()->value();
// qDebug("%i items", length()) ;
h = qMin(pModel->rowCount() * ls + 20, qMin(250, 2 * o->height() / 5));
// h = qMin(250, 2 * o->height() / 5);
// qDebug("y = %i; height = %i;", crect.y(), o->height());
if (lrect.y() <= (o->height() / 2)) {
if (x >= (o->width() / 2))
setGeometry(x - w, y + ls, w, h);
else
setGeometry(x, y, w, h);
} else {
if (x >= (o->width() / 2))
setGeometry(x - w, y + lrect.height() - h - ls, w, h);
else
setGeometry(x, y + lrect.height() - h, w, h);
}
offset = PADDING;
}
QDocumentCursor QCodeCompletionWidget::cursor() const { return _cur; }
void QCodeCompletionWidget::setCursor(const QDocumentCursor &newCur) {
_cur = newCur;
}
QEditor *QCodeCompletionWidget::editor() const {
return dynamic_cast<QEditor *>((QObject *)pEditor);
}
void QCodeCompletionWidget::setEditor(QEditor *e) {
pEditor = e;
if (e) {
setParent(e->viewport());
}
}
bool QCodeCompletionWidget::hasEntries() const { return pModel->rowCount(); }
QCodeCompletionWidget::Filter QCodeCompletionWidget::filter() const {
return pModel->filter();
}
void QCodeCompletionWidget::setFilter(Filter f) { pModel->setFilter(f); }
QString QCodeCompletionWidget::prefix() const { return pModel->prefix(); }
void QCodeCompletionWidget::setPrefix(const QString &prefix) {
pModel->setPrefix(prefix);
}
QStringList QCodeCompletionWidget::completions() const {
QString name;
QStringList l;
foreach (QCodeNode *n, pModel->focusNodes()) {
name = n->role(QCodeNode::Name);
if (n->type() ==
QCodeNode::Function) // qobject_cast<QFunctionNode*>(n) )
name += "()";
if (!l.contains(name))
l << name;
}
return l;
}
void QCodeCompletionWidget::setCompletions(const QList<QCodeNode *> &nodes) {
pModel->setFocusNodes(nodes);
}
void QCodeCompletionWidget::setTemporaryNodes(const QList<QCodeNode *> &l) {
m_temps = l;
}
bool QCodeCompletionWidget::isCompleting() const { return _completing; }
void QCodeCompletionWidget::clear() { pModel->clear(); }
void QCodeCompletionWidget::popup() {
// qDebug("popping up...");
if (!editor() || !hasEntries()) {
// qDebug("popup not needed... [0x%x, %i]", (long)editor(),
// pModel->rowlength());
return;
}
adjustGeometry();
// qDebug("showing...");
show();
// qDebug("focusing...");
setFocus();
// qDebug("selecting...");
setCurrentIndex(pModel->index(0, 0, QModelIndex()));
// qDebug("popped up");
}
void QCodeCompletionWidget::complete(const QModelIndex &index) {
_completing = true;
QEditor *e = editor();
if (!index.isValid() || !e)
return;
bool back = false;
QDocumentCursor c = e->cursor();
QString prefix = pModel->prefix(),
txt = pModel->data(index, Qt::UserRole).toString();
// must obtain data before hiding... might be a temporary node
hide();
int pb = txt.indexOf('('), pe = txt.lastIndexOf(')');
if (pb < (pe - 1)) {
back = true;
txt.remove(pb + 1, pe - pb - 1);
}
static QRegularExpression re("(\\bconst\\s*)?(=\\s*0)?$");
txt.remove(re);
QStringView view(txt);
if (prefix.length() &&
prefix.compare(view.left(prefix.length()), Qt::CaseInsensitive) == 0) {
if (_cur.isValid()) {
_cur.movePosition(prefix.length(),
QDocumentCursor::PreviousCharacter,
QDocumentCursor::KeepAnchor);
_cur.removeSelectedText();
}
}
e->write(txt);
if (back) {
auto c = e->cursor();
c.movePosition(1, QDocumentCursor::PreviousCharacter);
e->setCursor(c);
auto cc = c;
cc.movePosition(1, QDocumentCursor::PreviousCharacter);
e->completionEngine()->complete(cc, QStringLiteral("("));
}
e->setFocus();
_completing = false;
}
void QCodeCompletionWidget::showEvent(QShowEvent *e) {
QListView::showEvent(e);
verticalScrollBar()->setValue(0);
horizontalScrollBar()->setValue(0);
}
void QCodeCompletionWidget::hideEvent(QHideEvent *e) {
QListView::hideEvent(e);
qDeleteAll(m_temps);
m_temps.clear();
}
void QCodeCompletionWidget::focusInEvent(QFocusEvent *e) {
QListView::focusInEvent(e);
}
void QCodeCompletionWidget::focusOutEvent(QFocusEvent *e) {
QListView::focusOutEvent(e);
hide();
if (editor())
editor()->setFocus();
}
void QCodeCompletionWidget::keyPressEvent(QKeyEvent *e) {
if (!e)
return;
if (e->modifiers() &
(Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) {
e->ignore();
hide();
if (editor())
editor()->setFocus();
return;
}
const QModelIndex &index = currentIndex();
const int row = index.isValid() ? index.row() : -1;
QString prefix = pModel->prefix(), text = e->text();
switch (e->key()) {
case Qt::Key_Escape:
hide();
if (editor())
editor()->setFocus();
e->accept();
break;
case Qt::Key_Enter:
case Qt::Key_Return:
case Qt::Key_Tab:
// hide();
if (pModel->rowCount()) {
complete(currentIndex());
e->accept();
} else {
e->ignore();
if (editor())
editor()->setFocus();
}
break;
case Qt::Key_Up:
if (row >= 0)
setCurrentIndex(pModel->index(row - 1, 0));
e->accept();
break;
case Qt::Key_Down:
if (row < (pModel->rowCount(QModelIndex()) - 1))
setCurrentIndex(pModel->index(row + 1, 0));
e->accept();
break;
case Qt::Key_Backspace:
if (prefix.length()) {
prefix.chop(1);
pModel->setPrefix(prefix);
offset = -1 + PADDING;
changed();
} else {
hide();
if (editor())
editor()->setFocus();
}
e->ignore();
break;
case Qt::Key_Shift:
case Qt::Key_Alt:
case Qt::Key_Control:
e->ignore();
break;
default:
if (text.length() && text.at(0).isPrint() && pModel->rowCount()) {
pModel->setPrefix(prefix + text);
offset = text.length() + PADDING;
changed();
} else {
hide();
if (editor())
editor()->setFocus();
}
e->ignore();
break;
}
}
////////////////////////////////
QCodeCompletionModel::QCodeCompletionModel(QObject *p)
: QAbstractListModel(p), bUpdate(false) {}
void QCodeCompletionModel::clear() {
beginResetModel();
setPrefix(QString());
setFocusNodes(QList<QCodeNode *>());
setFilter(QCodeCompletionWidget::KeepAll);
m_visibles.clear();
endResetModel();
}
QString QCodeCompletionModel::prefix() const {
return QString::fromUtf8(m_prefix);
}
void QCodeCompletionModel::setPrefix(const QString &prefix) {
m_prefix = prefix.toUtf8();
emit prefixChanged(prefix);
update();
}
QCodeCompletionWidget::Filter QCodeCompletionModel::filter() const {
return m_filter;
}
void QCodeCompletionModel::setFilter(QCodeCompletionWidget::Filter filter) {
m_filter = filter;
emit filterChanged(filter);
update();
}
void QCodeCompletionModel::update() { bUpdate = true; }
void QCodeCompletionModel::forceUpdate() const {
m_visibles.clear();
foreach (QCodeNode *n, m_nodes) {
foreach (QCodeNode *c, n->children()) {
if (match(c, m_filter, m_prefix)) {
m_visibles << c;
}
if (c->type() == QCodeNode::Enum) {
if (match(c, m_filter))
for (auto &ev : c->children())
if (match(ev, m_filter, m_prefix))
m_visibles << ev;
}
}
}
emit const_cast<QCodeCompletionModel *>(this)->layoutChanged();
bUpdate = false;
emit const_cast<QCodeCompletionModel *>(this)->changed();
}
QList<QCodeNode *> QCodeCompletionModel::focusNodes() const { return m_nodes; }
void QCodeCompletionModel::setFocusNodes(const QList<QCodeNode *> &l) {
m_nodes.clear();
foreach (QCodeNode *n, l)
if (n && !m_nodes.contains(n))
m_nodes << n;
update();
}
QVariant QCodeCompletionModel::data(const QModelIndex &index, int role) const {
if (bUpdate)
forceUpdate();
int row = index.row();
if (!index.isValid() || row < 0 || row >= m_visibles.length()) {
// qDebug("invalid input (row=%i)", row);
return QVariant();
}
QCodeNode *n = m_visibles.at(row);
int type = n->type();
if (role == Qt::DisplayRole) {
if (type == QCodeNode::Enumerator) {
return n->parent()->data(role).toString() +
"::" + n->data(role).toString();
}
if (type == QCodeNode::Function || type == QCodeNode::Variable) {
auto p = n->parent();
if (p) {
if (p->type() == QCodeNode::Class) {
return p->role(QCodeNode::Name) + QStringLiteral("::") +
n->data(role).toString();
}
}
}
}
if (role == Qt::UserRole)
role = Qt::DisplayRole;
return n->data(role);
}
Qt::ItemFlags QCodeCompletionModel::flags(const QModelIndex &) const {
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
QVariant QCodeCompletionModel::headerData(int, Qt::Orientation, int) const {
return QVariant();
}
int QCodeCompletionModel::rowCount(const QModelIndex &parent) const {
if (bUpdate)
forceUpdate();
return parent.isValid() ? 0 : m_visibles.length();
}
bool QCodeCompletionModel::match(QCodeNode *n,
QCodeCompletionWidget::Filter filter,
const QByteArray &prefix) {
QByteArray bcxt = n->parent()->qualifiedName(),
bnn = n->role(QCodeNode::Name);
if (!n ||
(!prefix.isEmpty() && (prefix.compare(bnn.left(prefix.length()),
Qt::CaseInsensitive) != 0))) {
return false;
}
int type = n->type(), visibility = n->role(QCodeNode::Visibility).toInt(),
specifiers = (type == QCodeNode::Variable)
? n->role(QCodeNode::Specifiers).toInt()
: 0,
qualifiers = (type == QCodeNode::Function)
? n->role(QCodeNode::Qualifiers).toInt()
: 0;
const char *ctxt = bcxt.constData(), *name = bnn.constData();
int cxt_off = qMax(0, bcxt.lastIndexOf("::"));
if ((((type == QCodeNode::Class) || (type == QCodeNode::Typedef)) &&
!(filter & QCodeCompletionWidget::KeepSubTypes)) ||
((type == QCodeNode::Enum) &&
!(filter & QCodeCompletionWidget::KeepEnums)) ||
((visibility == QCodeNode::VISIBILITY_PRIVATE) &&
!(filter & QCodeCompletionWidget::Private)) ||
((visibility == QCodeNode::VISIBILITY_PROTECTED) &&
!(filter & QCodeCompletionWidget::Protected)) ||
((visibility == QCodeNode::VISIBILITY_PUBLIC) &&
!(filter & QCodeCompletionWidget::Public)) ||
((type == QCodeNode::Variable) &&
((!(filter & QCodeCompletionWidget::KeepStatic)) ||
((specifiers & QCodeNode::SPECIFIER_CONST) &&
!(filter & QCodeCompletionWidget::KeepConst)) ||
((filter & QCodeCompletionWidget::IsStatic))
// ||
// (!(specifiers & QCodeNode::SPECIFIER_CONST) &&
//(filter & QCodeCompletionWidget::IsConst))
)) ||
((type == QCodeNode::Function) &&
((!(filter & QCodeCompletionWidget::KeepStatic)) ||
((qualifiers & QCodeNode::QUALIFIER_CONST) &&
!(filter & QCodeCompletionWidget::KeepConst)) ||
((filter & QCodeCompletionWidget::IsStatic) &&
(n->parent()->type() != QCodeNode::Namespace)) ||
(!(qualifiers & QCodeNode::QUALIFIER_CONST) &&
(filter & QCodeCompletionWidget::IsConst)) ||
(!qstrcmp(name, ctxt + cxt_off) &&
!(filter & QCodeCompletionWidget::KeepCtor)) ||
((*name == '~') && !qstrcmp(name + 1, ctxt) &&
!(filter & QCodeCompletionWidget::KeepDtor))))) {
return false;
}
return true;
}

View File

@ -1,114 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QCOMPLETION_WIDGET_H_
#define _QCOMPLETION_WIDGET_H_
#include <QListView>
#include <QPointer>
#include "class/qcodenode.h"
#include "qdocumentcursor.h"
#include "qeditor.h"
class QCodeCompletionModel;
class QCodeCompletionWidget : public QListView {
Q_OBJECT
public:
enum FilterFlag {
None,
Public = 1,
Protected = 2,
Private = 4,
KeepAllVisibilities = Public | Protected | Private,
IsPointer = 8,
IsStatic = 16,
IsConst = 32,
KeepConst = 64,
KeepStatic = 128,
KeepDtor = 256,
KeepCtor = 512,
KeepAllFunctions = KeepConst | KeepStatic | KeepDtor | KeepCtor,
KeepEnums = 1024,
KeepEnumerators = 2048,
KeepSubTypes = 4096,
KeepAllSub = KeepEnums | KeepEnumerators | KeepSubTypes,
KeepAll = KeepAllFunctions | KeepAllSub | KeepAllVisibilities
};
typedef QFlags<FilterFlag> Filter;
QCodeCompletionWidget(QEditor *p = nullptr);
QEditor *editor() const;
void setEditor(QEditor *e);
bool hasEntries() const;
Filter filter() const;
void setFilter(Filter filter);
QString prefix() const;
void setPrefix(const QString &prefix);
QStringList completions() const;
void setCompletions(const QList<QCodeNode *> &nodes);
void setTemporaryNodes(const QList<QCodeNode *> &l);
bool isCompleting() const;
QDocumentCursor cursor() const;
void setCursor(const QDocumentCursor &newCur);
public slots:
void popup();
void clear();
protected:
virtual void showEvent(QShowEvent *e);
virtual void hideEvent(QHideEvent *e);
virtual void keyPressEvent(QKeyEvent *e);
virtual void focusInEvent(QFocusEvent *e);
virtual void focusOutEvent(QFocusEvent *e);
private slots:
void changed();
void complete(const QModelIndex &index);
private:
void adjustGeometry();
int offset;
QCodeCompletionModel *pModel;
QPointer<QObject> pEditor;
QList<QCodeNode *> m_temps;
QDocumentCursor _cur;
bool _completing = false;
};
#endif // _QCOMPLETION_WIDGET_H_

View File

@ -1,72 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef _QCOMPLETION_WIDGET_P_H_
#define _QCOMPLETION_WIDGET_P_H_
#include "qcodecompletionwidget.h"
#include <QAbstractListModel>
#include <QPointer>
class QCodeNode;
class QCodeModel;
class QCodeCompletionModel : public QAbstractListModel {
Q_OBJECT
public:
QCodeCompletionModel(QObject *p = nullptr);
void clear();
void update();
QString prefix() const;
void setPrefix(const QString &prefix);
QCodeCompletionWidget::Filter filter() const;
void setFilter(QCodeCompletionWidget::Filter filter);
QList<QCodeNode *> focusNodes() const;
void setFocusNodes(const QList<QCodeNode *> &node);
static bool match(QCodeNode *node, QCodeCompletionWidget::Filter filter,
const QByteArray &prefix = QByteArray());
QVariant data(const QModelIndex &index, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
signals:
void changed();
void prefixChanged(const QString &newPrefix);
void filterChanged(QCodeCompletionWidget::Filter f);
private:
void forceUpdate() const;
mutable bool bUpdate;
QByteArray m_prefix;
QList<QCodeNode *> m_nodes;
QCodeCompletionWidget::Filter m_filter;
mutable QList<QCodeNode *> m_visibles;
};
#endif // !_QCOMPLETION_WIDGET_P_H_

View File

@ -17,8 +17,6 @@
#include "scripteditor.h"
#include "DockWidgetTab.h"
#include "qcodeeditwidget/qdocumentswaptextcommand.h"
#include "qeditor.h"
#include "utilities.h"
#ifdef Q_OS_LINUX
@ -29,9 +27,12 @@
#include <QFile>
#include <QPixmap>
#include "qpanellayout.h"
#include <KSyntaxHighlighting/Definition>
#include <KSyntaxHighlighting/Repository>
#include <KSyntaxHighlighting/Theme>
#include "class/clangformatmanager.h"
#include "class/skinmanager.h"
ScriptEditor::ScriptEditor(QWidget *parent)
: ads::CDockWidget(nullptr, QString(), parent) {
@ -42,17 +43,40 @@ ScriptEditor::ScriptEditor(QWidget *parent)
this->setFocusPolicy(Qt::StrongFocus);
this->setObjectName(QStringLiteral("ScriptEditor"));
m_editor = new CodeEdit(true, this);
connect(m_editor, &CodeEdit::onToggleMark, this,
m_editor = new CodeEdit(this);
m_editor->setAutoIndent(true);
m_editor->setMatchBraces(true);
m_editor->setShowLongLineEdge(true);
m_editor->setShowIndentGuides(true);
m_editor->setShowLineNumbers(true);
m_editor->setShowFolding(true);
m_editor->setShowWhitespace(true);
m_editor->setShowSymbolMark(true);
m_editor->setAutoCloseChar(true);
switch (SkinManager::instance().currentTheme()) {
case SkinManager::Theme::Dark:
m_editor->setTheme(m_editor->syntaxRepo().defaultTheme(
KSyntaxHighlighting::Repository::DarkTheme));
break;
case SkinManager::Theme::Light:
m_editor->setTheme(m_editor->syntaxRepo().defaultTheme(
KSyntaxHighlighting::Repository::LightTheme));
break;
}
m_editor->setSyntax(
m_editor->syntaxRepo().definitionForName("AngelScript"));
connect(m_editor, &WingCodeEdit::symbolMarkLineMarginClicked, this,
&ScriptEditor::onToggleMark);
auto editor = m_editor->editor();
editor->setFlag(QEditor::AutoCloseChars, true);
connect(editor, &QEditor::titleChanged, this, &ScriptEditor::processTitle);
connect(editor, &QEditor::contentModified, this,
&ScriptEditor::processTitle);
// connect(editor, &QEditor::titleChanged, this,
// &ScriptEditor::processTitle); connect(editor, &QEditor::contentModified,
// this,
// &ScriptEditor::processTitle);
this->setWidget(editor);
this->setWidget(m_editor);
}
ScriptEditor::~ScriptEditor() {
@ -61,16 +85,19 @@ ScriptEditor::~ScriptEditor() {
e->disconnect();
}
QString ScriptEditor::fileName() const { return editor()->fileName(); }
QString ScriptEditor::fileName() const { return m_fileName; }
bool ScriptEditor::openFile(const QString &filename) {
auto e = editor();
return e->load(filename);
QFile f(filename);
if (!f.open(QFile::ReadOnly | QFile::Text)) {
return false;
}
m_editor->setPlainText(QString::fromUtf8(f.readAll()));
f.close();
return true;
}
bool ScriptEditor::save(const QString &path) {
auto e = editor();
#ifdef Q_OS_LINUX
auto needAdjustFile = !QFile::exists(path);
#endif
@ -81,60 +108,70 @@ bool ScriptEditor::save(const QString &path) {
}
if (path.isEmpty()) {
return e->save();
QFile f(m_fileName);
if (!f.open(QFile::WriteOnly | QFile::Text)) {
return false;
}
f.write(m_editor->toPlainText().toUtf8());
return true;
}
auto ret = e->save(path);
if (ret) {
QFile f(path);
if (!f.open(QFile::WriteOnly | QFile::Text)) {
return false;
}
f.write(m_editor->toPlainText().toUtf8());
#ifdef Q_OS_LINUX
if (Utilities::isRoot()) {
// a trick off when root under linux OS
// When new file created, change file's permission to 666.
if (Utilities::isRoot()) {
// a trick off when root under linux OS
// When new file created, change file's permission to 666.
// Because you cannot open it when you use it in common user
// after saving under root user.
// Because you cannot open it when you use it in common user
// after saving under root user.
// It's a workaround and not eligent for permission system
// It's a workaround and not eligent for permission system
if (needAdjustFile) {
if (Utilities::isFileOwnerRoot(path)) {
Utilities::fixUpFilePermissions(path);
}
if (needAdjustFile) {
if (Utilities::isFileOwnerRoot(path)) {
Utilities::fixUpFilePermissions(path);
}
}
#endif
}
return ret;
#endif
return true;
}
bool ScriptEditor::reload() {
auto e = m_editor->editor();
return e->load(e->fileName());
}
bool ScriptEditor::reload() { return openFile(m_fileName); }
void ScriptEditor::setReadOnly(bool b) {
m_editor->editor()->setFlag(QEditor::ReadOnly, b);
m_editor->setReadOnly(b);
this->tabWidget()->setIcon(b ? ICONRES("lockon") : QIcon());
}
void ScriptEditor::processTitle() {
auto e = m_editor->editor();
if (e->isContentModified()) {
setWindowTitle(e->windowTitle());
if (m_editor->document()->isModified()) {
// setWindowTitle(e->windowTitle());
} else {
setWindowTitle(e->name());
// setWindowTitle(e->name());
}
}
QEditor *ScriptEditor::editor() const { return m_editor->editor(); }
CodeEdit *ScriptEditor::editor() const { return m_editor; }
bool ScriptEditor::formatCode() {
bool ok;
auto e = editor();
auto fmtcodes = ClangFormatManager::instance().formatCode(e->text(), ok);
if (ok) {
auto doc = e->document();
doc->execute(new QDocumentSwapTextCommand(fmtcodes, doc, e));
auto orign = e->toPlainText();
auto fmtcodes = ClangFormatManager::instance().formatCode(orign, ok);
if (ok && fmtcodes != orign) {
auto cursor = e->textCursor();
cursor.beginEditBlock();
cursor.select(QTextCursor::Document);
cursor.removeSelectedText();
cursor.insertText(fmtcodes);
cursor.endEditBlock();
return true;
}
return false;

View File

@ -20,7 +20,6 @@
#include "Qt-Advanced-Docking-System/src/DockWidget.h"
#include "control/codeedit.h"
#include "qcodeedit.h"
class ScriptEditor : public ads::CDockWidget {
Q_OBJECT
@ -31,12 +30,12 @@ public:
QString fileName() const;
QEditor *editor() const;
CodeEdit *editor() const;
bool formatCode();
signals:
void onToggleMark(int lineIndex);
void onToggleMark(int line);
public slots:
bool openFile(const QString &filename);
@ -51,6 +50,7 @@ private:
private:
CodeEdit *m_editor = nullptr;
QString m_fileName;
};
#endif // SCRIPTEDITOR_H

View File

@ -18,25 +18,22 @@
#include "scriptingconsole.h"
#include "class/logger.h"
#include "class/scriptconsolemachine.h"
#include "qdocumentline.h"
#include "qregularexpression.h"
#include <KSyntaxHighlighting/Definition>
#include <KSyntaxHighlighting/Repository>
#include <QApplication>
#include <QColor>
#include <QKeyEvent>
#include <QTextObject>
ScriptingConsole::ScriptingConsole(QWidget *parent) : QConsoleWidget(parent) {}
ScriptingConsole::ScriptingConsole(QWidget *parent) : QConsoleWidget(parent) {
setSyntax(syntaxRepo().definitionForName("AngelScript"));
}
ScriptingConsole::~ScriptingConsole() {}
void ScriptingConsole::stdOut(const QString &str) { writeStdOut(str); }
void ScriptingConsole::stdErr(const QString &str) { writeStdErr(str); }
void ScriptingConsole::stdWarn(const QString &str) {
write(str, QStringLiteral("stdwarn"));
}
void ScriptingConsole::newLine() { _s << Qt::endl; }
void ScriptingConsole::init() {
@ -54,13 +51,14 @@ void ScriptingConsole::init() {
[=](ScriptConsoleMachine::MessageType type,
const ScriptConsoleMachine::MessageInfo &message) {
auto doc = this->document();
auto lastLine = doc->line(doc->lineCount() - 1);
auto lastLine =
doc->findBlockByLineNumber(doc->blockCount() - 1);
switch (type) {
case ScriptMachine::MessageType::Info:
if (lastLine.length()) {
_s << Qt::endl;
}
stdOut(tr("[Info]") + message.message);
write(tr("[Info]") + message.message);
_s << Qt::flush;
newLine();
break;
@ -68,7 +66,7 @@ void ScriptingConsole::init() {
if (lastLine.length()) {
_s << Qt::endl;
}
stdWarn(tr("[Warn]") + message.message);
write(tr("[Warn]") + message.message);
_s << Qt::flush;
newLine();
break;
@ -76,7 +74,7 @@ void ScriptingConsole::init() {
if (lastLine.length()) {
_s << Qt::endl;
}
stdErr(tr("[Error]") + message.message);
write(tr("[Error]") + message.message);
_s << Qt::flush;
newLine();
break;
@ -84,7 +82,7 @@ void ScriptingConsole::init() {
// If running ouput in the console,
// otherwise logging.
if (_sp->isRunning()) {
stdOut(message.message);
write(message.message);
} else {
Logger::logPrint(Logger::packDebugStr(
packUpLoggingStr(message.message)));
@ -98,11 +96,11 @@ void ScriptingConsole::init() {
}
void ScriptingConsole::initOutput() {
stdWarn(tr("Scripting console for WingHexExplorer"));
_s << QStringLiteral(R"(""")") << Qt::endl;
write(tr("Scripting console for WingHexExplorer"));
_s << Qt::endl;
stdWarn(tr(">>>> Powered by AngelScript <<<<"));
_s << Qt::endl << Qt::endl;
write(tr(">>>> Powered by AngelScript <<<<"));
_s << Qt::endl << QStringLiteral(R"(""")") << Qt::endl;
appendCommandPrompt();
setMode(Input);
}
@ -160,7 +158,7 @@ QString ScriptingConsole::getInput() {
if (!_cmdQueue.isEmpty()) {
instr = _cmdQueue.takeFirst();
setMode(Output);
QConsoleWidget::write(instr);
write(instr);
setMode(Input);
break;
}
@ -194,9 +192,9 @@ void ScriptingConsole::appendCommandPrompt(bool storeOnly) {
commandPrompt += QStringLiteral("... > ");
} else {
auto cursor = this->cursor();
if (!cursor.atBlockStart()) {
commandPrompt = QStringLiteral("\n");
}
// if (!cursor.atBlockStart()) {
// commandPrompt = QStringLiteral("\n");
// }
if (_sp && _sp->isDebugMode()) {
commandPrompt += QStringLiteral("[dbg] > ");
} else {
@ -206,7 +204,7 @@ void ScriptingConsole::appendCommandPrompt(bool storeOnly) {
_lastCommandPrompt = storeOnly;
QConsoleWidget::write(commandPrompt);
appendPlainText(commandPrompt);
}
ScriptMachine *ScriptingConsole::machine() const { return _sp; }

View File

@ -38,9 +38,6 @@ public:
void appendCommandPrompt(bool storeOnly = false);
public slots:
void stdOut(const QString &str);
void stdErr(const QString &str);
void stdWarn(const QString &str);
void newLine();
void init();

View File

@ -27,7 +27,6 @@
#include "class/dockcomponentsfactory.h"
#include "class/eventfilter.h"
#include "class/inspectqtloghelper.h"
#include "class/langservice.h"
#include "class/languagemanager.h"
#include "class/layoutmanager.h"
#include "class/logger.h"
@ -40,7 +39,6 @@
#include "class/winginputdialog.h"
#include "class/wingmessagebox.h"
#include "class/wingupdater.h"
#include "control/qcodecompletionwidget.h"
#include "control/toast.h"
#include "encodingdialog.h"
#include "fileinfodialog.h"
@ -245,11 +243,6 @@ MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
if (splash)
splash->setInfoText(tr("SetupScriptService"));
auto &langins = LangService::instance();
langins.init(m_scriptConsole);
langins.applyLanguageSerivce(m_scriptConsole);
connect(&langins, &LangService::onConsoleTip, this,
&MainWindow::showStatus);
m_scriptConsole->initOutput();
m_scriptConsole->machine()->setInsteadFoundDisabled(true);
@ -975,14 +968,16 @@ MainWindow::buildUpScriptConsoleDock(ads::CDockManager *dock,
connect(m_scriptConsole, &ScriptingConsole::consoleCommand, this,
[this] { showStatus({}); });
connect(m_scriptConsole, &ScriptingConsole::inputTimeOuted, this, [this] {
auto e =
qobject_cast<AsCompletion *>(m_scriptConsole->completionEngine());
if (e && e->codeCompletionWidget()->isVisible()) {
return;
}
showStatus({});
});
// connect(m_scriptConsole, &ScriptingConsole::inputTimeOuted, this, [this]
// {
// auto e =
// qobject_cast<AsCompletion
// *>(m_scriptConsole->completionEngine());
// if (e && e->codeCompletionWidget()->isVisible()) {
// return;
// }
// showStatus({});
// });
auto dw = buildDockWidget(dock, QStringLiteral("ScriptConsole"),
tr("ScriptConsole"), m_scriptConsole);

View File

@ -19,8 +19,8 @@
#include "QWingRibbon/ribbontabcontent.h"
#include "Qt-Advanced-Docking-System/src/DockAreaWidget.h"
#include "Qt-Advanced-Docking-System/src/DockSplitter.h"
#include "WingCodeEdit/wingsymbolcenter.h"
#include "aboutsoftwaredialog.h"
#include "class/langservice.h"
#include "class/languagemanager.h"
#include "class/pluginsystem.h"
#include "class/qkeysequences.h"
@ -28,13 +28,8 @@
#include "class/wingfiledialog.h"
#include "class/wingmessagebox.h"
#include "control/toast.h"
#include "qcodeeditwidget/qeditconfig.h"
#include "qcodeeditwidget/qformatconfig.h"
#include "qdocumentline.h"
#include "qeditor.h"
#include "qformatscheme.h"
#include "qlinemarksinfocenter.h"
#include "settings/clangformatsetdialog.h"
#include "settings/qeditconfig.h"
#include <QDesktopServices>
#include <QHeaderView>
@ -82,13 +77,7 @@ ScriptingDialog::ScriptingDialog(QWidget *parent)
buildUpSettingDialog();
auto lmic = QLineMarksInfoCenter::instance();
lmic->loadMarkTypes(QCE::fetchDataFile(":/qcodeedit/marks.qxm"));
// get symbol ID
m_symID.insert(Symbols::BreakPoint, lmic->markTypeId("breakpoint"));
m_symID.insert(Symbols::DbgRunCurrentLine, lmic->markTypeId("current"));
m_symID.insert(Symbols::DbgRunHitBreakPoint,
lmic->markTypeId("breakpoint-current"));
registerMark();
updateEditModeEnabled();
@ -104,8 +93,9 @@ ScriptingDialog::ScriptingDialog(QWidget *parent)
m_dock->restoreState(set.scriptDockLayout());
_savedLayout = set.scriptDockLayout();
connect(&LangService::instance(), &LangService::onScriptEditorTip, m_status,
[this](const QString &message) { m_status->setText(message); });
// connect(&LangService::instance(), &LangService::onScriptEditorTip,
// m_status,
// [this](const QString &message) { m_status->setText(message); });
this->setUpdatesEnabled(true);
}
@ -115,10 +105,6 @@ ScriptingDialog::~ScriptingDialog() {}
void ScriptingDialog::initConsole() {
Q_ASSERT(m_consoleout);
auto fmt = new QFormatScheme(this);
LangService::addAdditionalFormat(fmt);
m_consoleout->document()->setFormatScheme(fmt);
m_consoleout->init();
auto machine = m_consoleout->machine();
connect(machine, &ScriptMachine::onDebugFinished, this, [=] {
@ -129,21 +115,18 @@ void ScriptingDialog::initConsole() {
// clean up
if (!(_lastCurLine.first.isEmpty() || _lastCurLine.second < 0)) {
auto bpMark = m_symID.value(Symbols::BreakPoint);
auto curMark = m_symID.value(Symbols::DbgRunCurrentLine);
auto curHitMark = m_symID.value(Symbols::DbgRunHitBreakPoint);
// remove the last mark
if (!_lastCurLine.first.isEmpty() && _lastCurLine.second >= 0) {
auto lastCur = QCodeEdit::managed(_lastCurLine.first);
auto doc = lastCur->document();
auto line = doc->line(_lastCurLine.second - 1);
if (line.hasMark(curMark)) {
line.removeMark(curMark);
} else if (line.hasMark(curHitMark)) {
line.removeMark(curHitMark);
line.addMark(bpMark);
}
// auto lastCur = QCodeEdit::managed(_lastCurLine.first);
// auto doc = lastCur->document();
// auto line = doc->line(_lastCurLine.second - 1);
// if (line.hasMark(curMark)) {
// line.removeMark(curMark);
// } else if (line.hasMark(curHitMark)) {
// line.removeMark(curHitMark);
// line.addMark(bpMark);
// }
}
_lastCurLine.first.clear();
_lastCurLine.second = -1;
@ -151,16 +134,16 @@ void ScriptingDialog::initConsole() {
if (_needRestart) {
_needRestart = false;
startDebugScript(_DebugingScript);
startDebugScript(_DebugingEditor);
} else {
_DebugingScript.clear();
_DebugingEditor = nullptr;
}
});
auto dbg = machine->debugger();
Q_ASSERT(dbg);
connect(dbg, &asDebugger::onAdjustBreakPointLine, this,
[=](const asDebugger::BreakPoint &old, int newLineNr) {
auto editor = QCodeEdit::managed(old.name);
auto editor = findEditorView(old.name);
if (editor) {
removeBreakPoint(editor, old.lineNbr - 1);
addBreakPoint(editor, newLineNr - 1);
@ -194,36 +177,34 @@ void ScriptingDialog::initConsole() {
}
}
auto bpMark = m_symID.value(Symbols::BreakPoint);
auto curMark = m_symID.value(Symbols::DbgRunCurrentLine);
auto curHitMark = m_symID.value(Symbols::DbgRunHitBreakPoint);
const auto bpMark = QStringLiteral("bp");
const auto curSym = QStringLiteral("cur");
const auto hitCur = QStringLiteral("curbp");
// remove the last mark
if (!_lastCurLine.first.isEmpty() && _lastCurLine.second >= 0) {
auto lastCur = QCodeEdit::managed(_lastCurLine.first);
auto doc = lastCur->document();
auto line = doc->line(_lastCurLine.second - 1);
if (line.hasMark(curMark)) {
line.removeMark(curMark);
} else if (line.hasMark(curHitMark)) {
line.removeMark(curHitMark);
line.addMark(bpMark);
auto lastCur = findEditorView(_lastCurLine.first);
auto e = lastCur->editor();
auto symID = e->symbolMark(_lastCurLine.second);
if (symID == curSym) {
e->removeSymbolMark(_lastCurLine.second);
} else if (symID == hitCur) {
e->addSymbolMark(_lastCurLine.second, bpMark);
}
}
auto editor = e->editor();
// add the new mark
auto doc = editor->document();
auto line = doc->line(lineNr - 1);
if (line.hasMark(bpMark)) {
line.removeMark(bpMark);
line.addMark(curHitMark);
auto symID = editor->symbolMark(lineNr);
if (symID == bpMark) {
editor->addSymbolMark(lineNr, hitCur);
} else {
line.addMark(curMark);
editor->addSymbolMark(lineNr, curSym);
}
editor->ensureVisible(lineNr - 1);
// editor->ensureVisible(lineNr - 1);
_lastCurLine = {file, lineNr};
updateRunDebugMode();
@ -242,7 +223,7 @@ bool ScriptingDialog::about2Close() {
QList<ScriptEditor *> need2CloseView;
for (auto &view : m_views) {
if (view->editor()->isContentModified()) {
if (view->editor()->document()->isModified()) {
unSavedFiles << view->fileName();
} else {
need2CloseView << view;
@ -414,42 +395,6 @@ RibbonTabContent *ScriptingDialog::buildEditPage(RibbonTabContent *tab) {
}
RibbonTabContent *ScriptingDialog::buildViewPage(RibbonTabContent *tab) {
auto shortcuts = QKeySequences::instance();
{
auto pannel = tab->addGroup(tr("Display"));
auto menu = new QMenu(this);
menu->addAction(newAction(QStringLiteral("80%"), [this] {
this->setCurrentEditorScale(0.8);
}));
menu->addAction(newAction(QStringLiteral("90%"), [this] {
this->setCurrentEditorScale(0.9);
}));
menu->addAction(newAction(QStringLiteral("100%"), [this] {
this->setCurrentEditorScale(1.0);
}));
menu->addSeparator();
menu->addAction(newAction(QStringLiteral("120%"), [this] {
this->setCurrentEditorScale(1.2);
}));
menu->addAction(newAction(QStringLiteral("150%"), [this] {
this->setCurrentEditorScale(1.5);
}));
menu->addAction(newAction(QStringLiteral("200%"), [this] {
this->setCurrentEditorScale(2.0);
}));
menu->addAction(newAction(QStringLiteral("250%"), [this] {
this->setCurrentEditorScale(2.5);
}));
menu->addAction(newAction(QStringLiteral("300%"), [this] {
this->setCurrentEditorScale(3.0);
}));
addPannelAction(pannel, QStringLiteral("scale"), tr("Scale"),
EMPTY_FUNC, {}, menu);
addPannelAction(pannel, QStringLiteral("scalereset"), tr("ResetScale"),
[this] { this->setCurrentEditorScale(1.0); });
m_editStateWidgets << pannel;
}
{
auto pannel = tab->addGroup(tr("Window"));
m_Tbtneditors.insert(ToolButtonIndex::EDITOR_VIEWS,
@ -769,6 +714,13 @@ QMessageBox::StandardButton ScriptingDialog::saveRequest() {
return ret;
}
void ScriptingDialog::registerMark() {
auto &sc = WingSymbolCenter::instance();
sc.regsiterSymbol(QStringLiteral("bp"), markFromPath("bp"));
sc.regsiterSymbol(QStringLiteral("cur"), markFromPath("hitcur"));
sc.regsiterSymbol(QStringLiteral("curbp"), markFromPath("hitbp"));
}
void ScriptingDialog::registerEditorView(ScriptEditor *editor) {
connect(editor, &ScriptEditor::closeRequested, this, [this] {
auto editor = qobject_cast<ScriptEditor *>(sender());
@ -776,7 +728,7 @@ void ScriptingDialog::registerEditorView(ScriptEditor *editor) {
Q_ASSERT(m_views.contains(editor));
auto m = m_consoleout->machine();
if (m->isDebugMode() && _DebugingScript == editor->fileName()) {
if (m->isDebugMode() && _DebugingEditor == editor) {
if (WingMessageBox::warning(
this, this->windowTitle(), tr("ScriptStillRunning"),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
@ -785,7 +737,7 @@ void ScriptingDialog::registerEditorView(ScriptEditor *editor) {
on_stopscript();
}
if (editor->editor()->isContentModified()) {
if (editor->editor()->document()->isModified()) {
auto ret = saveRequest();
if (ret == QMessageBox::Cancel) {
return;
@ -823,7 +775,11 @@ void ScriptingDialog::registerEditorView(ScriptEditor *editor) {
updateEditModeEnabled();
});
LangService::instance().applyLanguageSerivce(editor->editor());
connect(editor, &ScriptEditor::onToggleMark, this, [=](int lineIndex) {
auto editor = qobject_cast<ScriptEditor *>(sender());
Q_ASSERT(editor);
toggleBreakPoint(editor, lineIndex);
});
m_views.append(editor);
@ -858,50 +814,39 @@ void ScriptingDialog::swapEditor(ScriptEditor *old, ScriptEditor *cur) {
}
if (old != nullptr) {
old->disconnect(SIGNAL(onToggleMark(int)));
auto editor = old->editor();
editor->disconnect(SIGNAL(copyAvailable(bool)));
editor->disconnect(SIGNAL(contentModified(bool)));
editor->disconnect(SIGNAL(undoAvailable(bool)));
editor->disconnect(SIGNAL(redoAvailable(bool)));
editor->disconnect(SIGNAL(zoomed()));
editor->disconnect(SIGNAL(copyAvailable(bool)));
}
auto editor = cur->editor();
m_Tbtneditors.value(ToolButtonIndex::UNDO_ACTION)
->setEnabled(editor->canUndo());
->setEnabled(editor->document()->isUndoAvailable());
m_Tbtneditors.value(ToolButtonIndex::REDO_ACTION)
->setEnabled(editor->canRedo());
->setEnabled(editor->document()->isRedoAvailable());
m_Tbtneditors.value(ToolButtonIndex::SAVE_ACTION)
->setEnabled(Utilities::fileCanWrite(editor->fileName()) &&
editor->isContentModified());
->setEnabled(Utilities::fileCanWrite(cur->fileName()) &&
editor->document()->isModified());
m_Tbtneditors.value(ToolButtonIndex::COPY_ACTION)
->setEnabled(editor->cursor().hasSelection());
->setEnabled(editor->textCursor().hasSelection());
connect(cur, &ScriptEditor::onToggleMark, this, [=](int lineIndex) {
auto editor = qobject_cast<ScriptEditor *>(sender());
Q_ASSERT(editor);
toggleBreakPoint(editor->editor(), lineIndex);
});
connect(editor, &QEditor::copyAvailable,
connect(editor, &CodeEdit::copyAvailable,
m_Tbtneditors.value(ToolButtonIndex::COPY_ACTION),
&QToolButton::setEnabled);
connect(editor, &QEditor::contentModified, this, [=] {
connect(editor, &CodeEdit::contentModified, this, [=] {
m_Tbtneditors.value(ToolButtonIndex::SAVE_ACTION)
->setEnabled(Utilities::fileCanWrite(editor->fileName()) &&
editor->isContentModified());
->setEnabled(Utilities::fileCanWrite(cur->fileName()) &&
editor->document()->isModified());
});
connect(editor, &QEditor::undoAvailable,
connect(editor, &CodeEdit::undoAvailable,
m_Tbtneditors.value(ToolButtonIndex::UNDO_ACTION),
&QToolButton::setEnabled);
connect(editor, &QEditor::redoAvailable,
connect(editor, &CodeEdit::redoAvailable,
m_Tbtneditors.value(ToolButtonIndex::REDO_ACTION),
&QToolButton::setEnabled);
connect(editor, &QEditor::zoomed, this, [=] {
Toast::toast(this, NAMEICONRES(QStringLiteral("scale")),
QString::number(editor->scaleRate() * 100) +
QStringLiteral("%"));
});
m_curEditor = cur;
}
@ -962,14 +907,6 @@ ScriptEditor *ScriptingDialog::findEditorView(const QString &filename) {
return nullptr;
}
void ScriptingDialog::setCurrentEditorScale(qreal rate) {
auto editor = currentEditor();
if (editor == nullptr) {
return;
}
editor->editor()->setScaleRate(rate);
}
bool ScriptingDialog::isCurrentDebugging() const {
auto m = m_consoleout->machine();
return m && m->isDebugMode();
@ -1014,136 +951,121 @@ void ScriptingDialog::buildUpSettingDialog() {
auto clang = new ClangFormatSetDialog(m_setdialog);
m_setdialog->addPage(clang);
auto &langsev = LangService::instance();
auto scheme = new QFormatConfig(langsev.formatSchemes(),
langsev.defaultSchemeName(), m_setdialog);
m_setdialog->addPage(scheme);
m_setdialog->build();
}
void ScriptingDialog::startDebugScript(const QString &fileName) {
void ScriptingDialog::startDebugScript(ScriptEditor *editor) {
Q_ASSERT(editor);
m_ribbon->setCurrentIndex(3);
m_consoleout->clear();
// add breakpoints
auto marks = QLineMarksInfoCenter::instance()->marks(
fileName, m_symID.value(Symbols::BreakPoint));
auto dbg = m_consoleout->machine()->debugger();
for (auto &bp : marks) {
dbg->addFileBreakPoint(bp.file, bp.line);
auto fileName = editor->fileName();
auto e = editor->editor();
auto totalblk = e->blockCount();
for (int i = 0; i < totalblk; ++i) {
if (!e->symbolMark(i).isEmpty()) {
dbg->addFileBreakPoint(fileName, i + 1);
}
}
_DebugingScript = fileName;
_DebugingEditor = editor;
PluginSystem::instance().scriptPragmaBegin();
auto view = findEditorView(fileName);
Q_ASSERT(view);
view->setReadOnly(true);
editor->setReadOnly(true);
m_consoleout->machine()->executeScript(fileName, true);
view->setReadOnly(false);
editor->setReadOnly(false);
updateRunDebugMode();
}
void ScriptingDialog::addBreakPoint(QEditor *editor, int lineIndex) {
void ScriptingDialog::addBreakPoint(ScriptEditor *editor, int line) {
Q_ASSERT(editor);
auto bpMark = m_symID.value(Symbols::BreakPoint);
auto curLine = lineIndex + 1;
auto dbg = m_consoleout->machine()->debugger();
auto e = editor->editor();
const auto bpMark = QStringLiteral("bp");
const auto curSym = QStringLiteral("cur");
const auto hitCur = QStringLiteral("curbp");
if (m_consoleout->machine()->isDebugMode()) {
auto line = editor->document()->line(lineIndex);
auto hitCur = m_symID.value(Symbols::DbgRunHitBreakPoint);
auto curSym = m_symID.value(Symbols::DbgRunCurrentLine);
if (line.hasMark(curSym)) {
line.removeMark(curSym);
line.addMark(hitCur);
dbg->addFileBreakPoint(editor->fileName(), curLine);
auto dbg = m_consoleout->machine()->debugger();
auto symID = e->symbolMark(line);
if (curSym == symID) {
e->addSymbolMark(line, hitCur);
dbg->addFileBreakPoint(editor->fileName(), line);
} else {
if (!line.hasMark(bpMark)) {
line.addMark(bpMark);
dbg->addFileBreakPoint(editor->fileName(), curLine);
if (symID.isEmpty()) {
e->addSymbolMark(line, curSym);
dbg->addFileBreakPoint(editor->fileName(), line);
}
}
} else {
auto line = editor->document()->line(lineIndex);
if (!line.hasMark(bpMark)) {
line.addMark(bpMark);
dbg->addFileBreakPoint(editor->fileName(), curLine);
}
e->addSymbolMark(line, bpMark);
}
}
void ScriptingDialog::removeBreakPoint(QEditor *editor, int lineIndex) {
void ScriptingDialog::removeBreakPoint(ScriptEditor *editor, int line) {
Q_ASSERT(editor);
auto bpMark = m_symID.value(Symbols::BreakPoint);
auto curLine = lineIndex + 1;
auto e = editor->editor();
auto dbg = m_consoleout->machine()->debugger();
if (m_consoleout->machine()->isDebugMode()) {
auto line = editor->document()->line(lineIndex);
auto hitCur = m_symID.value(Symbols::DbgRunHitBreakPoint);
auto curSym = m_symID.value(Symbols::DbgRunCurrentLine);
auto dbg = m_consoleout->machine()->debugger();
auto symID = e->symbolMark(line);
if (line.hasMark(hitCur)) {
line.removeMark(hitCur);
line.addMark(curSym);
dbg->removeFileBreakPoint(editor->fileName(), curLine);
const auto bpMark = QStringLiteral("bp");
const auto curSym = QStringLiteral("cur");
const auto hitCur = QStringLiteral("curbp");
if (hitCur == symID) {
e->addSymbolMark(line, curSym);
dbg->removeFileBreakPoint(editor->fileName(), line);
} else {
if (line.hasMark(bpMark)) {
line.removeMark(bpMark);
dbg->removeFileBreakPoint(editor->fileName(), curLine);
if (bpMark == symID) {
e->removeSymbolMark(line);
dbg->removeFileBreakPoint(editor->fileName(), line);
}
}
} else {
auto line = editor->document()->line(lineIndex);
if (line.hasMark(bpMark)) {
line.removeMark(bpMark);
dbg->removeFileBreakPoint(editor->fileName(), curLine);
}
e->removeSymbolMark(line);
}
}
void ScriptingDialog::toggleBreakPoint(QEditor *editor, int lineIndex) {
void ScriptingDialog::toggleBreakPoint(ScriptEditor *editor, int line) {
Q_ASSERT(editor);
auto curLine = lineIndex + 1;
auto e = editor->editor();
auto dbg = m_consoleout->machine()->debugger();
if (m_consoleout->machine()->isDebugMode()) {
auto line = editor->document()->line(lineIndex);
auto bpMark = m_symID.value(Symbols::BreakPoint);
auto hitCur = m_symID.value(Symbols::DbgRunHitBreakPoint);
auto curSym = m_symID.value(Symbols::DbgRunCurrentLine);
auto dbg = m_consoleout->machine()->debugger();
auto symID = e->symbolMark(line);
if (line.hasMark(hitCur)) {
line.removeMark(hitCur);
line.addMark(curSym);
dbg->removeFileBreakPoint(editor->fileName(), curLine);
} else if (line.hasMark(curSym)) {
line.removeMark(curSym);
line.addMark(hitCur);
dbg->addFileBreakPoint(editor->fileName(), curLine);
const auto bpMark = QStringLiteral("bp");
const auto curSym = QStringLiteral("cur");
const auto hitCur = QStringLiteral("curbp");
auto fileName = editor->fileName();
if (hitCur == symID) {
e->addSymbolMark(line, curSym);
dbg->removeFileBreakPoint(fileName, line);
} else if (curSym == symID) {
e->addSymbolMark(line, hitCur);
dbg->removeFileBreakPoint(fileName, line);
} else {
if (line.hasMark(bpMark)) {
line.removeMark(bpMark);
dbg->removeFileBreakPoint(editor->fileName(), curLine);
if (bpMark == symID) {
e->removeSymbolMark(line);
dbg->removeFileBreakPoint(fileName, line);
} else {
line.addMark(bpMark);
dbg->addFileBreakPoint(editor->fileName(), curLine);
e->addSymbolMark(line, bpMark);
dbg->addFileBreakPoint(fileName, line);
}
}
} else {
auto bpMark = m_symID.value(Symbols::BreakPoint);
QLineMark mrk(editor->fileName(), curLine, bpMark);
QLineMarksInfoCenter::instance()->toggleLineMark(mrk);
auto line = editor->document()->line(lineIndex);
if (line.hasMark(bpMark)) {
dbg->addFileBreakPoint(editor->fileName(), curLine);
auto symID = e->symbolMark(line);
if (symID.isEmpty()) {
e->addSymbolMark(line, QStringLiteral("bp"));
} else {
dbg->removeFileBreakPoint(editor->fileName(), curLine);
e->removeSymbolMark(line);
}
}
}
@ -1167,7 +1089,7 @@ void ScriptingDialog::on_newfile() {
f.close();
if (e) {
if (_DebugingScript == e->fileName()) {
if (_DebugingEditor == e) {
on_stopscript();
}
e->reload();
@ -1309,28 +1231,28 @@ void ScriptingDialog::on_pastefile() {
void ScriptingDialog::on_delete() {
auto e = currentEditor();
if (e) {
e->editor()->cursor().removeSelectedText();
e->editor()->textCursor().removeSelectedText();
}
}
void ScriptingDialog::on_findfile() {
auto e = currentEditor();
if (e) {
e->editor()->find();
// e->editor()->find();
}
}
void ScriptingDialog::on_replace() {
auto e = currentEditor();
if (e) {
e->editor()->replace();
// e->editor()->replace();
}
}
void ScriptingDialog::on_gotoline() {
auto e = currentEditor();
if (e) {
e->editor()->gotoLine();
// e->editor()->gotoLine();
}
}
@ -1386,8 +1308,7 @@ void ScriptingDialog::on_restoreLayout() {
void ScriptingDialog::on_runscript() {
auto editor = currentEditor();
if (editor) {
auto e = editor->editor();
if (!e->save()) {
if (!editor->save()) {
WingMessageBox::critical(this, qAppName(),
tr("CannotSave2RunScript"));
return;
@ -1396,7 +1317,7 @@ void ScriptingDialog::on_runscript() {
PluginSystem::instance().scriptPragmaBegin();
editor->setReadOnly(true);
m_consoleout->machine()->executeScript(e->fileName());
m_consoleout->machine()->executeScript(editor->fileName());
editor->setReadOnly(false);
updateRunDebugMode();
}
@ -1405,13 +1326,12 @@ void ScriptingDialog::on_runscript() {
void ScriptingDialog::on_rundbgscript() {
auto editor = currentEditor();
if (editor) {
auto e = editor->editor();
if (!e->save()) {
if (!editor->save()) {
WingMessageBox::critical(this, qAppName(),
tr("CannotSave2RunScript"));
return;
}
startDebugScript(e->fileName());
startDebugScript(editor);
}
}
@ -1444,7 +1364,7 @@ void ScriptingDialog::on_togglebreakpoint() {
auto editor = currentEditor();
if (editor) {
auto e = editor->editor();
toggleBreakPoint(e, e->cursor().lineNumber());
toggleBreakPoint(editor, e->textCursor().blockNumber() + 1);
}
}
@ -1452,7 +1372,7 @@ void ScriptingDialog::on_addbreakpoint() {
auto editor = currentEditor();
if (editor) {
auto e = editor->editor();
addBreakPoint(e, e->cursor().lineNumber());
addBreakPoint(editor, e->textCursor().blockNumber() + 1);
}
}
@ -1460,7 +1380,7 @@ void ScriptingDialog::on_removebreakpoint() {
auto editor = currentEditor();
if (editor) {
auto e = editor->editor();
removeBreakPoint(e, e->cursor().lineNumber());
removeBreakPoint(editor, e->textCursor().blockNumber() + 1);
}
}
@ -1485,3 +1405,9 @@ void ScriptingDialog::closeEvent(QCloseEvent *event) {
}
SettingDialog *ScriptingDialog::settingDialog() const { return m_setdialog; }
QPixmap ScriptingDialog::markFromPath(const QString &name) {
return QPixmap(
QStringLiteral(":/com.wingsummer.winghex/images/scriptdbg/") + name +
QStringLiteral(".png"));
}

View File

@ -61,14 +61,6 @@ private:
TOOL_VIEWS
};
enum Symbols {
BreakPoint,
ConditionBreakPoint,
DisabledBreakPoint,
DbgRunCurrentLine,
DbgRunHitBreakPoint,
};
public:
explicit ScriptingDialog(QWidget *parent = nullptr);
virtual ~ScriptingDialog();
@ -200,6 +192,9 @@ private:
}
private:
void registerMark();
QPixmap markFromPath(const QString &name);
void registerEditorView(ScriptEditor *editor);
inline ads::CDockAreaWidget *editorViewArea() const;
@ -211,8 +206,6 @@ private:
ScriptEditor *findEditorView(const QString &filename);
void setCurrentEditorScale(qreal rate);
bool isCurrentDebugging() const;
ScriptEditor *openFile(const QString &filename);
@ -221,13 +214,11 @@ private:
void buildUpSettingDialog();
void startDebugScript(const QString &fileName);
void startDebugScript(ScriptEditor *editor);
void addBreakPoint(QEditor *editor, int lineIndex);
void removeBreakPoint(QEditor *editor, int lineIndex);
void toggleBreakPoint(QEditor *editor, int lineIndex);
void addBreakPoint(ScriptEditor *editor, int line);
void removeBreakPoint(ScriptEditor *editor, int line);
void toggleBreakPoint(ScriptEditor *editor, int line);
private slots:
void on_newfile();
@ -296,7 +287,6 @@ private:
bool _needRestart = false;
QList<ScriptEditor *> m_views;
QMap<Symbols, int> m_symID;
QString m_lastusedpath;
// widgets for debugging
@ -306,7 +296,7 @@ private:
DbgCallStackModel *m_callstack = nullptr;
ASObjTreeWidget *m_sym = nullptr;
QString _DebugingScript;
ScriptEditor *_DebugingEditor;
QLabel *m_status = nullptr;
};

Some files were not shown because too many files have changed in this diff Show More