Initial commit: ReclassX structured binary editor

This commit is contained in:
sysadmin
2026-02-01 11:37:32 -07:00
commit 0be67c8396
786 changed files with 473499 additions and 0 deletions

13
.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
build/
*.exe
*.dll
*.obj
*.o
*.a
*.lib
*.pdb
*.ilk
*.user
*.suo
.vs/
CMakeUserPresets.json

93
CMakeLists.txt Normal file
View File

@@ -0,0 +1,93 @@
cmake_minimum_required(VERSION 3.20)
project(ReclassX VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt6 REQUIRED COMPONENTS Widgets PrintSupport)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
find_package(QScintilla REQUIRED)
add_executable(ReclassX
src/main.cpp
src/editor.h
src/editor.cpp
src/controller.h
src/controller.cpp
src/compose.cpp
src/format.cpp
src/icons.qrc
)
target_include_directories(ReclassX PRIVATE src)
target_link_libraries(ReclassX PRIVATE
Qt6::Widgets
Qt6::PrintSupport
QScintilla::QScintilla
dbghelp
)
add_custom_target(screenshot
COMMAND ReclassX --screenshot ${CMAKE_BINARY_DIR}/screenshot.png
DEPENDS ReclassX
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Capturing UI screenshot with class open..."
)
set(_combine_script "${CMAKE_BINARY_DIR}/combine_sources.cmake")
file(WRITE ${_combine_script} "
set(_out \"${CMAKE_BINARY_DIR}/h_cpp_combined.txt\")
file(WRITE \${_out} \"\")
foreach(_f
\"${CMAKE_SOURCE_DIR}/src/core.h\"
\"${CMAKE_SOURCE_DIR}/src/editor.h\"
\"${CMAKE_SOURCE_DIR}/src/editor.cpp\"
\"${CMAKE_SOURCE_DIR}/src/controller.h\"
\"${CMAKE_SOURCE_DIR}/src/controller.cpp\"
\"${CMAKE_SOURCE_DIR}/src/compose.cpp\"
\"${CMAKE_SOURCE_DIR}/src/format.cpp\"
\"${CMAKE_SOURCE_DIR}/src/main.cpp\")
file(READ \${_f} _content)
file(APPEND \${_out} \${_content})
file(APPEND \${_out} \"\\n\")
endforeach()
message(STATUS \"Combined sources -> \${_out}\")
")
add_custom_target(combined ALL
COMMAND ${CMAKE_COMMAND} -P ${_combine_script}
DEPENDS ReclassX
COMMENT "Combining all source files into h_cpp_combined.txt"
)
include(CTest)
if(BUILD_TESTING)
find_package(Qt6 REQUIRED COMPONENTS Test)
enable_testing()
add_executable(test_core tests/test_core.cpp src/format.cpp src/compose.cpp)
target_include_directories(test_core PRIVATE src)
target_link_libraries(test_core PRIVATE Qt6::Core Qt6::Test)
add_test(NAME test_core COMMAND test_core)
add_executable(test_format tests/test_format.cpp src/format.cpp)
target_include_directories(test_format PRIVATE src)
target_link_libraries(test_format PRIVATE Qt6::Core Qt6::Test)
add_test(NAME test_format COMMAND test_format)
add_executable(test_compose tests/test_compose.cpp src/compose.cpp src/format.cpp)
target_include_directories(test_compose PRIVATE src)
target_link_libraries(test_compose PRIVATE Qt6::Core Qt6::Test)
add_test(NAME test_compose COMMAND test_compose)
add_executable(test_editor tests/test_editor.cpp src/editor.cpp src/compose.cpp src/format.cpp)
target_include_directories(test_editor PRIVATE src)
target_link_libraries(test_editor PRIVATE
Qt6::Widgets Qt6::PrintSupport Qt6::Test
QScintilla::QScintilla)
add_test(NAME test_editor COMMAND test_editor)
endif()

View File

@@ -0,0 +1,32 @@
set(_QSCI_ROOT "${CMAKE_SOURCE_DIR}/third_party/qscintilla")
find_path(QScintilla_INCLUDE_DIR
NAMES Qsci/qsciscintilla.h
PATHS "${_QSCI_ROOT}/src" "${_QSCI_ROOT}/include"
NO_DEFAULT_PATH
)
find_library(QScintilla_LIBRARY
NAMES qscintilla2_qt6 libqscintilla2_qt6
PATHS
"${_QSCI_ROOT}/src/release"
"${_QSCI_ROOT}/src"
"${_QSCI_ROOT}/lib"
NO_DEFAULT_PATH
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(QScintilla DEFAULT_MSG
QScintilla_LIBRARY QScintilla_INCLUDE_DIR)
if(QScintilla_FOUND)
set(QScintilla_INCLUDE_DIRS ${QScintilla_INCLUDE_DIR})
set(QScintilla_LIBRARIES ${QScintilla_LIBRARY})
if(NOT TARGET QScintilla::QScintilla)
add_library(QScintilla::QScintilla STATIC IMPORTED)
set_target_properties(QScintilla::QScintilla PROPERTIES
IMPORTED_LOCATION "${QScintilla_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${QScintilla_INCLUDE_DIR}"
)
endif()
endif()

View File

@@ -0,0 +1,13 @@
@echo off
set "PATH=C:\Qt\Tools\mingw1120_64\bin;C:\Qt\6.5.2\mingw_64\bin;%PATH%"
cd /d "E:\game_dev\util\reclass2027-main\third_party\qscintilla\src"
echo Current dir: %cd%
echo Running qmake...
"C:\Qt\6.5.2\mingw_64\bin\qmake.exe" qscintilla.pro "CONFIG+=staticlib"
echo qmake exit code: %errorlevel%
echo Running mingw32-make...
"C:\Qt\Tools\mingw1120_64\bin\mingw32-make.exe" -j8
echo make exit code: %errorlevel%
echo Done. Checking for .a files:
dir /b *.a 2>nul
dir /b release\*.a 2>nul

323
src/compose.cpp Normal file
View File

@@ -0,0 +1,323 @@
#include "core.h"
#include <algorithm>
namespace rcx {
namespace {
// Scintilla fold constants (avoid including Scintilla headers in core)
constexpr int SC_FOLDLEVELBASE = 0x400;
constexpr int SC_FOLDLEVELHEADERFLAG = 0x2000;
constexpr uint64_t kGoldenRatio = 0x9E3779B97F4A7C15ULL;
struct ComposeState {
QString text;
QVector<LineMeta> meta;
QSet<uint64_t> visiting; // cycle detection for struct recursion
QSet<qulonglong> ptrVisiting; // cycle guard for pointer expansions
int currentLine = 0;
// Precomputed for O(1) lookups
QHash<uint64_t, QVector<int>> childMap;
QVector<int64_t> absOffsets; // indexed by node index
void emitLine(const QString& lineText, LineMeta lm) {
if (currentLine > 0) text += '\n';
// 3-char fold indicator column: " - " expanded, " + " collapsed, " " other
if (lm.foldHead)
text += lm.foldCollapsed ? QStringLiteral(" + ") : QStringLiteral(" - ");
else
text += QStringLiteral(" ");
text += lineText;
meta.append(lm);
currentLine++;
}
};
int computeFoldLevel(int depth, bool isHead) {
int level = SC_FOLDLEVELBASE + depth;
if (isHead) level |= SC_FOLDLEVELHEADERFLAG;
return level;
}
uint32_t computeMarkers(const Node& node, const Provider& prov,
uint64_t addr, bool isCont, int depth) {
uint32_t mask = 0;
if (isCont) mask |= (1u << M_CONT);
if (node.kind == NodeKind::Padding) mask |= (1u << M_PAD);
if (prov.isValid()) {
int sz = node.byteSize();
if (sz > 0 && !prov.isReadable(addr, sz)) {
mask |= (1u << M_ERR);
} else if (sz > 0) {
if (node.kind == NodeKind::Pointer32 && prov.readU32(addr) == 0)
mask |= (1u << M_PTR0);
if (node.kind == NodeKind::Pointer64 && prov.readU64(addr) == 0)
mask |= (1u << M_PTR0);
}
}
return mask;
}
static inline uint64_t ptrToProviderAddr(const NodeTree& tree, uint64_t ptr) {
if (tree.baseAddress && ptr >= tree.baseAddress) return ptr - tree.baseAddress;
return ptr;
}
static int64_t relOffsetFromRoot(const NodeTree& tree, int idx, uint64_t rootId) {
int64_t total = 0;
QSet<int> visited;
int cur = idx;
while (cur >= 0 && cur < tree.nodes.size()) {
if (visited.contains(cur)) break;
visited.insert(cur);
const Node& n = tree.nodes[cur];
if (n.id == rootId) break;
total += n.offset;
if (n.parentId == 0) break;
cur = tree.indexOfId(n.parentId);
}
return total;
}
static inline uint64_t resolveAddr(const ComposeState& state,
const NodeTree& tree,
int nodeIdx,
uint64_t base, uint64_t rootId) {
if (rootId != 0)
return base + relOffsetFromRoot(tree, nodeIdx, rootId);
return state.absOffsets[nodeIdx];
}
void composeLeaf(ComposeState& state, const NodeTree& tree,
const Provider& prov, int nodeIdx,
int depth, uint64_t absAddr) {
const Node& node = tree.nodes[nodeIdx];
// Line count: padding wraps at 8 bytes per line
int numLines;
if (node.kind == NodeKind::Padding) {
int totalBytes = qMax(1, node.arrayLen);
numLines = (totalBytes + 7) / 8;
} else {
numLines = linesForKind(node.kind);
}
for (int sub = 0; sub < numLines; sub++) {
bool isCont = (sub > 0);
LineMeta lm;
lm.nodeIdx = nodeIdx;
lm.nodeId = node.id;
lm.subLine = sub;
lm.depth = depth;
lm.isContinuation = isCont;
lm.lineKind = isCont ? LineKind::Continuation : LineKind::Field;
lm.nodeKind = node.kind;
lm.offsetText = fmt::fmtOffsetMargin(absAddr, isCont);
lm.markerMask = computeMarkers(node, prov, absAddr, isCont, depth);
lm.foldLevel = computeFoldLevel(depth, false);
QString lineText = fmt::fmtNodeLine(node, prov, absAddr, depth, sub);
state.emitLine(lineText, lm);
}
}
// Forward declarations (base/rootId default to 0 = use precomputed offsets)
void composeNode(ComposeState& state, const NodeTree& tree,
const Provider& prov, int nodeIdx, int depth,
uint64_t base = 0, uint64_t rootId = 0);
void composeParent(ComposeState& state, const NodeTree& tree,
const Provider& prov, int nodeIdx, int depth,
uint64_t base = 0, uint64_t rootId = 0);
void composeParent(ComposeState& state, const NodeTree& tree,
const Provider& prov, int nodeIdx, int depth,
uint64_t base, uint64_t rootId) {
const Node& node = tree.nodes[nodeIdx];
uint64_t absAddr = resolveAddr(state, tree, nodeIdx, base, rootId);
// Cycle detection
if (state.visiting.contains(node.id)) {
LineMeta lm;
lm.nodeIdx = nodeIdx;
lm.nodeId = node.id;
lm.depth = depth;
lm.lineKind = LineKind::Field;
lm.offsetText = fmt::fmtOffsetMargin(absAddr, false);
lm.nodeKind = node.kind;
lm.markerMask = (1u << M_CYCLE) | (1u << M_ERR);
lm.foldLevel = computeFoldLevel(depth, false);
state.emitLine(fmt::indent(depth) + QStringLiteral("/* CYCLE: ") +
node.name + QStringLiteral(" */"), lm);
return;
}
state.visiting.insert(node.id);
// Header line
{
LineMeta lm;
lm.nodeIdx = nodeIdx;
lm.nodeId = node.id;
lm.depth = depth;
lm.lineKind = LineKind::Header;
lm.offsetText = fmt::fmtOffsetMargin(absAddr, false);
lm.nodeKind = node.kind;
lm.foldHead = true;
lm.foldCollapsed = node.collapsed;
lm.foldLevel = computeFoldLevel(depth, true);
lm.markerMask = (1u << M_STRUCT_BG);
state.emitLine(fmt::fmtStructHeader(node, depth), lm);
}
if (!node.collapsed) {
QVector<int> children = state.childMap.value(node.id);
std::sort(children.begin(), children.end(), [&](int a, int b) {
return tree.nodes[a].offset < tree.nodes[b].offset;
});
for (int childIdx : children) {
composeNode(state, tree, prov, childIdx, depth + 1, base, rootId);
}
}
// Footer line
{
LineMeta lm;
lm.nodeIdx = nodeIdx;
lm.nodeId = node.id;
lm.depth = depth;
lm.lineKind = LineKind::Footer;
lm.nodeKind = node.kind;
lm.offsetText = QStringLiteral(" ---");
lm.foldLevel = computeFoldLevel(depth, false);
lm.markerMask = (1u << M_STRUCT_BG);
int sz = tree.structSpan(node.id, &state.childMap);
state.emitLine(fmt::fmtStructFooter(node, depth, sz), lm);
}
state.visiting.remove(node.id);
}
void composeNode(ComposeState& state, const NodeTree& tree,
const Provider& prov, int nodeIdx, int depth,
uint64_t base, uint64_t rootId) {
const Node& node = tree.nodes[nodeIdx];
uint64_t absAddr = resolveAddr(state, tree, nodeIdx, base, rootId);
// Pointer deref expansion
if ((node.kind == NodeKind::Pointer32 || node.kind == NodeKind::Pointer64)
&& node.refId != 0) {
{
LineMeta lm;
lm.nodeIdx = nodeIdx;
lm.nodeId = node.id;
lm.depth = depth;
lm.lineKind = LineKind::Field;
lm.offsetText = fmt::fmtOffsetMargin(absAddr, false);
lm.nodeKind = node.kind;
lm.foldHead = true;
lm.foldCollapsed = node.collapsed;
lm.foldLevel = computeFoldLevel(depth, true);
lm.markerMask = computeMarkers(node, prov, absAddr, false, depth);
state.emitLine(fmt::fmtNodeLine(node, prov, absAddr, depth, 0), lm);
}
if (!node.collapsed) {
int sz = node.byteSize();
if (prov.isValid() && sz > 0 && prov.isReadable(absAddr, sz)) {
uint64_t ptrVal = (node.kind == NodeKind::Pointer32)
? (uint64_t)prov.readU32(absAddr) : prov.readU64(absAddr);
if (ptrVal != 0) {
uint64_t pBase = ptrToProviderAddr(tree, ptrVal);
qulonglong key = pBase ^ (node.refId * kGoldenRatio);
if (!state.ptrVisiting.contains(key)) {
state.ptrVisiting.insert(key);
int refIdx = tree.indexOfId(node.refId);
if (refIdx >= 0) {
const Node& ref = tree.nodes[refIdx];
if (ref.kind == NodeKind::Struct || ref.kind == NodeKind::Array)
composeParent(state, tree, prov, refIdx,
depth + 1, pBase, ref.id);
}
state.ptrVisiting.remove(key);
}
}
}
}
return;
}
if (node.kind == NodeKind::Struct || node.kind == NodeKind::Array) {
composeParent(state, tree, prov, nodeIdx, depth, base, rootId);
} else {
composeLeaf(state, tree, prov, nodeIdx, depth, absAddr);
}
}
} // anonymous namespace
ComposeResult compose(const NodeTree& tree, const Provider& prov) {
ComposeState state;
// Precompute parent→children map
for (int i = 0; i < tree.nodes.size(); i++)
state.childMap[tree.nodes[i].parentId].append(i);
// Precompute absolute offsets
state.absOffsets.resize(tree.nodes.size());
for (int i = 0; i < tree.nodes.size(); i++)
state.absOffsets[i] = tree.computeOffset(i);
QVector<int> roots = state.childMap.value(0);
std::sort(roots.begin(), roots.end(), [&](int a, int b) {
return tree.nodes[a].offset < tree.nodes[b].offset;
});
for (int idx : roots) {
composeNode(state, tree, prov, idx, 0);
}
return { state.text, state.meta };
}
QSet<uint64_t> NodeTree::normalizePreferAncestors(const QSet<uint64_t>& ids) const {
QSet<uint64_t> result;
for (uint64_t id : ids) {
int idx = indexOfId(id);
if (idx < 0) continue;
bool ancestorSelected = false;
uint64_t cur = nodes[idx].parentId;
QSet<uint64_t> visited;
while (cur != 0 && !visited.contains(cur)) {
visited.insert(cur);
if (ids.contains(cur)) { ancestorSelected = true; break; }
int pi = indexOfId(cur);
if (pi < 0) break;
cur = nodes[pi].parentId;
}
if (!ancestorSelected)
result.insert(id);
}
return result;
}
QSet<uint64_t> NodeTree::normalizePreferDescendants(const QSet<uint64_t>& ids) const {
QSet<uint64_t> result;
for (uint64_t id : ids) {
QVector<int> sub = subtreeIndices(id);
bool hasSelectedDescendant = false;
for (int si : sub) {
uint64_t sid = nodes[si].id;
if (sid != id && ids.contains(sid)) {
hasSelectedDescendant = true;
break;
}
}
if (!hasSelectedDescendant)
result.insert(id);
}
return result;
}
} // namespace rcx

565
src/controller.cpp Normal file
View File

@@ -0,0 +1,565 @@
#include "controller.h"
#include <QSplitter>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QMenu>
#include <QInputDialog>
#include <QClipboard>
#include <QApplication>
namespace rcx {
// ── RcxDocument ──
RcxDocument::RcxDocument(QObject* parent)
: QObject(parent)
, provider(std::make_unique<NullProvider>())
{
connect(&undoStack, &QUndoStack::cleanChanged, this, [this](bool clean) {
modified = !clean;
});
}
ComposeResult RcxDocument::compose() const {
return rcx::compose(tree, *provider);
}
bool RcxDocument::save(const QString& path) {
QJsonObject json = tree.toJson();
QJsonDocument jdoc(json);
QFile file(path);
if (!file.open(QIODevice::WriteOnly))
return false;
file.write(jdoc.toJson(QJsonDocument::Indented));
filePath = path;
undoStack.setClean();
modified = false;
return true;
}
bool RcxDocument::load(const QString& path) {
QFile file(path);
if (!file.open(QIODevice::ReadOnly))
return false;
undoStack.clear();
QJsonDocument jdoc = QJsonDocument::fromJson(file.readAll());
tree = NodeTree::fromJson(jdoc.object());
filePath = path;
modified = false;
emit documentChanged();
return true;
}
void RcxDocument::loadData(const QString& binaryPath) {
QFile file(binaryPath);
if (!file.open(QIODevice::ReadOnly))
return;
undoStack.clear();
provider = std::make_unique<FileProvider>(file.readAll());
tree.baseAddress = 0;
emit documentChanged();
}
void RcxDocument::loadData(const QByteArray& data) {
undoStack.clear();
provider = std::make_unique<FileProvider>(data);
tree.baseAddress = 0;
emit documentChanged();
}
// ── RcxCommand ──
RcxCommand::RcxCommand(RcxController* ctrl, Command cmd)
: m_ctrl(ctrl), m_cmd(cmd) {}
void RcxCommand::undo() { m_ctrl->applyCommand(m_cmd, true); }
void RcxCommand::redo() { m_ctrl->applyCommand(m_cmd, false); }
// ── RcxController ──
RcxController::RcxController(RcxDocument* doc, QWidget* parent)
: QObject(parent), m_doc(doc)
{
connect(m_doc, &RcxDocument::documentChanged, this, &RcxController::refresh);
}
RcxEditor* RcxController::primaryEditor() const {
return m_editors.isEmpty() ? nullptr : m_editors.first();
}
RcxEditor* RcxController::addSplitEditor(QSplitter* splitter) {
auto* editor = new RcxEditor(splitter);
splitter->addWidget(editor);
m_editors.append(editor);
connectEditor(editor);
if (!m_lastResult.text.isEmpty()) {
editor->applyDocument(m_lastResult);
}
return editor;
}
void RcxController::removeSplitEditor(RcxEditor* editor) {
m_editors.removeOne(editor);
editor->deleteLater();
}
void RcxController::connectEditor(RcxEditor* editor) {
connect(editor, &RcxEditor::marginClicked,
this, [this, editor](int margin, int line, Qt::KeyboardModifiers mods) {
handleMarginClick(editor, margin, line, mods);
});
connect(editor, &RcxEditor::contextMenuRequested,
this, [this, editor](int line, int nodeIdx, int subLine, QPoint globalPos) {
showContextMenu(editor, line, nodeIdx, subLine, globalPos);
});
connect(editor, &RcxEditor::nodeClicked,
this, [this, editor](int line, uint64_t nodeId, Qt::KeyboardModifiers mods) {
handleNodeClick(editor, line, nodeId, mods);
});
// Inline editing signals
connect(editor, &RcxEditor::inlineEditCommitted,
this, [this](int nodeIdx, int subLine, EditTarget target, const QString& text) {
if (nodeIdx < 0) { refresh(); return; }
switch (target) {
case EditTarget::Name:
if (!text.isEmpty()) renameNode(nodeIdx, text);
break;
case EditTarget::Type: {
bool ok;
NodeKind k = kindFromTypeName(text, &ok);
if (ok) changeNodeKind(nodeIdx, k);
break;
}
case EditTarget::Value:
setNodeValue(nodeIdx, subLine, text);
break;
}
// Always refresh to restore canonical text (handles parse failures, no-ops, etc.)
refresh();
});
connect(editor, &RcxEditor::inlineEditCancelled,
this, [this]() { refresh(); });
}
void RcxController::refresh() {
m_lastResult = m_doc->compose();
// Prune stale selections (nodes removed by undo/redo/delete)
QSet<uint64_t> valid;
for (uint64_t id : m_selIds) {
if (m_doc->tree.indexOfId(id) >= 0)
valid.insert(id);
}
m_selIds = valid;
for (auto* editor : m_editors) {
ViewState vs = editor->saveViewState();
editor->applyDocument(m_lastResult);
editor->restoreViewState(vs);
}
applySelectionOverlays();
}
void RcxController::changeNodeKind(int nodeIdx, NodeKind newKind) {
if (nodeIdx < 0 || nodeIdx >= m_doc->tree.nodes.size()) return;
auto& node = m_doc->tree.nodes[nodeIdx];
int oldSize = node.byteSize();
// Compute what byteSize() would be with the new kind
Node tmp = node;
tmp.kind = newKind;
int newSize = tmp.byteSize();
int delta = newSize - oldSize;
QVector<cmd::OffsetAdj> adjs;
if (delta != 0 && oldSize > 0 && newSize > 0) {
int oldEnd = node.offset + oldSize;
auto siblings = m_doc->tree.childrenOf(node.parentId);
for (int si : siblings) {
if (si == nodeIdx) continue;
auto& sib = m_doc->tree.nodes[si];
if (sib.offset >= oldEnd)
adjs.append({sib.id, sib.offset, sib.offset + delta});
}
}
m_doc->undoStack.push(new RcxCommand(this,
cmd::ChangeKind{node.id, node.kind, newKind, adjs}));
}
void RcxController::renameNode(int nodeIdx, const QString& newName) {
if (nodeIdx < 0 || nodeIdx >= m_doc->tree.nodes.size()) return;
auto& node = m_doc->tree.nodes[nodeIdx];
m_doc->undoStack.push(new RcxCommand(this,
cmd::Rename{node.id, node.name, newName}));
}
void RcxController::insertNode(uint64_t parentId, int offset, NodeKind kind, const QString& name) {
Node n;
n.kind = kind;
n.name = name;
n.parentId = parentId;
if (offset < 0) {
// Auto-place after last sibling with alignment
int maxEnd = 0;
auto siblings = m_doc->tree.childrenOf(parentId);
for (int si : siblings) {
auto& sn = m_doc->tree.nodes[si];
int sz = (sn.kind == NodeKind::Struct || sn.kind == NodeKind::Array)
? m_doc->tree.structSpan(sn.id) : sn.byteSize();
int end = sn.offset + sz;
if (end > maxEnd) maxEnd = end;
}
int align = alignmentFor(kind);
n.offset = (maxEnd + align - 1) / align * align;
} else {
n.offset = offset;
}
// Assign ID before storing
n.id = m_doc->tree.m_nextId;
m_doc->undoStack.push(new RcxCommand(this, cmd::Insert{n}));
}
void RcxController::removeNode(int nodeIdx) {
if (nodeIdx < 0 || nodeIdx >= m_doc->tree.nodes.size()) return;
uint64_t nodeId = m_doc->tree.nodes[nodeIdx].id;
QVector<int> indices = m_doc->tree.subtreeIndices(nodeId);
QVector<Node> subtree;
for (int i : indices)
subtree.append(m_doc->tree.nodes[i]);
m_doc->undoStack.push(new RcxCommand(this,
cmd::Remove{nodeId, subtree}));
}
void RcxController::toggleCollapse(int nodeIdx) {
if (nodeIdx < 0 || nodeIdx >= m_doc->tree.nodes.size()) return;
auto& node = m_doc->tree.nodes[nodeIdx];
m_doc->undoStack.push(new RcxCommand(this,
cmd::Collapse{node.id, node.collapsed, !node.collapsed}));
}
void RcxController::applyCommand(const Command& command, bool isUndo) {
auto& tree = m_doc->tree;
std::visit([&](auto&& c) {
using T = std::decay_t<decltype(c)>;
if constexpr (std::is_same_v<T, cmd::ChangeKind>) {
int idx = tree.indexOfId(c.nodeId);
if (idx >= 0)
tree.nodes[idx].kind = isUndo ? c.oldKind : c.newKind;
for (const auto& adj : c.offAdjs) {
int ai = tree.indexOfId(adj.nodeId);
if (ai >= 0)
tree.nodes[ai].offset = isUndo ? adj.oldOffset : adj.newOffset;
}
} else if constexpr (std::is_same_v<T, cmd::Rename>) {
int idx = tree.indexOfId(c.nodeId);
if (idx >= 0)
tree.nodes[idx].name = isUndo ? c.oldName : c.newName;
} else if constexpr (std::is_same_v<T, cmd::Collapse>) {
int idx = tree.indexOfId(c.nodeId);
if (idx >= 0)
tree.nodes[idx].collapsed = isUndo ? c.oldState : c.newState;
} else if constexpr (std::is_same_v<T, cmd::Insert>) {
if (isUndo) {
int idx = tree.indexOfId(c.node.id);
if (idx >= 0) {
tree.nodes.remove(idx);
tree.invalidateIdCache();
}
} else {
tree.addNode(c.node);
}
} else if constexpr (std::is_same_v<T, cmd::Remove>) {
if (isUndo) {
for (const Node& n : c.subtree)
tree.addNode(n);
} else {
QVector<int> indices = tree.subtreeIndices(c.nodeId);
std::sort(indices.begin(), indices.end(), std::greater<int>());
for (int idx : indices)
tree.nodes.remove(idx);
tree.invalidateIdCache();
}
} else if constexpr (std::is_same_v<T, cmd::ChangeBase>) {
tree.baseAddress = isUndo ? c.oldBase : c.newBase;
} else if constexpr (std::is_same_v<T, cmd::WriteBytes>) {
const QByteArray& bytes = isUndo ? c.oldBytes : c.newBytes;
m_doc->provider->writeBytes(c.addr, bytes);
}
}, command);
refresh();
}
void RcxController::setNodeValue(int nodeIdx, int subLine, const QString& text) {
if (nodeIdx < 0 || nodeIdx >= m_doc->tree.nodes.size()) return;
if (!m_doc->provider->isWritable()) return;
const Node& node = m_doc->tree.nodes[nodeIdx];
uint64_t addr = m_doc->tree.computeOffset(nodeIdx);
// For vector sub-components, redirect to float parsing at sub-offset
NodeKind editKind = node.kind;
if ((node.kind == NodeKind::Vec2 || node.kind == NodeKind::Vec3 ||
node.kind == NodeKind::Vec4) && subLine >= 0) {
addr += subLine * 4;
editKind = NodeKind::Float;
}
bool ok;
QByteArray newBytes = fmt::parseValue(editKind, text, &ok);
if (!ok) return;
// For strings, pad/truncate to full buffer size
if (node.kind == NodeKind::UTF8 || node.kind == NodeKind::UTF16) {
int fullSize = node.byteSize();
newBytes = newBytes.left(fullSize);
if (newBytes.size() < fullSize)
newBytes.append(QByteArray(fullSize - newBytes.size(), '\0'));
}
if (newBytes.isEmpty()) return;
int writeSize = newBytes.size();
// Validate write range before pushing command
if (!m_doc->provider->isReadable(addr, writeSize)) return;
QByteArray oldBytes = m_doc->provider->readBytes(addr, writeSize);
m_doc->undoStack.push(new RcxCommand(this,
cmd::WriteBytes{addr, oldBytes, newBytes}));
}
void RcxController::duplicateNode(int nodeIdx) {
if (nodeIdx < 0 || nodeIdx >= m_doc->tree.nodes.size()) return;
const Node& src = m_doc->tree.nodes[nodeIdx];
if (src.kind == NodeKind::Struct || src.kind == NodeKind::Array) return;
insertNode(src.parentId, src.offset + src.byteSize(), src.kind, src.name + "_copy");
}
void RcxController::showContextMenu(RcxEditor* editor, int line, int nodeIdx,
int subLine, const QPoint& globalPos) {
if (nodeIdx < 0 || nodeIdx >= m_doc->tree.nodes.size()) return;
uint64_t clickedId = m_doc->tree.nodes[nodeIdx].id;
// Right-click selection policy: if not in selection, select only this node
if (!m_selIds.contains(clickedId)) {
m_selIds.clear();
m_selIds.insert(clickedId);
m_anchorLine = line;
applySelectionOverlays();
}
// Multi-select batch menu
if (m_selIds.size() > 1) {
QMenu menu;
int count = m_selIds.size();
QSet<uint64_t> ids = m_selIds;
menu.addAction(QString("Delete %1 nodes").arg(count), [this, ids]() {
QVector<int> indices;
for (uint64_t id : ids) {
int idx = m_doc->tree.indexOfId(id);
if (idx >= 0) indices.append(idx);
}
batchRemoveNodes(indices);
});
menu.addAction(QString("Change type of %1 nodes...").arg(count),
[this, ids]() {
QStringList types;
for (const auto& e : kKindMeta) types << e.name;
bool ok;
QString sel = QInputDialog::getItem(nullptr, "Change Type", "Type:",
types, 0, false, &ok);
if (ok) {
QVector<int> indices;
for (uint64_t id : ids) {
int idx = m_doc->tree.indexOfId(id);
if (idx >= 0) indices.append(idx);
}
batchChangeKind(indices, kindFromString(sel));
}
});
menu.exec(globalPos);
return;
}
const Node& node = m_doc->tree.nodes[nodeIdx];
uint64_t nodeId = node.id;
uint64_t parentId = node.parentId;
QMenu menu;
// Inline edit actions — position cursor on the right-clicked line
bool isEditable = node.kind != NodeKind::Struct && node.kind != NodeKind::Array
&& node.kind != NodeKind::Padding && node.kind != NodeKind::Mat4x4
&& m_doc->provider->isWritable();
if (isEditable) {
menu.addAction("Edit &Value", [editor, line]() {
editor->beginInlineEdit(EditTarget::Value, line);
});
}
menu.addAction("Re&name", [editor, line]() {
editor->beginInlineEdit(EditTarget::Name, line);
});
menu.addAction("Change &Type", [editor, line]() {
editor->beginInlineEdit(EditTarget::Type, line);
});
menu.addSeparator();
menu.addAction("&Add Field Below", [this, parentId]() {
insertNode(parentId, -1, NodeKind::Hex64, "newField");
});
if (node.kind == NodeKind::Struct || node.kind == NodeKind::Array) {
menu.addAction("Add &Child", [this, nodeId]() {
insertNode(nodeId, 0, NodeKind::Hex64, "newField");
});
QString colText = node.collapsed ? "&Expand" : "&Collapse";
menu.addAction(colText, [this, nodeId]() {
int ni = m_doc->tree.indexOfId(nodeId);
if (ni >= 0) toggleCollapse(ni);
});
}
menu.addAction("D&uplicate", [this, nodeId]() {
int ni = m_doc->tree.indexOfId(nodeId);
if (ni >= 0) duplicateNode(ni);
});
menu.addAction("&Delete", [this, nodeId]() {
int ni = m_doc->tree.indexOfId(nodeId);
if (ni >= 0) removeNode(ni);
});
menu.addSeparator();
menu.addAction("Copy &Address", [this, nodeId]() {
int ni = m_doc->tree.indexOfId(nodeId);
if (ni < 0) return;
uint64_t addr = m_doc->tree.baseAddress + m_doc->tree.computeOffset(ni);
QApplication::clipboard()->setText(
QStringLiteral("0x") + QString::number(addr, 16).toUpper());
});
menu.addAction("Copy &Offset", [this, nodeId]() {
int ni = m_doc->tree.indexOfId(nodeId);
if (ni < 0) return;
int off = m_doc->tree.nodes[ni].offset;
QApplication::clipboard()->setText(
QStringLiteral("+0x") + QString::number(off, 16).toUpper().rightJustified(4, '0'));
});
menu.exec(globalPos);
}
void RcxController::batchRemoveNodes(const QVector<int>& nodeIndices) {
QSet<uint64_t> idSet;
for (int idx : nodeIndices) {
if (idx >= 0 && idx < m_doc->tree.nodes.size())
idSet.insert(m_doc->tree.nodes[idx].id);
}
idSet = m_doc->tree.normalizePreferAncestors(idSet);
if (idSet.isEmpty()) return;
m_doc->undoStack.beginMacro(QString("Delete %1 nodes").arg(idSet.size()));
for (uint64_t id : idSet) {
int idx = m_doc->tree.indexOfId(id);
if (idx >= 0) removeNode(idx);
}
m_doc->undoStack.endMacro();
}
void RcxController::batchChangeKind(const QVector<int>& nodeIndices, NodeKind newKind) {
QSet<uint64_t> idSet;
for (int idx : nodeIndices) {
if (idx >= 0 && idx < m_doc->tree.nodes.size())
idSet.insert(m_doc->tree.nodes[idx].id);
}
idSet = m_doc->tree.normalizePreferDescendants(idSet);
if (idSet.isEmpty()) return;
m_doc->undoStack.beginMacro(QString("Change type of %1 nodes").arg(idSet.size()));
for (uint64_t id : idSet) {
int idx = m_doc->tree.indexOfId(id);
if (idx >= 0) changeNodeKind(idx, newKind);
}
m_doc->undoStack.endMacro();
}
void RcxController::handleNodeClick(RcxEditor* source, int line,
uint64_t nodeId,
Qt::KeyboardModifiers mods) {
bool ctrl = mods & Qt::ControlModifier;
bool shift = mods & Qt::ShiftModifier;
if (!ctrl && !shift) {
m_selIds.clear();
m_selIds.insert(nodeId);
m_anchorLine = line;
} else if (ctrl && !shift) {
if (m_selIds.contains(nodeId))
m_selIds.remove(nodeId);
else
m_selIds.insert(nodeId);
m_anchorLine = line;
} else if (shift && !ctrl) {
m_selIds.clear();
int from = qMin(m_anchorLine, line);
int to = qMax(m_anchorLine, line);
for (int i = from; i <= to && i < m_lastResult.meta.size(); i++) {
uint64_t nid = m_lastResult.meta[i].nodeId;
if (nid != 0) m_selIds.insert(nid);
}
} else { // Ctrl+Shift
int from = qMin(m_anchorLine, line);
int to = qMax(m_anchorLine, line);
for (int i = from; i <= to && i < m_lastResult.meta.size(); i++) {
uint64_t nid = m_lastResult.meta[i].nodeId;
if (nid != 0) m_selIds.insert(nid);
}
}
applySelectionOverlays();
if (m_selIds.size() == 1) {
uint64_t sid = *m_selIds.begin();
int idx = m_doc->tree.indexOfId(sid);
if (idx >= 0) emit nodeSelected(idx);
}
}
void RcxController::clearSelection() {
m_selIds.clear();
m_anchorLine = -1;
applySelectionOverlays();
}
void RcxController::applySelectionOverlays() {
for (auto* editor : m_editors)
editor->applySelectionOverlay(m_selIds);
}
void RcxController::handleMarginClick(RcxEditor* editor, int margin,
int line, Qt::KeyboardModifiers) {
const LineMeta* lm = editor->metaForLine(line);
if (!lm) return;
if (lm->foldHead && (margin == 0 || margin == 1)) {
toggleCollapse(lm->nodeIdx);
} else if (margin == 0 || margin == 1) {
emit nodeSelected(lm->nodeIdx);
}
}
} // namespace rcx

99
src/controller.h Normal file
View File

@@ -0,0 +1,99 @@
#pragma once
#include "core.h"
#include "editor.h"
#include <QObject>
#include <QUndoStack>
#include <QUndoCommand>
#include <memory>
class QSplitter;
namespace rcx {
class RcxController;
// ── Document ──
class RcxDocument : public QObject {
Q_OBJECT
public:
explicit RcxDocument(QObject* parent = nullptr);
NodeTree tree;
std::unique_ptr<Provider> provider;
QUndoStack undoStack;
QString filePath;
bool modified = false;
ComposeResult compose() const;
bool save(const QString& path);
bool load(const QString& path);
void loadData(const QString& binaryPath);
void loadData(const QByteArray& data);
signals:
void documentChanged();
};
// ── Undo command ──
class RcxCommand : public QUndoCommand {
public:
RcxCommand(RcxController* ctrl, Command cmd);
void undo() override;
void redo() override;
private:
RcxController* m_ctrl;
Command m_cmd;
};
// ── Controller ──
class RcxController : public QObject {
Q_OBJECT
public:
explicit RcxController(RcxDocument* doc, QWidget* parent = nullptr);
RcxEditor* primaryEditor() const;
RcxEditor* addSplitEditor(QSplitter* splitter);
void removeSplitEditor(RcxEditor* editor);
QList<RcxEditor*> editors() const { return m_editors; }
void changeNodeKind(int nodeIdx, NodeKind newKind);
void renameNode(int nodeIdx, const QString& newName);
void insertNode(uint64_t parentId, int offset, NodeKind kind, const QString& name);
void removeNode(int nodeIdx);
void toggleCollapse(int nodeIdx);
void setNodeValue(int nodeIdx, int subLine, const QString& text);
void duplicateNode(int nodeIdx);
void showContextMenu(RcxEditor* editor, int line, int nodeIdx, int subLine, const QPoint& globalPos);
void batchRemoveNodes(const QVector<int>& nodeIndices);
void batchChangeKind(const QVector<int>& nodeIndices, NodeKind newKind);
void applyCommand(const Command& cmd, bool isUndo);
void refresh();
// Selection
void handleNodeClick(RcxEditor* source, int line, uint64_t nodeId,
Qt::KeyboardModifiers mods);
void clearSelection();
void applySelectionOverlays();
QSet<uint64_t> selectedIds() const { return m_selIds; }
RcxDocument* document() const { return m_doc; }
signals:
void nodeSelected(int nodeIdx);
private:
RcxDocument* m_doc;
QList<RcxEditor*> m_editors;
ComposeResult m_lastResult;
QSet<uint64_t> m_selIds;
int m_anchorLine = -1;
void connectEditor(RcxEditor* editor);
void handleMarginClick(RcxEditor* editor, int margin, int line, Qt::KeyboardModifiers mods);
};
} // namespace rcx

521
src/core.h Normal file
View File

@@ -0,0 +1,521 @@
#pragma once
#include <QString>
#include <QVector>
#include <QJsonObject>
#include <QJsonArray>
#include <QByteArray>
#include <QFile>
#include <QHash>
#include <QSet>
#include <cstdint>
#include <memory>
#include <variant>
namespace rcx {
// ── Node kind enum ──
enum class NodeKind : uint8_t {
Hex8, Hex16, Hex32, Hex64,
Int8, Int16, Int32, Int64,
UInt8, UInt16, UInt32, UInt64,
Float, Double, Bool,
Pointer32, Pointer64,
Vec2, Vec3, Vec4, Mat4x4,
UTF8, UTF16,
Padding,
Struct, Array
};
// ── Unified kind metadata table (single source of truth) ──
struct KindMeta {
NodeKind kind;
const char* name; // UI/JSON name: "Hex64", "UInt16"
const char* typeName; // display name: "Hex64", "uint16_t"
int size; // byte size (0 = dynamic: Struct/Array)
int lines; // display line count
int align; // natural alignment
};
inline constexpr KindMeta kKindMeta[] = {
// kind name typeName sz ln al
{NodeKind::Hex8, "Hex8", "Hex8", 1, 1, 1},
{NodeKind::Hex16, "Hex16", "Hex16", 2, 1, 2},
{NodeKind::Hex32, "Hex32", "Hex32", 4, 1, 4},
{NodeKind::Hex64, "Hex64", "Hex64", 8, 1, 8},
{NodeKind::Int8, "Int8", "int8_t", 1, 1, 1},
{NodeKind::Int16, "Int16", "int16_t", 2, 1, 2},
{NodeKind::Int32, "Int32", "int32_t", 4, 1, 4},
{NodeKind::Int64, "Int64", "int64_t", 8, 1, 8},
{NodeKind::UInt8, "UInt8", "uint8_t", 1, 1, 1},
{NodeKind::UInt16, "UInt16", "uint16_t", 2, 1, 2},
{NodeKind::UInt32, "UInt32", "uint32_t", 4, 1, 4},
{NodeKind::UInt64, "UInt64", "uint64_t", 8, 1, 8},
{NodeKind::Float, "Float", "float", 4, 1, 4},
{NodeKind::Double, "Double", "double", 8, 1, 8},
{NodeKind::Bool, "Bool", "bool", 1, 1, 1},
{NodeKind::Pointer32, "Pointer32", "ptr32", 4, 1, 4},
{NodeKind::Pointer64, "Pointer64", "ptr64", 8, 1, 8},
{NodeKind::Vec2, "Vec2", "Vec2", 8, 2, 4},
{NodeKind::Vec3, "Vec3", "Vec3", 12, 3, 4},
{NodeKind::Vec4, "Vec4", "Vec4", 16, 4, 4},
{NodeKind::Mat4x4, "Mat4x4", "Mat4x4", 64, 4, 4},
{NodeKind::UTF8, "UTF8", "char[]", 1, 1, 1},
{NodeKind::UTF16, "UTF16", "wchar_t[]", 2, 1, 2},
{NodeKind::Padding, "Padding", "pad", 1, 1, 1},
{NodeKind::Struct, "Struct", "struct", 0, 1, 1},
{NodeKind::Array, "Array", "array", 0, 1, 1},
};
inline constexpr const KindMeta* kindMeta(NodeKind k) {
for (const auto& m : kKindMeta)
if (m.kind == k) return &m;
return nullptr;
}
inline constexpr int sizeForKind(NodeKind k) { auto* m = kindMeta(k); return m ? m->size : 0; }
inline constexpr int linesForKind(NodeKind k) { auto* m = kindMeta(k); return m ? m->lines : 1; }
inline constexpr int alignmentFor(NodeKind k) { auto* m = kindMeta(k); return m ? m->align : 1; }
inline const char* kindToString(NodeKind k) {
auto* m = kindMeta(k);
return m ? m->name : "Unknown";
}
inline NodeKind kindFromString(const QString& s) {
for (const auto& m : kKindMeta)
if (s == m.name) return m.kind;
return NodeKind::Hex8;
}
inline NodeKind kindFromTypeName(const QString& s, bool* ok = nullptr) {
for (const auto& m : kKindMeta) {
if (s == m.typeName) {
if (ok) *ok = true;
return m.kind;
}
}
if (ok) *ok = false;
return NodeKind::Hex8;
}
// ── Marker vocabulary ──
enum Marker : int {
M_CONT = 0,
M_PAD = 1,
M_PTR0 = 2,
M_CYCLE = 3,
M_ERR = 4,
M_STRUCT_BG = 5,
};
// ── Provider interface ──
class Provider {
public:
virtual ~Provider() = default;
virtual uint8_t readU8 (uint64_t addr) const = 0;
virtual uint16_t readU16(uint64_t addr) const = 0;
virtual uint32_t readU32(uint64_t addr) const = 0;
virtual uint64_t readU64(uint64_t addr) const = 0;
virtual float readF32(uint64_t addr) const = 0;
virtual double readF64(uint64_t addr) const = 0;
virtual QByteArray readBytes(uint64_t addr, int len) const = 0;
virtual bool isValid() const = 0;
virtual bool isReadable(uint64_t addr, int len) const = 0;
virtual int size() const = 0;
virtual bool isWritable() const { return false; }
virtual bool writeBytes(uint64_t addr, const QByteArray& data) {
Q_UNUSED(addr); Q_UNUSED(data); return false;
}
};
class FileProvider : public Provider {
QByteArray m_data;
template<class T>
T readT(uint64_t a) const {
if (a + sizeof(T) > (uint64_t)m_data.size()) return T{};
T v; memcpy(&v, m_data.data() + a, sizeof(T)); return v;
}
public:
explicit FileProvider(const QByteArray& data) : m_data(data) {}
static FileProvider fromFile(const QString& path) {
QFile f(path);
if (f.open(QIODevice::ReadOnly)) return FileProvider(f.readAll());
return FileProvider({});
}
bool isValid() const override { return !m_data.isEmpty(); }
bool isReadable(uint64_t addr, int len) const override {
if (len <= 0) return len == 0;
if (addr > (uint64_t)m_data.size()) return false;
return (uint64_t)len <= (uint64_t)m_data.size() - addr;
}
int size() const override { return m_data.size(); }
uint8_t readU8 (uint64_t a) const override { return readT<uint8_t>(a); }
uint16_t readU16(uint64_t a) const override { return readT<uint16_t>(a); }
uint32_t readU32(uint64_t a) const override { return readT<uint32_t>(a); }
uint64_t readU64(uint64_t a) const override { return readT<uint64_t>(a); }
float readF32(uint64_t a) const override { return readT<float>(a); }
double readF64(uint64_t a) const override { return readT<double>(a); }
QByteArray readBytes(uint64_t a, int len) const override {
if (a >= (uint64_t)m_data.size()) return {};
int avail = qMin(len, (int)((uint64_t)m_data.size() - a));
return m_data.mid((int)a, avail);
}
bool isWritable() const override { return true; }
bool writeBytes(uint64_t addr, const QByteArray& data) override {
if (addr + data.size() > (uint64_t)m_data.size()) return false;
memcpy(m_data.data() + addr, data.data(), data.size());
return true;
}
};
class NullProvider : public Provider {
public:
uint8_t readU8 (uint64_t) const override { return 0; }
uint16_t readU16(uint64_t) const override { return 0; }
uint32_t readU32(uint64_t) const override { return 0; }
uint64_t readU64(uint64_t) const override { return 0; }
float readF32(uint64_t) const override { return 0.0f; }
double readF64(uint64_t) const override { return 0.0; }
QByteArray readBytes(uint64_t, int) const override { return {}; }
bool isValid() const override { return false; }
bool isReadable(uint64_t, int) const override { return false; }
int size() const override { return 0; }
};
// ── Node ──
struct Node {
uint64_t id = 0;
NodeKind kind = NodeKind::Hex8;
QString name;
uint64_t parentId = 0; // 0 = root (no parent)
int offset = 0;
int arrayLen = 0;
int strLen = 64;
bool collapsed = false;
uint64_t refId = 0; // Pointer32/64: id of Struct to expand at *ptr
int byteSize() const {
switch (kind) {
case NodeKind::UTF8: return strLen;
case NodeKind::UTF16: return strLen * 2;
case NodeKind::Padding: return qMax(1, arrayLen);
default: return sizeForKind(kind);
}
}
QJsonObject toJson() const {
QJsonObject o;
o["id"] = QString::number(id);
o["kind"] = kindToString(kind);
o["name"] = name;
o["parentId"] = QString::number(parentId);
o["offset"] = offset;
o["arrayLen"] = arrayLen;
o["strLen"] = strLen;
o["collapsed"] = collapsed;
o["refId"] = QString::number(refId);
return o;
}
static Node fromJson(const QJsonObject& o) {
Node n;
n.id = o["id"].toString("0").toULongLong();
n.kind = kindFromString(o["kind"].toString());
n.name = o["name"].toString();
n.parentId = o["parentId"].toString("0").toULongLong();
n.offset = o["offset"].toInt(0);
n.arrayLen = o["arrayLen"].toInt(0);
n.strLen = o["strLen"].toInt(64);
n.collapsed = o["collapsed"].toBool(false);
n.refId = o["refId"].toString("0").toULongLong();
return n;
}
};
// ── NodeTree ──
struct NodeTree {
QVector<Node> nodes;
uint64_t baseAddress = 0x00400000;
uint64_t m_nextId = 1;
mutable QHash<uint64_t, int> m_idCache;
int addNode(const Node& n) {
Node copy = n;
if (copy.id == 0) copy.id = m_nextId++;
else if (copy.id >= m_nextId) m_nextId = copy.id + 1;
nodes.append(copy);
m_idCache.clear();
return nodes.size() - 1;
}
void invalidateIdCache() const { m_idCache.clear(); }
int indexOfId(uint64_t id) const {
if (m_idCache.isEmpty() && !nodes.isEmpty()) {
for (int i = 0; i < nodes.size(); i++)
m_idCache[nodes[i].id] = i;
}
return m_idCache.value(id, -1);
}
QVector<int> childrenOf(uint64_t parentId) const {
QVector<int> result;
for (int i = 0; i < nodes.size(); i++) {
if (nodes[i].parentId == parentId) result.append(i);
}
return result;
}
// Collect node + all descendants (iterative, cycle-safe)
QVector<int> subtreeIndices(uint64_t nodeId) const {
int idx = indexOfId(nodeId);
if (idx < 0) return {};
// Build parent→children map
QHash<uint64_t, QVector<int>> childMap;
for (int i = 0; i < nodes.size(); i++)
childMap[nodes[i].parentId].append(i);
// BFS with visited guard
QVector<int> result;
QSet<uint64_t> visited;
QVector<uint64_t> stack;
stack.append(nodeId);
result.append(idx);
visited.insert(nodeId);
while (!stack.isEmpty()) {
uint64_t pid = stack.takeLast();
for (int ci : childMap.value(pid)) {
uint64_t cid = nodes[ci].id;
if (!visited.contains(cid)) {
visited.insert(cid);
result.append(ci);
stack.append(cid);
}
}
}
return result;
}
int depthOf(int idx) const {
int d = 0;
QSet<int> visited;
int cur = idx;
while (cur >= 0 && cur < nodes.size() && nodes[cur].parentId != 0) {
if (visited.contains(cur)) break;
visited.insert(cur);
cur = indexOfId(nodes[cur].parentId);
if (cur < 0) break;
d++;
}
return d;
}
int64_t computeOffset(int idx) const {
int64_t total = 0;
QSet<int> visited;
int cur = idx;
while (cur >= 0 && cur < nodes.size()) {
if (visited.contains(cur)) break;
visited.insert(cur);
total += nodes[cur].offset;
if (nodes[cur].parentId == 0) break;
cur = indexOfId(nodes[cur].parentId);
}
return total;
}
int structSpan(uint64_t structId,
const QHash<uint64_t, QVector<int>>* childMap = nullptr) const {
int maxEnd = 0;
QVector<int> kids = childMap ? childMap->value(structId) : childrenOf(structId);
for (int ci : kids) {
const Node& c = nodes[ci];
int sz = (c.kind == NodeKind::Struct || c.kind == NodeKind::Array)
? structSpan(c.id, childMap) : c.byteSize();
int end = c.offset + sz;
if (end > maxEnd) maxEnd = end;
}
return maxEnd;
}
// Batch selection normalizers
QSet<uint64_t> normalizePreferAncestors(const QSet<uint64_t>& ids) const;
QSet<uint64_t> normalizePreferDescendants(const QSet<uint64_t>& ids) const;
QJsonObject toJson() const {
QJsonObject o;
o["baseAddress"] = QString::number(baseAddress, 16);
o["nextId"] = QString::number(m_nextId);
QJsonArray arr;
for (const auto& n : nodes) arr.append(n.toJson());
o["nodes"] = arr;
return o;
}
static NodeTree fromJson(const QJsonObject& o) {
NodeTree t;
t.baseAddress = o["baseAddress"].toString("400000").toULongLong(nullptr, 16);
t.m_nextId = o["nextId"].toString("1").toULongLong();
QJsonArray arr = o["nodes"].toArray();
for (const auto& v : arr) {
Node n = Node::fromJson(v.toObject());
t.nodes.append(n);
if (n.id >= t.m_nextId) t.m_nextId = n.id + 1;
}
return t;
}
};
// ── LineMeta ──
enum class LineKind : uint8_t {
Header, Field, Continuation, Footer
};
struct LineMeta {
int nodeIdx = -1;
uint64_t nodeId = 0;
int subLine = 0;
int depth = 0;
int foldLevel = 0;
bool foldHead = false;
bool foldCollapsed = false;
bool isContinuation = false;
LineKind lineKind = LineKind::Field;
NodeKind nodeKind = NodeKind::Int32;
QString offsetText;
uint32_t markerMask = 0;
};
// ── ComposeResult ──
struct ComposeResult {
QString text;
QVector<LineMeta> meta;
};
// ── Command ──
namespace cmd {
struct OffsetAdj { uint64_t nodeId; int oldOffset, newOffset; };
struct ChangeKind { uint64_t nodeId; NodeKind oldKind, newKind;
QVector<OffsetAdj> offAdjs; };
struct Rename { uint64_t nodeId; QString oldName, newName; };
struct Collapse { uint64_t nodeId; bool oldState, newState; };
struct Insert { Node node; };
struct Remove { uint64_t nodeId; QVector<Node> subtree; };
struct ChangeBase { uint64_t oldBase, newBase; };
struct WriteBytes { uint64_t addr; QByteArray oldBytes, newBytes; };
}
using Command = std::variant<
cmd::ChangeKind, cmd::Rename, cmd::Collapse,
cmd::Insert, cmd::Remove, cmd::ChangeBase, cmd::WriteBytes
>;
// ── Column spans (for inline editing) ──
struct ColumnSpan {
int start = 0; // inclusive column index
int end = 0; // exclusive column index
bool valid = false;
};
enum class EditTarget { Name, Type, Value };
// Column layout constants (shared with format.cpp span computation)
inline constexpr int kFoldCol = 3; // 3-char fold indicator prefix per line
inline constexpr int kColType = 10;
inline constexpr int kColName = 24;
inline constexpr int kSepWidth = 2;
inline ColumnSpan typeSpanFor(const LineMeta& lm) {
if (lm.lineKind != LineKind::Field || lm.isContinuation) return {};
int ind = kFoldCol + lm.depth * 3;
return {ind, ind + kColType, true};
}
inline ColumnSpan nameSpanFor(const LineMeta& lm) {
if (lm.isContinuation || lm.lineKind != LineKind::Field) return {};
// Hex/Padding nodes show ASCII data preview instead of name
switch (lm.nodeKind) {
case NodeKind::Hex8: case NodeKind::Hex16:
case NodeKind::Hex32: case NodeKind::Hex64:
case NodeKind::Padding:
return {};
default: break;
}
int ind = kFoldCol + lm.depth * 3;
int start = ind + kColType + kSepWidth;
return {start, start + kColName, true};
}
inline ColumnSpan valueSpanFor(const LineMeta& lm, int lineLength) {
if (lm.lineKind == LineKind::Header || lm.lineKind == LineKind::Footer) return {};
int ind = kFoldCol + lm.depth * 3;
if (lm.isContinuation) {
int prefixW = kColType + kColName + 4; // 2 seps × 2 chars
int start = ind + prefixW;
return {start, lineLength, start < lineLength};
}
if (lm.lineKind != LineKind::Field) return {};
int start = ind + kColType + kSepWidth + kColName + kSepWidth;
return {start, lineLength, start < lineLength};
}
// ── ViewState ──
struct ViewState {
int scrollLine = 0;
int cursorLine = 0;
int cursorCol = 0;
};
// ── Format function forward declarations ──
namespace fmt {
using TypeNameFn = QString (*)(NodeKind);
void setTypeNameProvider(TypeNameFn fn);
QString typeName(NodeKind kind);
QString fmtInt8(int8_t v);
QString fmtInt16(int16_t v);
QString fmtInt32(int32_t v);
QString fmtInt64(int64_t v);
QString fmtUInt8(uint8_t v);
QString fmtUInt16(uint16_t v);
QString fmtUInt32(uint32_t v);
QString fmtUInt64(uint64_t v);
QString fmtFloat(float v);
QString fmtDouble(double v);
QString fmtBool(uint8_t v);
QString fmtPointer32(uint32_t v);
QString fmtPointer64(uint64_t v);
QString fmtNodeLine(const Node& node, const Provider& prov,
uint64_t addr, int depth, int subLine = 0);
QString fmtOffsetMargin(int64_t relativeOffset, bool isContinuation);
QString fmtStructHeader(const Node& node, int depth);
QString fmtStructFooter(const Node& node, int depth, int totalSize = -1);
QString indent(int depth);
QString readValue(const Node& node, const Provider& prov,
uint64_t addr, int subLine);
QString editableValue(const Node& node, const Provider& prov,
uint64_t addr, int subLine);
QByteArray parseValue(NodeKind kind, const QString& text, bool* ok);
} // namespace fmt
// ── Compose function forward declaration ──
ComposeResult compose(const NodeTree& tree, const Provider& prov);
} // namespace rcx

982
src/editor.cpp Normal file
View File

@@ -0,0 +1,982 @@
#include "editor.h"
#include <Qsci/qsciscintilla.h>
#include <Qsci/qsciscintillabase.h>
#include <Qsci/qscilexercpp.h>
#include <QVBoxLayout>
#include <QFont>
#include <QColor>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QFocusEvent>
#include <QToolTip>
#include <QTimer>
#include <QCursor>
#include <QApplication>
namespace rcx {
// ── Theme constants ──
static const QColor kBgText("#1e1e1e");
static const QColor kBgMargin("#252526");
static const QColor kFgMargin("#858585");
static const QColor kFgMarginDim("#505050");
static constexpr int IND_EDITABLE = 8;
static constexpr int IND_HEX_DIM = 9;
static constexpr int IND_SELECTED = 10;
static constexpr int IND_HOVER = 11;
static QFont editorFont() {
QFont f("Consolas", 12);
f.setFixedPitch(true);
return f;
}
RcxEditor::RcxEditor(QWidget* parent) : QWidget(parent) {
auto* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
m_sci = new QsciScintilla(this);
layout->addWidget(m_sci);
setupScintilla();
setupLexer();
setupMargins();
setupFolding();
setupMarkers();
allocateMarginStyles();
m_sci->installEventFilter(this);
m_sci->viewport()->installEventFilter(this);
m_sci->viewport()->setMouseTracking(true);
// Hover cursor is applied synchronously in eventFilter (no timer).
connect(m_sci, &QsciScintilla::marginClicked,
this, [this](int margin, int line, Qt::KeyboardModifiers mods) {
emit marginClicked(margin, line, mods);
});
m_sci->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_sci, &QWidget::customContextMenuRequested,
this, [this](const QPoint& pos) {
int line = m_sci->lineAt(pos);
int nodeIdx = -1;
int subLine = 0;
if (line >= 0 && line < m_meta.size()) {
nodeIdx = m_meta[line].nodeIdx;
subLine = m_meta[line].subLine;
}
emit contextMenuRequested(line, nodeIdx, subLine, m_sci->mapToGlobal(pos));
});
connect(m_sci, &QsciScintilla::userListActivated,
this, [this](int id, const QString& text) {
if (id == 1 && m_editState.active && m_editState.target == EditTarget::Type) {
auto info = endInlineEdit();
emit inlineEditCommitted(info.nodeIdx, info.subLine, info.target, text);
}
});
connect(m_sci, &QsciScintilla::cursorPositionChanged,
this, [this](int line, int /*col*/) { updateEditableUnderline(line); });
}
void RcxEditor::setupScintilla() {
m_sci->setFont(editorFont());
m_sci->setReadOnly(true);
m_sci->setWrapMode(QsciScintilla::WrapNone);
m_sci->setCaretLineVisible(true);
m_sci->setCaretLineBackgroundColor(QColor("#2c3338"));
m_sci->setPaper(kBgText);
m_sci->setColor(QColor("#d4d4d4"));
m_sci->setTabWidth(2);
m_sci->setIndentationsUseTabs(false);
// Caret color for dark theme
m_sci->setCaretForegroundColor(QColor("#d4d4d4"));
// Line spacing for readability
m_sci->SendScintilla(QsciScintillaBase::SCI_SETEXTRAASCENT, (long)2);
m_sci->SendScintilla(QsciScintillaBase::SCI_SETEXTRADESCENT, (long)2);
// Selection colors
m_sci->setSelectionBackgroundColor(QColor("#264f78"));
m_sci->setSelectionForegroundColor(QColor("#d4d4d4"));
// Editable-field link-style indicator (colored text + underline)
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,
IND_EDITABLE, 17 /*INDIC_TEXTFORE*/);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETFORE,
IND_EDITABLE, QColor("#569cd6"));
// Hex/Padding node dim indicator — overrides text color to gray
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,
IND_HEX_DIM, 17 /*INDIC_TEXTFORE*/);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETFORE,
IND_HEX_DIM, QColor("#505050"));
// Selection overlay — translucent blue box
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,
IND_SELECTED, 8 /*INDIC_STRAIGHTBOX*/);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETFORE,
IND_SELECTED, QColor("#264f78"));
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETALPHA,
IND_SELECTED, (long)50);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETOUTLINEALPHA,
IND_SELECTED, (long)100);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETUNDER,
IND_SELECTED, (long)1);
// Hover row highlight — very subtle fill
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,
IND_HOVER, 16 /*INDIC_FULLBOX*/);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETFORE,
IND_HOVER, QColor("#264f78"));
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETALPHA,
IND_HOVER, (long)25);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETOUTLINEALPHA,
IND_HOVER, (long)0);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETUNDER,
IND_HOVER, (long)1);
}
void RcxEditor::setupLexer() {
m_lexer = new QsciLexerCPP(m_sci);
QFont font = editorFont();
m_lexer->setFont(font);
// Dark theme colors
m_lexer->setColor(QColor("#569cd6"), QsciLexerCPP::Keyword);
m_lexer->setColor(QColor("#4ec9b0"), QsciLexerCPP::KeywordSet2);
m_lexer->setColor(QColor("#b5cea8"), QsciLexerCPP::Number);
m_lexer->setColor(QColor("#ce9178"), QsciLexerCPP::DoubleQuotedString);
m_lexer->setColor(QColor("#ce9178"), QsciLexerCPP::SingleQuotedString);
m_lexer->setColor(QColor("#6a9955"), QsciLexerCPP::Comment);
m_lexer->setColor(QColor("#6a9955"), QsciLexerCPP::CommentLine);
m_lexer->setColor(QColor("#6a9955"), QsciLexerCPP::CommentDoc);
m_lexer->setColor(QColor("#d4d4d4"), QsciLexerCPP::Default);
m_lexer->setColor(QColor("#dcdcaa"), QsciLexerCPP::Identifier);
m_lexer->setColor(QColor("#c586c0"), QsciLexerCPP::PreProcessor);
m_lexer->setColor(QColor("#d4d4d4"), QsciLexerCPP::Operator);
// Dark background for all styles
for (int i = 0; i <= 127; i++) {
m_lexer->setPaper(kBgText, i);
m_lexer->setFont(font, i);
}
m_sci->setLexer(m_lexer);
m_sci->setBraceMatching(QsciScintilla::SloppyBraceMatch);
}
void RcxEditor::setupMargins() {
m_sci->setMarginsFont(editorFont());
// Margin 0: Offset text
m_sci->setMarginType(0, QsciScintilla::TextMarginRightJustified);
m_sci->setMarginWidth(0, " +0x00000000 ");
m_sci->setMarginsBackgroundColor(kBgMargin);
m_sci->setMarginsForegroundColor(kFgMargin);
m_sci->setMarginSensitivity(0, true);
// Margin 1: hidden (fold chevrons moved to text column)
m_sci->setMarginWidth(1, 0);
}
void RcxEditor::setupFolding() {
// Hide fold margin (fold indicators are text-based now)
m_sci->setMarginWidth(2, 0);
m_sci->setFoldMarginColors(kBgMargin, kBgMargin);
// Fold indicators are now text in the line content (kFoldCol prefix),
// so no Scintilla markers needed for fold state.
// Keep Scintilla fold markers invisible (fold levels still used for click detection)
for (int i = 25; i <= 31; i++)
m_sci->markerDefine(QsciScintilla::Invisible, i);
// Disable automatic fold toggle — we handle collapse at model level
m_sci->SendScintilla(QsciScintillaBase::SCI_SETAUTOMATICFOLD,
(unsigned long)0);
// Disable lexer-driven folding — we set fold levels manually
m_sci->SendScintilla(QsciScintillaBase::SCI_SETPROPERTY,
(const char*)"fold", (const char*)"0");
}
void RcxEditor::setupMarkers() {
// M_CONT (0): vertical line
m_sci->markerDefine(QsciScintilla::VLine, M_CONT);
m_sci->setMarkerBackgroundColor(kFgMarginDim, M_CONT);
m_sci->setMarkerForegroundColor(kFgMarginDim, M_CONT);
// M_PAD (1): small rectangle (dim gray)
m_sci->markerDefine(QsciScintilla::SmallRectangle, M_PAD);
m_sci->setMarkerBackgroundColor(QColor("#606060"), M_PAD);
m_sci->setMarkerForegroundColor(QColor("#606060"), M_PAD);
// M_PTR0 (2): right triangle (red)
m_sci->markerDefine(QsciScintilla::RightTriangle, M_PTR0);
m_sci->setMarkerBackgroundColor(QColor("#f44747"), M_PTR0);
m_sci->setMarkerForegroundColor(QColor("#f44747"), M_PTR0);
// M_CYCLE (3): arrows (orange)
m_sci->markerDefine(QsciScintilla::ThreeRightArrows, M_CYCLE);
m_sci->setMarkerBackgroundColor(QColor("#e5a00d"), M_CYCLE);
m_sci->setMarkerForegroundColor(QColor("#e5a00d"), M_CYCLE);
// M_ERR (4): background (dark red)
m_sci->markerDefine(QsciScintilla::Background, M_ERR);
m_sci->setMarkerBackgroundColor(QColor("#5c2020"), M_ERR);
m_sci->setMarkerForegroundColor(QColor("#ffffff"), M_ERR);
// M_STRUCT_BG (5): background tint for struct header/footer
m_sci->markerDefine(QsciScintilla::Background, M_STRUCT_BG);
m_sci->setMarkerBackgroundColor(QColor("#1a2332"), M_STRUCT_BG);
m_sci->setMarkerForegroundColor(QColor("#d4d4d4"), M_STRUCT_BG);
}
void RcxEditor::allocateMarginStyles() {
// Relative indices within margin style offset
static constexpr int MSTYLE_NORMAL = 0;
static constexpr int MSTYLE_CONT = 1;
long base = m_sci->SendScintilla(QsciScintillaBase::SCI_ALLOCATEEXTENDEDSTYLES, (long)2);
m_marginStyleBase = (int)base;
m_sci->SendScintilla(QsciScintillaBase::SCI_MARGINSETSTYLEOFFSET, base);
const long bgrMargin = 0x262525; // BGR for #252526
// Normal offset style: gray on dark
m_sci->SendScintilla(QsciScintillaBase::SCI_STYLESETFORE,
(unsigned long)(base + MSTYLE_NORMAL), (long)0x858585);
m_sci->SendScintilla(QsciScintillaBase::SCI_STYLESETBACK,
(unsigned long)(base + MSTYLE_NORMAL), bgrMargin);
// Continuation style: dimmer
m_sci->SendScintilla(QsciScintillaBase::SCI_STYLESETFORE,
(unsigned long)(base + MSTYLE_CONT), (long)0x505050);
m_sci->SendScintilla(QsciScintillaBase::SCI_STYLESETBACK,
(unsigned long)(base + MSTYLE_CONT), bgrMargin);
}
void RcxEditor::applyDocument(const ComposeResult& result) {
// Silently deactivate inline edit (no signal — refresh is already happening)
if (m_editState.active)
endInlineEdit();
m_meta = result.meta;
m_sci->setReadOnly(false);
m_sci->setText(result.text);
m_sci->setReadOnly(true);
// Force full re-lex to fix stale syntax coloring after edits
m_sci->SendScintilla(QsciScintillaBase::SCI_COLOURISE, (uintptr_t)0, (long)-1);
applyMarginText(result.meta);
applyMarkers(result.meta);
applyFoldLevels(result.meta);
applyHexDimming(result.meta);
// Re-apply editable underline for current cursor line
m_hintLine = -1;
int line, col;
m_sci->getCursorPosition(&line, &col);
updateEditableUnderline(line);
}
void RcxEditor::applyMarginText(const QVector<LineMeta>& meta) {
// Clear all margin text
m_sci->clearMarginText(-1);
for (int i = 0; i < meta.size(); i++) {
const auto& lm = meta[i];
if (!lm.offsetText.isEmpty()) {
int style = lm.isContinuation ? 1 : 0;
m_sci->setMarginText(i, lm.offsetText, style);
}
}
}
void RcxEditor::applyMarkers(const QVector<LineMeta>& meta) {
for (int m = M_CONT; m <= M_STRUCT_BG; m++) {
m_sci->markerDeleteAll(m);
}
for (int i = 0; i < meta.size(); i++) {
uint32_t mask = meta[i].markerMask;
for (int m = M_CONT; m <= M_STRUCT_BG; m++) {
if (mask & (1u << m)) {
m_sci->markerAdd(i, m);
}
}
}
}
void RcxEditor::applyFoldLevels(const QVector<LineMeta>& meta) {
for (int i = 0; i < meta.size(); i++) {
m_sci->SendScintilla(QsciScintillaBase::SCI_SETFOLDLEVEL,
(unsigned long)i, (long)meta[i].foldLevel);
}
}
void RcxEditor::applyHexDimming(const QVector<LineMeta>& meta) {
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_HEX_DIM);
for (int i = 0; i < meta.size(); i++) {
switch (meta[i].nodeKind) {
case NodeKind::Hex8: case NodeKind::Hex16:
case NodeKind::Hex32: case NodeKind::Hex64:
case NodeKind::Padding: {
long pos = m_sci->SendScintilla(
QsciScintillaBase::SCI_POSITIONFROMLINE, (unsigned long)i);
long len = m_sci->SendScintilla(
QsciScintillaBase::SCI_LINELENGTH, (unsigned long)i);
if (len > 0)
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE, pos, len);
break;
}
default: break;
}
}
}
void RcxEditor::applySelectionOverlay(const QSet<uint64_t>& selIds) {
m_currentSelIds = selIds;
// Clear all selection indicators
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_SELECTED);
long docLen = m_sci->SendScintilla(QsciScintillaBase::SCI_GETLENGTH);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORCLEARRANGE, (uintptr_t)0, docLen);
if (selIds.isEmpty()) return;
for (int i = 0; i < m_meta.size(); i++) {
if (selIds.contains(m_meta[i].nodeId)) {
long pos = m_sci->SendScintilla(
QsciScintillaBase::SCI_POSITIONFROMLINE, (unsigned long)i);
long len = m_sci->SendScintilla(
QsciScintillaBase::SCI_LINELENGTH, (unsigned long)i);
if (len > 0)
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE, pos, len);
}
}
// Refresh hover since selection may suppress it
applyHoverHighlight();
}
void RcxEditor::applyHoverHighlight() {
// Clear previous hover indicator
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_HOVER);
long docLen = m_sci->SendScintilla(QsciScintillaBase::SCI_GETLENGTH);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORCLEARRANGE, (uintptr_t)0, docLen);
if (m_editState.active) return;
if (!m_hoverInside) return;
if (m_hoveredNodeId == 0) return;
if (m_currentSelIds.contains(m_hoveredNodeId)) return;
for (int i = 0; i < m_meta.size(); i++) {
if (m_meta[i].nodeId == m_hoveredNodeId) {
long pos = m_sci->SendScintilla(
QsciScintillaBase::SCI_POSITIONFROMLINE, (unsigned long)i);
long len = m_sci->SendScintilla(
QsciScintillaBase::SCI_LINELENGTH, (unsigned long)i);
if (len > 0)
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE, pos, len);
}
}
}
ViewState RcxEditor::saveViewState() const {
ViewState vs;
vs.scrollLine = (int)m_sci->SendScintilla(QsciScintillaBase::SCI_GETFIRSTVISIBLELINE);
int line, col;
m_sci->getCursorPosition(&line, &col);
vs.cursorLine = line;
vs.cursorCol = col;
return vs;
}
void RcxEditor::restoreViewState(const ViewState& vs) {
m_sci->setCursorPosition(vs.cursorLine, vs.cursorCol);
m_sci->SendScintilla(QsciScintillaBase::SCI_SETFIRSTVISIBLELINE,
(unsigned long)vs.scrollLine);
}
const LineMeta* RcxEditor::metaForLine(int line) const {
if (line >= 0 && line < m_meta.size())
return &m_meta[line];
return nullptr;
}
int RcxEditor::currentNodeIndex() const {
int line, col;
m_sci->getCursorPosition(&line, &col);
auto* lm = metaForLine(line);
return lm ? lm->nodeIdx : -1;
}
// ── Column span computation ──
ColumnSpan RcxEditor::typeSpan(const LineMeta& lm) { return typeSpanFor(lm); }
ColumnSpan RcxEditor::nameSpan(const LineMeta& lm) { return nameSpanFor(lm); }
ColumnSpan RcxEditor::valueSpan(const LineMeta& lm, int lineLength) { return valueSpanFor(lm, lineLength); }
// ── Multi-selection ──
QSet<int> RcxEditor::selectedNodeIndices() const {
int lineFrom, indexFrom, lineTo, indexTo;
m_sci->getSelection(&lineFrom, &indexFrom, &lineTo, &indexTo);
if (lineFrom < 0) {
int line, col;
m_sci->getCursorPosition(&line, &col);
auto* lm = metaForLine(line);
return lm && lm->nodeIdx >= 0 ? QSet<int>{lm->nodeIdx} : QSet<int>{};
}
QSet<int> result;
for (int line = lineFrom; line <= lineTo; line++) {
auto* lm = metaForLine(line);
if (lm && lm->nodeIdx >= 0) result.insert(lm->nodeIdx);
}
return result;
}
// ── Inline edit helpers ──
static QString getLineText(QsciScintilla* sci, int line) {
int len = (int)sci->SendScintilla(QsciScintillaBase::SCI_LINELENGTH, (unsigned long)line);
if (len <= 0) return {};
QByteArray buf(len + 1, '\0');
sci->SendScintilla(QsciScintillaBase::SCI_GETLINE, (unsigned long)line, (void*)buf.data());
QString text = QString::fromUtf8(buf.data(), len);
while (text.endsWith('\n') || text.endsWith('\r'))
text.chop(1);
return text;
}
// ── Shared inline-edit shutdown ──
RcxEditor::EndEditInfo RcxEditor::endInlineEdit() {
EndEditInfo info{m_editState.nodeIdx, m_editState.subLine, m_editState.target};
m_editState.active = false;
m_sci->setReadOnly(true);
m_sci->SendScintilla(QsciScintillaBase::SCI_SETUNDOCOLLECTION, (long)1);
m_sci->SendScintilla(QsciScintillaBase::SCI_EMPTYUNDOBUFFER);
return info;
}
// ── Span helpers ──
static ColumnSpan headerNameSpan(const LineMeta& lm, const QString& lineText) {
if (lm.lineKind != LineKind::Header) return {};
int bracePos = lineText.lastIndexOf(QStringLiteral(" {"));
if (bracePos <= 0) return {};
int ind = kFoldCol + lm.depth * 3;
int typeEnd = lineText.indexOf(' ', ind);
if (typeEnd <= ind || typeEnd >= bracePos) return {};
return {typeEnd + 1, bracePos, true};
}
RcxEditor::NormalizedSpan RcxEditor::normalizeSpan(
const ColumnSpan& raw, const QString& lineText,
EditTarget target, bool skipPrefixes) const
{
if (!raw.valid) return {};
int textLen = lineText.size();
if (raw.start >= textLen) return {};
int start = raw.start;
int end = qMin(raw.end, textLen);
if (end <= start) return {};
if (skipPrefixes && target == EditTarget::Value) {
QString spanText = lineText.mid(start, end - start);
int arrow = spanText.indexOf(QStringLiteral("->"));
if (arrow >= 0) {
int i = arrow + 2;
while (i < spanText.size() && spanText[i].isSpace()) i++;
start += i;
} else {
int eq = spanText.indexOf('=');
if (eq >= 0 && eq <= 3) {
int i = eq + 1;
while (i < spanText.size() && spanText[i].isSpace()) i++;
start += i;
}
}
if (start >= end) return {};
}
QString inner = lineText.mid(start, end - start);
int lead = 0;
while (lead < inner.size() && inner[lead].isSpace()) lead++;
int trail = inner.size();
while (trail > lead && inner[trail - 1].isSpace()) trail--;
if (trail <= lead) return {};
return {start + lead, start + trail, true};
}
// ── Double-click hit test ──
static bool hitTestTarget(QsciScintilla* sci,
const QVector<LineMeta>& meta,
const QPoint& viewportPos,
int& outLine, EditTarget& outTarget)
{
long pos = sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMPOINTCLOSE,
(unsigned long)viewportPos.x(), (long)viewportPos.y());
if (pos < 0) return false;
int line = (int)sci->SendScintilla(QsciScintillaBase::SCI_LINEFROMPOSITION,
(unsigned long)pos);
int col = (int)sci->SendScintilla(QsciScintillaBase::SCI_GETCOLUMN,
(unsigned long)pos);
if (line < 0 || line >= meta.size()) return false;
QString lineText = getLineText(sci, line);
int textLen = lineText.size();
const LineMeta& lm = meta[line];
ColumnSpan ts = RcxEditor::typeSpan(lm);
ColumnSpan ns = RcxEditor::nameSpan(lm);
ColumnSpan vs = RcxEditor::valueSpan(lm, textLen);
if (!ns.valid)
ns = headerNameSpan(lm, lineText);
auto inSpan = [&](const ColumnSpan& s) {
return s.valid && col >= s.start && col < s.end;
};
if (inSpan(ts)) outTarget = EditTarget::Type;
else if (inSpan(ns)) outTarget = EditTarget::Name;
else if (inSpan(vs)) outTarget = EditTarget::Value;
else return false;
outLine = line;
return true;
}
// ── Event filter ──
bool RcxEditor::eventFilter(QObject* obj, QEvent* event) {
if (obj == m_sci && event->type() == QEvent::KeyPress) {
auto* ke = static_cast<QKeyEvent*>(event);
return m_editState.active ? handleEditKey(ke) : handleNormalKey(ke);
}
if (obj == m_sci->viewport() && event->type() == QEvent::MouseButtonPress
&& m_editState.active) {
// Only commit if click is outside the active edit span
auto* me = static_cast<QMouseEvent*>(event);
long pos = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMPOINTCLOSE,
(unsigned long)me->pos().x(), (long)me->pos().y());
bool insideEdit = false;
if (pos >= 0) {
int clickLine = (int)m_sci->SendScintilla(
QsciScintillaBase::SCI_LINEFROMPOSITION, (unsigned long)pos);
int clickCol = (int)m_sci->SendScintilla(
QsciScintillaBase::SCI_GETCOLUMN, (unsigned long)pos);
if (clickLine == m_editState.line) {
QString lineText = getLineText(m_sci, m_editState.line);
int delta = lineText.size() - m_editState.linelenAfterReplace;
int editEnd = m_editState.spanStart + m_editState.original.size() + delta;
insideEdit = (clickCol >= m_editState.spanStart && clickCol < editEnd);
}
}
if (!insideEdit)
commitInlineEdit();
return false; // always let click through to Scintilla
}
// Single-click on fold column (" - " / " + ") toggles fold
// Other left-clicks emit nodeClicked for selection
if (obj == m_sci->viewport() && !m_editState.active
&& event->type() == QEvent::MouseButtonPress) {
auto* me = static_cast<QMouseEvent*>(event);
if (me->button() == Qt::LeftButton) {
long pos = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMPOINTCLOSE,
(unsigned long)me->pos().x(), (long)me->pos().y());
if (pos >= 0) {
int line = (int)m_sci->SendScintilla(
QsciScintillaBase::SCI_LINEFROMPOSITION, (unsigned long)pos);
int col = (int)m_sci->SendScintilla(
QsciScintillaBase::SCI_GETCOLUMN, (unsigned long)pos);
if (col < kFoldCol && line >= 0 && line < m_meta.size()
&& m_meta[line].foldHead) {
emit marginClicked(0, line, me->modifiers());
return true;
}
// Selection click — emit for controller to manage
if (line >= 0 && line < m_meta.size()) {
uint64_t nid = m_meta[line].nodeId;
if (nid != 0)
emit nodeClicked(line, nid, me->modifiers());
}
}
}
}
if (obj == m_sci->viewport() && !m_editState.active
&& event->type() == QEvent::MouseButtonDblClick) {
auto* me = static_cast<QMouseEvent*>(event);
int line; EditTarget t;
if (hitTestTarget(m_sci, m_meta, me->pos(), line, t))
return beginInlineEdit(t, line);
}
if (obj == m_sci && event->type() == QEvent::FocusOut) {
auto* fe = static_cast<QFocusEvent*>(event);
// Commit active edit on focus loss (click-away = save)
// Deferred so autocomplete popup has time to register as active
if (m_editState.active && fe->reason() != Qt::PopupFocusReason) {
QTimer::singleShot(0, this, [this]() {
if (m_editState.active && !m_sci->hasFocus()
&& !m_sci->SendScintilla(QsciScintillaBase::SCI_AUTOCACTIVE))
commitInlineEdit();
});
}
// Clear underlines when editor loses focus
if (m_hintLine >= 0) {
long start = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE, (unsigned long)m_hintLine);
long len = m_sci->SendScintilla(QsciScintillaBase::SCI_LINELENGTH, (unsigned long)m_hintLine);
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_EDITABLE);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORCLEARRANGE, start, len);
m_hintLine = -1;
}
}
if (obj == m_sci && event->type() == QEvent::FocusIn) {
int line, col;
m_sci->getCursorPosition(&line, &col);
updateEditableUnderline(line);
}
if (obj == m_sci->viewport() && !m_editState.active) {
if (event->type() == QEvent::MouseMove) {
m_lastHoverPos = static_cast<QMouseEvent*>(event)->pos();
m_hoverInside = true;
} else if (event->type() == QEvent::Leave) {
m_hoverInside = false;
m_hoveredNodeId = 0;
applyHoverHighlight();
} else if (event->type() == QEvent::Wheel) {
m_lastHoverPos = m_sci->viewport()->mapFromGlobal(QCursor::pos());
m_hoverInside = m_sci->viewport()->rect().contains(m_lastHoverPos);
}
// Resolve hovered nodeId on move/wheel
if (event->type() == QEvent::MouseMove
|| event->type() == QEvent::Wheel) {
long pos = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMPOINTCLOSE,
(unsigned long)m_lastHoverPos.x(),
(long)m_lastHoverPos.y());
uint64_t newHoverId = 0;
if (pos >= 0 && m_hoverInside) {
int hLine = (int)m_sci->SendScintilla(
QsciScintillaBase::SCI_LINEFROMPOSITION, (unsigned long)pos);
if (hLine >= 0 && hLine < m_meta.size())
newHoverId = m_meta[hLine].nodeId;
}
if (newHoverId != m_hoveredNodeId) {
m_hoveredNodeId = newHoverId;
applyHoverHighlight();
}
}
if (event->type() == QEvent::MouseMove
|| event->type() == QEvent::Leave
|| event->type() == QEvent::Wheel)
applyHoverCursor();
}
return QWidget::eventFilter(obj, event);
}
// ── Normal mode key handling ──
bool RcxEditor::handleNormalKey(QKeyEvent* ke) {
switch (ke->key()) {
case Qt::Key_F2:
return beginInlineEdit(EditTarget::Name);
case Qt::Key_T:
if (ke->modifiers() == Qt::NoModifier)
return beginInlineEdit(EditTarget::Type);
return false;
case Qt::Key_Return:
case Qt::Key_Enter:
return beginInlineEdit(EditTarget::Value);
default:
return false;
}
}
// ── Edit mode key handling ──
bool RcxEditor::handleEditKey(QKeyEvent* ke) {
bool autocActive = m_sci->SendScintilla(QsciScintillaBase::SCI_AUTOCACTIVE);
switch (ke->key()) {
case Qt::Key_Return:
case Qt::Key_Enter:
case Qt::Key_Tab:
if (autocActive) {
if (m_editState.target == EditTarget::Type) {
// Extract selected typeName directly from autocomplete
QByteArray buf(256, '\0');
m_sci->SendScintilla(QsciScintillaBase::SCI_AUTOCGETCURRENTTEXT,
(unsigned long)256, (void*)buf.data());
QString selectedType = QString::fromUtf8(buf.constData());
m_sci->SendScintilla(QsciScintillaBase::SCI_AUTOCCANCEL);
auto info = endInlineEdit();
emit inlineEditCommitted(info.nodeIdx, info.subLine, EditTarget::Type, selectedType);
return true;
}
// Other targets: let Scintilla complete, then auto-commit
QTimer::singleShot(0, this, &RcxEditor::commitInlineEdit);
return false;
}
commitInlineEdit();
return true;
case Qt::Key_Escape:
if (autocActive) {
m_sci->SendScintilla(QsciScintillaBase::SCI_AUTOCCANCEL);
return true; // close popup, stay in edit mode
}
cancelInlineEdit();
return true;
case Qt::Key_Up:
case Qt::Key_Down:
case Qt::Key_PageUp:
case Qt::Key_PageDown:
if (autocActive) return false; // let Scintilla navigate list
return true; // block line navigation
case Qt::Key_Delete:
return true; // block to prevent eating trailing content
case Qt::Key_Left:
case Qt::Key_Backspace: {
int line, col;
m_sci->getCursorPosition(&line, &col);
if (col <= m_editState.spanStart) return true;
return false;
}
case Qt::Key_Home:
m_sci->setCursorPosition(m_editState.line, m_editState.spanStart);
return true;
default:
return false;
}
}
// ── Begin inline edit ──
bool RcxEditor::beginInlineEdit(EditTarget target, int line) {
if (m_editState.active) return false;
if (m_cursorOverridden) {
QApplication::restoreOverrideCursor();
m_cursorOverridden = false;
}
m_hoveredNodeId = 0;
applyHoverHighlight();
if (line >= 0) {
m_sci->setCursorPosition(line, 0);
}
int col;
m_sci->getCursorPosition(&line, &col);
auto* lm = metaForLine(line);
if (!lm || lm->nodeIdx < 0) return false;
QString lineText = getLineText(m_sci, line);
int textLen = lineText.size();
ColumnSpan span;
switch (target) {
case EditTarget::Type: span = typeSpan(*lm); break;
case EditTarget::Name: span = nameSpan(*lm); break;
case EditTarget::Value: span = valueSpan(*lm, textLen); break;
}
if (!span.valid && target == EditTarget::Name)
span = headerNameSpan(*lm, lineText);
auto norm = normalizeSpan(span, lineText, target, /*skipPrefixes=*/true);
if (!norm.valid) return false;
QString trimmed = lineText.mid(norm.start, norm.end - norm.start);
m_editState.active = true;
m_editState.line = line;
m_editState.nodeIdx = lm->nodeIdx;
m_editState.subLine = lm->subLine;
m_editState.target = target;
m_editState.spanStart = norm.start;
m_editState.original = trimmed;
m_editState.linelenAfterReplace = textLen;
// Disable Scintilla undo during inline edit
m_sci->SendScintilla(QsciScintillaBase::SCI_SETUNDOCOLLECTION, (long)0);
m_sci->setReadOnly(false);
// Select just the trimmed text (keeps columns aligned)
long lineStart = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE,
(unsigned long)line);
long posSelStart = lineStart + m_editState.spanStart;
long posSelEnd = posSelStart + trimmed.toUtf8().size();
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSEL, posSelStart, posSelEnd);
if (target == EditTarget::Type)
QTimer::singleShot(0, this, &RcxEditor::showTypeAutocomplete);
return true;
}
// ── Commit inline edit ──
void RcxEditor::commitInlineEdit() {
if (!m_editState.active) return;
QString lineText = getLineText(m_sci, m_editState.line);
int currentLen = lineText.size();
int delta = currentLen - m_editState.linelenAfterReplace;
int editedLen = m_editState.original.size() + delta;
QString editedText;
if (editedLen > 0)
editedText = lineText.mid(m_editState.spanStart, editedLen).trimmed();
auto info = endInlineEdit();
emit inlineEditCommitted(info.nodeIdx, info.subLine, info.target, editedText);
}
// ── Cancel inline edit ──
void RcxEditor::cancelInlineEdit() {
if (!m_editState.active) return;
endInlineEdit();
emit inlineEditCancelled();
}
// ── Type autocomplete ──
void RcxEditor::showTypeAutocomplete() {
if (!m_editState.active || m_editState.target != EditTarget::Type)
return;
// Collapse selection to start — old type text stays visible
long lineStart = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE,
(unsigned long)m_editState.line);
long posStart = lineStart + m_editState.spanStart;
m_sci->SendScintilla(QsciScintillaBase::SCI_GOTOPOS, posStart);
// Build list from typeName (matches what the editor displays)
QStringList types;
for (const auto& m : kKindMeta)
types << m.typeName;
types.sort(Qt::CaseInsensitive);
QByteArray list = types.join(QChar(' ')).toUtf8();
m_sci->SendScintilla(QsciScintillaBase::SCI_AUTOCSETSEPARATOR, (long)' ');
m_sci->SendScintilla(QsciScintillaBase::SCI_AUTOCSETIGNORECASE, (long)1);
m_sci->SendScintilla(QsciScintillaBase::SCI_AUTOCSETDROPRESTOFWORD, (long)1);
m_sci->SendScintilla(QsciScintillaBase::SCI_AUTOCSHOW,
(uintptr_t)0, list.constData());
// Highlight the current type in the list
QByteArray cur = m_editState.original.toUtf8();
m_sci->SendScintilla(QsciScintillaBase::SCI_AUTOCSELECT,
(uintptr_t)0, cur.constData());
long pos = m_sci->SendScintilla(QsciScintillaBase::SCI_GETCURRENTPOS);
int x = (int)m_sci->SendScintilla(QsciScintillaBase::SCI_POINTXFROMPOSITION, 0, pos);
int y = (int)m_sci->SendScintilla(QsciScintillaBase::SCI_POINTYFROMPOSITION, 0, pos);
QToolTip::showText(
m_sci->viewport()->mapToGlobal(QPoint(x, y + 20)),
QStringLiteral("Type to filter \u2022 \u2191/\u2193 select \u2022 Enter apply \u2022 Esc cancel"),
m_sci);
}
// ── Editable-field underline indicator ──
void RcxEditor::updateEditableUnderline(int line) {
if (m_editState.active) return;
if (line == m_hintLine) return;
auto clearLine = [&](int l) {
if (l < 0) return;
long start = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE, (unsigned long)l);
long len = m_sci->SendScintilla(QsciScintillaBase::SCI_LINELENGTH, (unsigned long)l);
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_EDITABLE);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORCLEARRANGE, start, len);
};
clearLine(m_hintLine);
m_hintLine = line;
const LineMeta* lm = metaForLine(line);
if (!lm || lm->nodeIdx < 0) return;
QString lineText = getLineText(m_sci, line);
int textLen = lineText.size();
ColumnSpan ts = typeSpan(*lm);
ColumnSpan ns = nameSpan(*lm);
ColumnSpan vs = valueSpan(*lm, textLen);
if (!ns.valid)
ns = headerNameSpan(*lm, lineText);
auto underlineSpan = [&](ColumnSpan s, EditTarget tgt) {
auto norm = normalizeSpan(s, lineText, tgt, /*skipPrefixes=*/true);
if (!norm.valid) return;
long lineStart = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE, (unsigned long)line);
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_EDITABLE);
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE,
lineStart + norm.start, norm.end - norm.start);
};
underlineSpan(ts, EditTarget::Type);
underlineSpan(ns, EditTarget::Name);
underlineSpan(vs, EditTarget::Value);
}
// ── Hover cursor (coalesced) ──
void RcxEditor::applyHoverCursor() {
if (m_editState.active || !m_hoverInside
|| !m_sci->viewport()->underMouse()) {
if (m_cursorOverridden) {
QApplication::restoreOverrideCursor();
m_cursorOverridden = false;
}
return;
}
int line; EditTarget t;
bool interactive = hitTestTarget(m_sci, m_meta, m_lastHoverPos, line, t);
// Also show pointer cursor for fold column on fold-head lines
if (!interactive) {
long pos = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMPOINTCLOSE,
(unsigned long)m_lastHoverPos.x(),
(long)m_lastHoverPos.y());
if (pos >= 0) {
int hLine = (int)m_sci->SendScintilla(
QsciScintillaBase::SCI_LINEFROMPOSITION, (unsigned long)pos);
int hCol = (int)m_sci->SendScintilla(
QsciScintillaBase::SCI_GETCOLUMN, (unsigned long)pos);
if (hCol < kFoldCol && hLine >= 0 && hLine < m_meta.size()
&& m_meta[hLine].foldHead)
interactive = true;
}
}
if (interactive && !m_cursorOverridden) {
QApplication::setOverrideCursor(Qt::PointingHandCursor);
m_cursorOverridden = true;
} else if (!interactive && m_cursorOverridden) {
QApplication::restoreOverrideCursor();
m_cursorOverridden = false;
}
}
} // namespace rcx

109
src/editor.h Normal file
View File

@@ -0,0 +1,109 @@
#pragma once
#include "core.h"
#include <QWidget>
#include <QSet>
#include <QPoint>
class QsciScintilla;
class QsciLexerCPP;
namespace rcx {
class RcxEditor : public QWidget {
Q_OBJECT
public:
explicit RcxEditor(QWidget* parent = nullptr);
void applyDocument(const ComposeResult& result);
ViewState saveViewState() const;
void restoreViewState(const ViewState& vs);
QsciScintilla* scintilla() const { return m_sci; }
const LineMeta* metaForLine(int line) const;
int currentNodeIndex() const;
// ── Column span computation ──
static ColumnSpan typeSpan(const LineMeta& lm);
static ColumnSpan nameSpan(const LineMeta& lm);
static ColumnSpan valueSpan(const LineMeta& lm, int lineLength);
// ── Multi-selection ──
QSet<int> selectedNodeIndices() const;
// ── Inline editing ──
bool isEditing() const { return m_editState.active; }
bool beginInlineEdit(EditTarget target, int line = -1);
void cancelInlineEdit();
void applySelectionOverlay(const QSet<uint64_t>& selIds);
signals:
void marginClicked(int margin, int line, Qt::KeyboardModifiers mods);
void contextMenuRequested(int line, int nodeIdx, int subLine, QPoint globalPos);
void nodeClicked(int line, uint64_t nodeId, Qt::KeyboardModifiers mods);
void inlineEditCommitted(int nodeIdx, int subLine,
EditTarget target, const QString& text);
void inlineEditCancelled();
protected:
bool eventFilter(QObject* obj, QEvent* event) override;
private:
QsciScintilla* m_sci = nullptr;
QsciLexerCPP* m_lexer = nullptr;
QVector<LineMeta> m_meta;
int m_marginStyleBase = -1;
int m_hintLine = -1;
// ── Hover cursor + highlight ──
QPoint m_lastHoverPos;
bool m_hoverInside = false;
bool m_cursorOverridden = false;
uint64_t m_hoveredNodeId = 0;
QSet<uint64_t> m_currentSelIds;
// ── Inline edit state ──
struct InlineEditState {
bool active = false;
int line = -1;
int nodeIdx = -1;
int subLine = 0;
EditTarget target = EditTarget::Name;
int spanStart = 0;
int linelenAfterReplace = 0;
QString original;
};
InlineEditState m_editState;
void setupScintilla();
void setupLexer();
void setupMargins();
void setupFolding();
void setupMarkers();
void allocateMarginStyles();
void applyMarginText(const QVector<LineMeta>& meta);
void applyMarkers(const QVector<LineMeta>& meta);
void applyFoldLevels(const QVector<LineMeta>& meta);
void applyHexDimming(const QVector<LineMeta>& meta);
void commitInlineEdit();
bool handleNormalKey(QKeyEvent* ke);
bool handleEditKey(QKeyEvent* ke);
void showTypeAutocomplete();
void updateEditableUnderline(int line);
void applyHoverCursor();
void applyHoverHighlight();
// ── Refactored helpers ──
struct EndEditInfo { int nodeIdx; int subLine; EditTarget target; };
EndEditInfo endInlineEdit();
struct NormalizedSpan { int start = 0; int end = 0; bool valid = false; };
NormalizedSpan normalizeSpan(const ColumnSpan& raw, const QString& lineText,
EditTarget target, bool skipPrefixes) const;
};
} // namespace rcx

364
src/format.cpp Normal file
View File

@@ -0,0 +1,364 @@
#include "core.h"
#include <cstring>
#include <limits>
namespace rcx::fmt {
// ── Column layout ──
// COL_TYPE and COL_NAME use shared constants from core.h (kColType, kColName)
static constexpr int COL_TYPE = kColType;
static constexpr int COL_NAME = kColName;
static constexpr int COL_VALUE = 22;
static const QString SEP = QStringLiteral(" ");
static QString fit(QString s, int w) {
if (w <= 0) return {};
if (s.size() > w) {
if (w >= 2) s = s.left(w - 1) + QChar(0x2026); // ellipsis
else s = s.left(w);
}
return s.leftJustified(w, ' ');
}
// ── Type name ──
// Override seam: injectable type-name provider
static TypeNameFn g_typeNameFn = nullptr;
void setTypeNameProvider(TypeNameFn fn) { g_typeNameFn = fn; }
QString typeName(NodeKind kind) {
if (g_typeNameFn) return fit(g_typeNameFn(kind), COL_TYPE);
auto* m = kindMeta(kind);
return fit(m ? QString::fromLatin1(m->typeName) : QStringLiteral("???"), COL_TYPE);
}
// ── Value formatting ──
static QString hexStr(uint64_t v, int digits) {
return QStringLiteral("0x") + QString::number(v, 16).toUpper().rightJustified(digits, '0');
}
static QString rawHex(uint64_t v, int digits) {
return QString::number(v, 16).toUpper().rightJustified(digits, '0');
}
QString fmtInt8(int8_t v) { return QString::number(v); }
QString fmtInt16(int16_t v) { return QString::number(v); }
QString fmtInt32(int32_t v) { return QString::number(v); }
QString fmtInt64(int64_t v) { return QString::number(v); }
QString fmtUInt8(uint8_t v) { return QString::number(v); }
QString fmtUInt16(uint16_t v) { return QString::number(v); }
QString fmtUInt32(uint32_t v) { return QString::number(v); }
QString fmtUInt64(uint64_t v) { return QString::number(v); }
QString fmtFloat(float v) { return QString::number(v, 'f', 3); }
QString fmtDouble(double v) { return QString::number(v, 'f', 6); }
QString fmtBool(uint8_t v) { return v ? QStringLiteral("true") : QStringLiteral("false"); }
QString fmtPointer32(uint32_t v) {
if (v == 0) return QStringLiteral("-> NULL");
return QStringLiteral("-> ") + hexStr(v, 8);
}
QString fmtPointer64(uint64_t v) {
if (v == 0) return QStringLiteral("-> NULL");
return QStringLiteral("-> ") + hexStr(v, 16);
}
// ── Indentation ──
QString indent(int depth) {
return QString(depth * 3, ' ');
}
// ── Offset margin ──
QString fmtOffsetMargin(int64_t relativeOffset, bool isContinuation) {
if (isContinuation) return QStringLiteral(" \u00B7");
return QStringLiteral("+0x") + QString::number(relativeOffset, 16).toUpper();
}
// ── Struct header / footer ──
QString fmtStructHeader(const Node& node, int depth) {
return indent(depth) + typeName(node.kind).trimmed() +
QStringLiteral(" ") + node.name + QStringLiteral(" {");
}
QString fmtStructFooter(const Node& node, int depth, int totalSize) {
QString s = indent(depth) + QStringLiteral("}; // ") + node.name;
if (totalSize > 0)
s += QStringLiteral(" sizeof=0x") + QString::number(totalSize, 16).toUpper();
return s;
}
// ── Hex / ASCII preview ──
static inline bool isAsciiPrintable(uint8_t c) { return c >= 0x20 && c <= 0x7E; }
static QString bytesToAscii(const QByteArray& b, int slot) {
QString out;
out.reserve(slot);
for (int i = 0; i < slot; ++i) {
uint8_t c = (i < b.size()) ? (uint8_t)b[i] : 0;
out += isAsciiPrintable(c) ? QChar(c) : QChar('.');
}
return out;
}
static QString bytesToHex(const QByteArray& b, int slot) {
QString out;
out.reserve(slot * 3);
for (int i = 0; i < slot; ++i) {
uint8_t c = (i < b.size()) ? (uint8_t)b[i] : 0;
out += QString::asprintf("%02X", (unsigned)c);
if (i + 1 < slot) out += ' ';
}
return out;
}
static QString fmtAsciiAndBytes(const Provider& prov, uint64_t addr,
int sizeBytes, int slotBytes = 8) {
const int slot = qMax(slotBytes, sizeBytes);
QByteArray b = prov.isReadable(addr, slot)
? prov.readBytes(addr, slot)
: QByteArray(slot, '\0');
return bytesToAscii(b, slot) + QStringLiteral(" ") + bytesToHex(b, slot);
}
// ── Single value from provider (unified) ──
enum class ValueMode { Display, Editable };
static QString readValueImpl(const Node& node, const Provider& prov,
uint64_t addr, int subLine, ValueMode mode) {
const bool display = (mode == ValueMode::Display);
switch (node.kind) {
case NodeKind::Hex8: return display ? hexStr(prov.readU8(addr), 2) : rawHex(prov.readU8(addr), 2);
case NodeKind::Hex16: return display ? hexStr(prov.readU16(addr), 4) : rawHex(prov.readU16(addr), 4);
case NodeKind::Hex32: return display ? hexStr(prov.readU32(addr), 8) : rawHex(prov.readU32(addr), 8);
case NodeKind::Hex64: return display ? hexStr(prov.readU64(addr), 16): rawHex(prov.readU64(addr), 16);
case NodeKind::Int8: return fmtInt8((int8_t)prov.readU8(addr));
case NodeKind::Int16: return fmtInt16((int16_t)prov.readU16(addr));
case NodeKind::Int32: return fmtInt32((int32_t)prov.readU32(addr));
case NodeKind::Int64: return fmtInt64((int64_t)prov.readU64(addr));
case NodeKind::UInt8: return fmtUInt8(prov.readU8(addr));
case NodeKind::UInt16: return fmtUInt16(prov.readU16(addr));
case NodeKind::UInt32: return fmtUInt32(prov.readU32(addr));
case NodeKind::UInt64: return fmtUInt64(prov.readU64(addr));
case NodeKind::Float: { auto s = fmtFloat(prov.readF32(addr)); return display ? s : s.trimmed(); }
case NodeKind::Double: { auto s = fmtDouble(prov.readF64(addr)); return display ? s : s.trimmed(); }
case NodeKind::Bool: return fmtBool(prov.readU8(addr));
case NodeKind::Pointer32: return display ? fmtPointer32(prov.readU32(addr)) : rawHex(prov.readU32(addr), 8);
case NodeKind::Pointer64: return display ? fmtPointer64(prov.readU64(addr)) : rawHex(prov.readU64(addr), 16);
case NodeKind::Vec2:
case NodeKind::Vec3:
case NodeKind::Vec4: {
int maxSub = linesForKind(node.kind);
if (subLine < 0 || subLine >= maxSub) return QStringLiteral("?");
float component = prov.readF32(addr + subLine * 4);
if (!display) return fmtFloat(component).trimmed();
static const char* labels[] = {"x", "y", "z", "w"};
return QString(labels[subLine]) + QStringLiteral(" = ") + fmtFloat(component);
}
case NodeKind::Mat4x4: {
if (!display) return {}; // not editable as single value
if (subLine < 0 || subLine >= 4) return QStringLiteral("?");
QString line = QStringLiteral("[");
for (int c = 0; c < 4; c++) {
if (c > 0) line += QStringLiteral(", ");
line += fmtFloat(prov.readF32(addr + (subLine * 4 + c) * 4)).trimmed();
}
line += QStringLiteral("]");
return line;
}
case NodeKind::Padding: return display ? hexStr(prov.readU8(addr), 2) : rawHex(prov.readU8(addr), 2);
case NodeKind::UTF8: {
QByteArray bytes = prov.readBytes(addr, node.strLen);
int end = bytes.indexOf('\0');
if (end >= 0) bytes.truncate(end);
QString s = QString::fromUtf8(bytes);
return display ? (QStringLiteral("\"") + s + QStringLiteral("\"")) : s;
}
case NodeKind::UTF16: {
QByteArray bytes = prov.readBytes(addr, node.strLen * 2);
QString s = QString::fromUtf16(reinterpret_cast<const char16_t*>(bytes.data()),
bytes.size() / 2);
int end = s.indexOf(QChar(0));
if (end >= 0) s.truncate(end);
return display ? (QStringLiteral("L\"") + s + QStringLiteral("\"")) : s;
}
default:
return {};
}
}
QString readValue(const Node& node, const Provider& prov,
uint64_t addr, int subLine) {
return readValueImpl(node, prov, addr, subLine, ValueMode::Display);
}
// ── Full node line ──
QString fmtNodeLine(const Node& node, const Provider& prov,
uint64_t addr, int depth, int subLine) {
QString ind = indent(depth);
QString type = typeName(node.kind);
QString name = fit(node.name, COL_NAME);
// Blank prefix for continuation lines (same width as type+sep+name+sep)
const int prefixW = COL_TYPE + COL_NAME + 4; // 2 seps × 2 chars
// Mat4x4: subLine 0..3 = rows
if (node.kind == NodeKind::Mat4x4) {
QString val = readValue(node, prov, addr, subLine);
if (subLine == 0) return ind + type + SEP + name + SEP + val;
return ind + QString(prefixW, ' ') + val;
}
// For vector types, subLine selects component
if (subLine > 0 && (node.kind == NodeKind::Vec2 ||
node.kind == NodeKind::Vec3 ||
node.kind == NodeKind::Vec4)) {
QString val = readValue(node, prov, addr, subLine);
return ind + QString(prefixW, ' ') + val;
}
// Hex nodes and Padding: ASCII preview + hex bytes (compact)
if (node.kind == NodeKind::Hex8 || node.kind == NodeKind::Hex16 ||
node.kind == NodeKind::Hex32 || node.kind == NodeKind::Hex64 ||
node.kind == NodeKind::Padding)
{
if (node.kind == NodeKind::Padding) {
const int totalSz = qMax(1, node.arrayLen);
const int lineOff = subLine * 8;
const int lineBytes = qMin(8, totalSz - lineOff);
QByteArray b = prov.isReadable(addr + lineOff, lineBytes)
? prov.readBytes(addr + lineOff, lineBytes) : QByteArray(lineBytes, '\0');
QString ascii = bytesToAscii(b, lineBytes);
QString hex = bytesToHex(b, lineBytes);
if (subLine == 0)
return ind + type + SEP + ascii + SEP + hex;
return ind + QString(COL_TYPE + (int)SEP.size(), ' ') + ascii + SEP + hex;
}
// Hex8..Hex64: single line, ASCII padded to 8 chars so hex column aligns
const int sz = sizeForKind(node.kind);
QByteArray b = prov.isReadable(addr, sz)
? prov.readBytes(addr, sz) : QByteArray(sz, '\0');
QString ascii = bytesToAscii(b, sz).leftJustified(8, ' ');
QString hex = bytesToHex(b, sz);
return ind + type + SEP + ascii + SEP + hex;
}
QString val = readValue(node, prov, addr, subLine);
return ind + type + SEP + name + SEP + val;
}
// ── Editable value (parse-friendly form for edit dialog) ──
QString editableValue(const Node& node, const Provider& prov,
uint64_t addr, int subLine) {
return readValueImpl(node, prov, addr, subLine, ValueMode::Editable);
}
// ── Value parsing (text → bytes) ──
template<class T>
static QByteArray toBytes(T v) {
QByteArray b(sizeof(T), Qt::Uninitialized);
memcpy(b.data(), &v, sizeof(T));
return b;
}
static QString stripHex(const QString& s) {
if (s.startsWith(QStringLiteral("0x"), Qt::CaseInsensitive))
return s.mid(2);
return s;
}
// Range-checked narrowing: sets *ok = false if parsed value doesn't fit in T
template<class T, class ParseT>
static QByteArray parseIntChecked(ParseT val, bool* ok) {
if (*ok) {
using L = std::numeric_limits<T>;
if constexpr (std::is_signed_v<T>) {
if (val < (ParseT)L::min() || val > (ParseT)L::max()) *ok = false;
} else {
if (val > (ParseT)L::max()) *ok = false;
}
}
return *ok ? toBytes<T>(static_cast<T>(val)) : QByteArray{};
}
QByteArray parseValue(NodeKind kind, const QString& text, bool* ok) {
*ok = false;
QString s = text.trimmed();
// Allow empty for string types (will produce zero-length content, caller pads)
if (s.isEmpty()) {
if (kind == NodeKind::UTF8 || kind == NodeKind::UTF16) {
*ok = true;
return {};
}
return {};
}
switch (kind) {
case NodeKind::Hex8: { uint val = stripHex(s).remove(' ').toUInt(ok, 16); return parseIntChecked<uint8_t>(val, ok); }
case NodeKind::Hex16: { uint val = stripHex(s).remove(' ').toUInt(ok, 16); return parseIntChecked<uint16_t>(val, ok); }
case NodeKind::Hex32: { uint val = stripHex(s).remove(' ').toUInt(ok, 16); return *ok ? toBytes<uint32_t>(val) : QByteArray{}; }
case NodeKind::Hex64: { qulonglong val = stripHex(s).remove(' ').toULongLong(ok, 16); return *ok ? toBytes<uint64_t>(val) : QByteArray{}; }
case NodeKind::Int8: { int val = s.toInt(ok); return parseIntChecked<int8_t>(val, ok); }
case NodeKind::Int16: { int val = s.toInt(ok); return parseIntChecked<int16_t>(val, ok); }
case NodeKind::Int32: { int val = s.toInt(ok); return *ok ? toBytes<int32_t>(val) : QByteArray{}; }
case NodeKind::Int64: { qlonglong val = s.toLongLong(ok); return *ok ? toBytes<int64_t>(val) : QByteArray{}; }
case NodeKind::UInt8: { uint val = s.toUInt(ok); return parseIntChecked<uint8_t>(val, ok); }
case NodeKind::UInt16: { uint val = s.toUInt(ok); return parseIntChecked<uint16_t>(val, ok); }
case NodeKind::UInt32: { uint val = s.toUInt(ok); return *ok ? toBytes<uint32_t>(val) : QByteArray{}; }
case NodeKind::UInt64: { qulonglong val = s.toULongLong(ok); return *ok ? toBytes<uint64_t>(val) : QByteArray{}; }
case NodeKind::Float: {
float val = s.toFloat(ok);
return *ok ? toBytes<float>(val) : QByteArray{};
}
case NodeKind::Double: {
double val = s.toDouble(ok);
return *ok ? toBytes<double>(val) : QByteArray{};
}
case NodeKind::Bool: {
if (s == QStringLiteral("true") || s == QStringLiteral("1")) {
*ok = true; return toBytes<uint8_t>(1);
}
if (s == QStringLiteral("false") || s == QStringLiteral("0")) {
*ok = true; return toBytes<uint8_t>(0);
}
return {}; // unknown token → ok stays false
}
case NodeKind::Pointer32: {
uint val = stripHex(s).toUInt(ok, 16);
return *ok ? toBytes<uint32_t>(val) : QByteArray{};
}
case NodeKind::Pointer64: {
qulonglong val = stripHex(s).toULongLong(ok, 16);
return *ok ? toBytes<uint64_t>(val) : QByteArray{};
}
case NodeKind::UTF8: {
*ok = true;
if (s.startsWith('"') && s.endsWith('"'))
s = s.mid(1, s.size() - 2);
return s.toUtf8();
}
case NodeKind::UTF16: {
*ok = true;
if (s.startsWith(QStringLiteral("L\""))) s = s.mid(2);
else if (s.startsWith('"')) s = s.mid(1);
if (s.endsWith('"')) s.chop(1);
QByteArray b(s.size() * 2, Qt::Uninitialized);
memcpy(b.data(), s.utf16(), s.size() * 2);
return b;
}
default:
return {};
}
}
} // namespace rcx::fmt

6
src/icons.qrc Normal file
View File

@@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/icons">
<file alias="chevron-right.png">icons/chevron-right.png</file>
<file alias="chevron-down.png">icons/chevron-down.png</file>
</qresource>
</RCC>

BIN
src/icons/chevron-down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

BIN
src/icons/chevron-right.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

BIN
src/icons/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

636
src/main.cpp Normal file
View File

@@ -0,0 +1,636 @@
#include "controller.h"
#include <QApplication>
#include <QMainWindow>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QMenuBar>
#include <QToolBar>
#include <QStatusBar>
#include <QLabel>
#include <QSplitter>
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>
#include <QAction>
#include <QMap>
#include <QTimer>
#include <QDir>
#include <QMetaObject>
#ifdef _WIN32
#include <windows.h>
#include <dbghelp.h>
#include <cstdio>
static LONG WINAPI crashHandler(EXCEPTION_POINTERS* ep) {
fprintf(stderr, "\n=== UNHANDLED EXCEPTION ===\n");
fprintf(stderr, "Code : 0x%08lX\n", ep->ExceptionRecord->ExceptionCode);
fprintf(stderr, "Addr : %p\n", ep->ExceptionRecord->ExceptionAddress);
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
SymInitialize(process, NULL, TRUE);
CONTEXT* ctx = ep->ContextRecord;
STACKFRAME64 frame = {};
DWORD machineType;
#ifdef _M_X64
machineType = IMAGE_FILE_MACHINE_AMD64;
frame.AddrPC.Offset = ctx->Rip;
frame.AddrFrame.Offset = ctx->Rbp;
frame.AddrStack.Offset = ctx->Rsp;
#else
machineType = IMAGE_FILE_MACHINE_I386;
frame.AddrPC.Offset = ctx->Eip;
frame.AddrFrame.Offset = ctx->Ebp;
frame.AddrStack.Offset = ctx->Esp;
#endif
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Mode = AddrModeFlat;
fprintf(stderr, "\nStack trace:\n");
for (int i = 0; i < 64; i++) {
if (!StackWalk64(machineType, process, thread, &frame, ctx,
NULL, SymFunctionTableAccess64,
SymGetModuleBase64, NULL))
break;
if (frame.AddrPC.Offset == 0) break;
char buf[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* sym = reinterpret_cast<SYMBOL_INFO*>(buf);
sym->SizeOfStruct = sizeof(SYMBOL_INFO);
sym->MaxNameLen = 255;
DWORD64 disp64 = 0;
DWORD disp32 = 0;
IMAGEHLP_LINE64 line = {};
line.SizeOfStruct = sizeof(line);
bool hasSym = SymFromAddr(process, frame.AddrPC.Offset, &disp64, sym);
bool hasLine = SymGetLineFromAddr64(process, frame.AddrPC.Offset,
&disp32, &line);
if (hasSym && hasLine) {
fprintf(stderr, " [%2d] %s+0x%llx (%s:%lu)\n",
i, sym->Name, (unsigned long long)disp64,
line.FileName, line.LineNumber);
} else if (hasSym) {
fprintf(stderr, " [%2d] %s+0x%llx\n",
i, sym->Name, (unsigned long long)disp64);
} else {
fprintf(stderr, " [%2d] 0x%llx\n",
i, (unsigned long long)frame.AddrPC.Offset);
}
}
SymCleanup(process);
fprintf(stderr, "=== END CRASH ===\n");
fflush(stderr);
return EXCEPTION_EXECUTE_HANDLER;
}
#endif
namespace rcx {
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = nullptr);
private slots:
void newFile();
void openFile();
void saveFile();
void saveFileAs();
void loadBinary();
void addNode();
void removeNode();
void changeNodeType();
void renameNodeAction();
void splitView();
void unsplitView();
void undo();
void redo();
void about();
private:
QMdiArea* m_mdiArea;
QLabel* m_statusLabel;
struct TabState {
RcxDocument* doc;
RcxController* ctrl;
QSplitter* splitter;
};
QMap<QMdiSubWindow*, TabState> m_tabs;
void createMenus();
void createStatusBar();
RcxController* activeController() const;
TabState* activeTab();
QMdiSubWindow* createTab(RcxDocument* doc);
void updateWindowTitle();
};
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) {
setWindowTitle("ReclassX");
resize(1200, 800);
m_mdiArea = new QMdiArea(this);
m_mdiArea->setViewMode(QMdiArea::TabbedView);
m_mdiArea->setTabsClosable(true);
m_mdiArea->setTabsMovable(true);
setCentralWidget(m_mdiArea);
createMenus();
createStatusBar();
connect(m_mdiArea, &QMdiArea::subWindowActivated,
this, [this](QMdiSubWindow*) { updateWindowTitle(); });
}
void MainWindow::createMenus() {
// File
auto* file = menuBar()->addMenu("&File");
file->addAction("&New", QKeySequence::New, this, &MainWindow::newFile);
file->addAction("&Open...", QKeySequence::Open, this, &MainWindow::openFile);
file->addSeparator();
file->addAction("&Save", QKeySequence::Save, this, &MainWindow::saveFile);
file->addAction("Save &As...", QKeySequence::SaveAs, this, &MainWindow::saveFileAs);
file->addSeparator();
file->addAction("Load &Binary...", this, &MainWindow::loadBinary);
file->addSeparator();
file->addAction("E&xit", QKeySequence::Quit, this, &QMainWindow::close);
// Edit
auto* edit = menuBar()->addMenu("&Edit");
edit->addAction("&Undo", QKeySequence::Undo, this, &MainWindow::undo);
edit->addAction("&Redo", QKeySequence::Redo, this, &MainWindow::redo);
// View
auto* view = menuBar()->addMenu("&View");
view->addAction("Split &Horizontal", this, &MainWindow::splitView);
view->addAction("&Unsplit", this, &MainWindow::unsplitView);
// Node
auto* node = menuBar()->addMenu("&Node");
node->addAction("&Add Field", QKeySequence(Qt::Key_Insert), this, &MainWindow::addNode);
node->addAction("&Remove Field", QKeySequence::Delete, this, &MainWindow::removeNode);
auto* actType = node->addAction("Change &Type", this, &MainWindow::changeNodeType);
actType->setText("Change &Type\tT");
auto* actName = node->addAction("Re&name", this, &MainWindow::renameNodeAction);
actName->setText("Re&name\tF2");
// Help
auto* help = menuBar()->addMenu("&Help");
help->addAction("&About ReclassX", this, &MainWindow::about);
}
void MainWindow::createStatusBar() {
m_statusLabel = new QLabel("Ready");
statusBar()->addWidget(m_statusLabel, 1);
statusBar()->setStyleSheet("QStatusBar { background: #252526; color: #858585; }");
}
QMdiSubWindow* MainWindow::createTab(RcxDocument* doc) {
auto* splitter = new QSplitter(Qt::Horizontal);
auto* ctrl = new RcxController(doc, splitter);
ctrl->addSplitEditor(splitter);
auto* sub = m_mdiArea->addSubWindow(splitter);
sub->setWindowTitle(doc->filePath.isEmpty()
? "Untitled" : QFileInfo(doc->filePath).fileName());
sub->setAttribute(Qt::WA_DeleteOnClose);
sub->showMaximized();
m_tabs[sub] = { doc, ctrl, splitter };
connect(sub, &QObject::destroyed, this, [this, sub]() {
auto it = m_tabs.find(sub);
if (it != m_tabs.end()) {
it->doc->deleteLater();
m_tabs.erase(it);
}
});
connect(ctrl, &RcxController::nodeSelected,
this, [this, ctrl](int nodeIdx) {
if (nodeIdx >= 0 && nodeIdx < ctrl->document()->tree.nodes.size()) {
auto& node = ctrl->document()->tree.nodes[nodeIdx];
m_statusLabel->setText(
QString("%1 %2 offset: +0x%3 size: %4 bytes")
.arg(kindToString(node.kind))
.arg(node.name)
.arg(node.offset, 4, 16, QChar('0'))
.arg(node.byteSize()));
} else {
m_statusLabel->setText("Ready");
}
});
ctrl->refresh();
return sub;
}
void MainWindow::newFile() {
auto* doc = new RcxDocument(this);
// Autoload self as binary data
doc->loadData(QCoreApplication::applicationFilePath());
doc->tree.baseAddress = 0;
// Read e_lfanew to find PE header offset
uint32_t lfanew = doc->provider->readU32(0x3C);
if (lfanew < 0x40 || lfanew >= (uint32_t)doc->provider->size())
lfanew = 0x40;
uint32_t pe = lfanew; // PE signature
uint32_t fh = pe + 4; // IMAGE_FILE_HEADER
uint32_t oh = fh + 20; // IMAGE_OPTIONAL_HEADER (PE32+)
Node root;
root.kind = NodeKind::Struct;
root.name = "PE_HEADER";
root.parentId = 0;
root.offset = 0;
int ri = doc->tree.addNode(root);
uint64_t rootId = doc->tree.nodes[ri].id;
auto add = [&](NodeKind k, const QString& name, int off) {
Node n;
n.kind = k;
n.name = name;
n.offset = off;
n.parentId = rootId;
doc->tree.addNode(n);
};
// ── IMAGE_DOS_HEADER (0x00 0x3F) ──
add(NodeKind::UInt16, "e_magic", 0x00);
add(NodeKind::UInt16, "e_cblp", 0x02);
add(NodeKind::UInt16, "e_cp", 0x04);
add(NodeKind::UInt16, "e_crlc", 0x06);
add(NodeKind::UInt16, "e_cparhdr", 0x08);
add(NodeKind::UInt16, "e_minalloc", 0x0A);
add(NodeKind::UInt16, "e_maxalloc", 0x0C);
add(NodeKind::UInt16, "e_ss", 0x0E);
add(NodeKind::UInt16, "e_sp", 0x10);
add(NodeKind::UInt16, "e_csum", 0x12);
add(NodeKind::UInt16, "e_ip", 0x14);
add(NodeKind::UInt16, "e_cs", 0x16);
add(NodeKind::UInt16, "e_lfarlc", 0x18);
add(NodeKind::UInt16, "e_ovno", 0x1A);
add(NodeKind::Hex64, "e_res", 0x1C);
add(NodeKind::UInt16, "e_oemid", 0x24);
add(NodeKind::UInt16, "e_oeminfo", 0x26);
add(NodeKind::Hex64, "e_res2_0", 0x28);
add(NodeKind::Hex64, "e_res2_1", 0x30);
add(NodeKind::Hex32, "e_res2_2", 0x38);
add(NodeKind::UInt32, "e_lfanew", 0x3C);
// ── DOS Stub (0x40 to PE signature) — fill with Hex nodes ──
{
int cursor = 0x40;
while (cursor + 8 <= (int)pe) {
add(NodeKind::Hex64,
QString("stub_%1").arg(cursor, 4, 16, QChar('0')),
cursor);
cursor += 8;
}
if (cursor + 4 <= (int)pe) {
add(NodeKind::Hex32,
QString("stub_%1").arg(cursor, 4, 16, QChar('0')),
cursor);
cursor += 4;
}
if (cursor + 2 <= (int)pe) {
add(NodeKind::Hex16,
QString("stub_%1").arg(cursor, 4, 16, QChar('0')),
cursor);
cursor += 2;
}
if (cursor + 1 <= (int)pe) {
add(NodeKind::Hex8,
QString("stub_%1").arg(cursor, 4, 16, QChar('0')),
cursor);
cursor += 1;
}
}
// ── PE Signature ──
add(NodeKind::UInt32, "Signature", pe);
// ── IMAGE_FILE_HEADER (nested struct) ──
{
Node fhStruct;
fhStruct.kind = NodeKind::Struct;
fhStruct.name = "IMAGE_FILE_HEADER";
fhStruct.parentId = rootId;
fhStruct.offset = fh;
int fi = doc->tree.addNode(fhStruct);
uint64_t fhId = doc->tree.nodes[fi].id;
auto addFH = [&](NodeKind k, const QString& name, int off) {
Node n;
n.kind = k;
n.name = name;
n.offset = off;
n.parentId = fhId;
doc->tree.addNode(n);
};
addFH(NodeKind::UInt16, "Machine", 0x00);
addFH(NodeKind::UInt16, "NumberOfSections", 0x02);
addFH(NodeKind::UInt32, "TimeDateStamp", 0x04);
addFH(NodeKind::UInt32, "PtrToSymbolTable", 0x08);
addFH(NodeKind::UInt32, "NumberOfSymbols", 0x0C);
addFH(NodeKind::UInt16, "SizeOfOptionalHeader", 0x10);
addFH(NodeKind::UInt16, "Characteristics", 0x12);
}
// ── IMAGE_OPTIONAL_HEADER64 (nested struct) ──
{
Node ohStruct;
ohStruct.kind = NodeKind::Struct;
ohStruct.name = "IMAGE_OPTIONAL_HEADER64";
ohStruct.parentId = rootId;
ohStruct.offset = oh;
int oi = doc->tree.addNode(ohStruct);
uint64_t ohId = doc->tree.nodes[oi].id;
auto addOH = [&](NodeKind k, const QString& name, int off) {
Node n;
n.kind = k;
n.name = name;
n.offset = off;
n.parentId = ohId;
doc->tree.addNode(n);
};
addOH(NodeKind::UInt16, "Magic", 0x00);
addOH(NodeKind::UInt8, "MajorLinkerVersion", 0x02);
addOH(NodeKind::UInt8, "MinorLinkerVersion", 0x03);
addOH(NodeKind::UInt32, "SizeOfCode", 0x04);
addOH(NodeKind::UInt32, "SizeOfInitData", 0x08);
addOH(NodeKind::UInt32, "SizeOfUninitData", 0x0C);
addOH(NodeKind::UInt32, "AddressOfEntryPoint", 0x10);
addOH(NodeKind::UInt32, "BaseOfCode", 0x14);
addOH(NodeKind::UInt64, "ImageBase", 0x18);
addOH(NodeKind::UInt32, "SectionAlignment", 0x20);
addOH(NodeKind::UInt32, "FileAlignment", 0x24);
addOH(NodeKind::UInt16, "MajorOSVersion", 0x28);
addOH(NodeKind::UInt16, "MinorOSVersion", 0x2A);
addOH(NodeKind::UInt16, "MajorImageVersion", 0x2C);
addOH(NodeKind::UInt16, "MinorImageVersion", 0x2E);
addOH(NodeKind::UInt16, "MajorSubsysVersion", 0x30);
addOH(NodeKind::UInt16, "MinorSubsysVersion", 0x32);
addOH(NodeKind::UInt32, "Win32VersionValue", 0x34);
addOH(NodeKind::UInt32, "SizeOfImage", 0x38);
addOH(NodeKind::UInt32, "SizeOfHeaders", 0x3C);
addOH(NodeKind::UInt32, "CheckSum", 0x40);
addOH(NodeKind::UInt16, "Subsystem", 0x44);
addOH(NodeKind::UInt16, "DllCharacteristics", 0x46);
addOH(NodeKind::UInt64, "SizeOfStackReserve", 0x48);
addOH(NodeKind::UInt64, "SizeOfStackCommit", 0x50);
addOH(NodeKind::UInt64, "SizeOfHeapReserve", 0x58);
addOH(NodeKind::UInt64, "SizeOfHeapCommit", 0x60);
addOH(NodeKind::UInt32, "LoaderFlags", 0x68);
addOH(NodeKind::UInt32, "NumberOfRvaAndSizes", 0x6C);
// Data directories (16 entries × 8 bytes)
static const char* dirNames[] = {
"Export", "Import", "Resource", "Exception",
"Security", "BaseReloc", "Debug", "Architecture",
"GlobalPtr", "TLS", "LoadConfig", "BoundImport",
"IAT", "DelayImport", "CLR", "Reserved"
};
for (int i = 0; i < 16; i++) {
int doff = 0x70 + i * 8;
addOH(NodeKind::UInt32, QString("%1_RVA").arg(dirNames[i]), doff);
addOH(NodeKind::UInt32, QString("%1_Size").arg(dirNames[i]), doff + 4);
}
}
// ── 0x100 bytes of Hex64 padding (32 nodes) ──
int padStart = oh + 0xF0; // end of optional header
for (int i = 0; i < 32; i++) {
int off = padStart + i * 8;
add(NodeKind::Hex64,
QString("pad_%1").arg(off, 4, 16, QChar('0')),
off);
}
createTab(doc);
}
void MainWindow::openFile() {
QString path = QFileDialog::getOpenFileName(this,
"Open Definition", {}, "ReclassX (*.rcx);;JSON (*.json);;All (*)");
if (path.isEmpty()) return;
auto* doc = new RcxDocument(this);
if (!doc->load(path)) {
QMessageBox::warning(this, "Error", "Failed to load: " + path);
delete doc;
return;
}
createTab(doc);
}
void MainWindow::saveFile() {
auto* tab = activeTab();
if (!tab) return;
if (tab->doc->filePath.isEmpty()) { saveFileAs(); return; }
tab->doc->save(tab->doc->filePath);
updateWindowTitle();
}
void MainWindow::saveFileAs() {
auto* tab = activeTab();
if (!tab) return;
QString path = QFileDialog::getSaveFileName(this,
"Save Definition", {}, "ReclassX (*.rcx);;JSON (*.json)");
if (path.isEmpty()) return;
tab->doc->save(path);
updateWindowTitle();
}
void MainWindow::loadBinary() {
auto* tab = activeTab();
if (!tab) return;
QString path = QFileDialog::getOpenFileName(this,
"Load Binary Data", {}, "All Files (*)");
if (path.isEmpty()) return;
tab->doc->loadData(path);
}
void MainWindow::addNode() {
auto* ctrl = activeController();
if (!ctrl) return;
uint64_t parentId = 0;
auto* primary = ctrl->primaryEditor();
if (primary && primary->isEditing()) return;
if (primary) {
int ni = primary->currentNodeIndex();
if (ni >= 0) {
auto& node = ctrl->document()->tree.nodes[ni];
if (node.kind == NodeKind::Struct || node.kind == NodeKind::Array)
parentId = node.id;
else
parentId = node.parentId;
}
}
ctrl->insertNode(parentId, -1, NodeKind::Hex64, "newField");
}
void MainWindow::removeNode() {
auto* ctrl = activeController();
if (!ctrl) return;
auto* primary = ctrl->primaryEditor();
if (!primary || primary->isEditing()) return;
QSet<int> indices = primary->selectedNodeIndices();
if (indices.size() > 1) {
ctrl->batchRemoveNodes(indices.values());
} else if (indices.size() == 1) {
ctrl->removeNode(*indices.begin());
}
}
void MainWindow::changeNodeType() {
auto* ctrl = activeController();
if (!ctrl) return;
auto* primary = ctrl->primaryEditor();
if (!primary) return;
primary->beginInlineEdit(EditTarget::Type);
}
void MainWindow::renameNodeAction() {
auto* ctrl = activeController();
if (!ctrl) return;
auto* primary = ctrl->primaryEditor();
if (!primary) return;
primary->beginInlineEdit(EditTarget::Name);
}
void MainWindow::splitView() {
auto* tab = activeTab();
if (!tab) return;
tab->ctrl->addSplitEditor(tab->splitter);
}
void MainWindow::unsplitView() {
auto* tab = activeTab();
if (!tab) return;
auto editors = tab->ctrl->editors();
if (editors.size() > 1)
tab->ctrl->removeSplitEditor(editors.last());
}
void MainWindow::undo() {
auto* tab = activeTab();
if (tab) tab->doc->undoStack.undo();
}
void MainWindow::redo() {
auto* tab = activeTab();
if (tab) tab->doc->undoStack.redo();
}
void MainWindow::about() {
QMessageBox::about(this, "About ReclassX",
"ReclassX - Structured Binary Editor\n"
"Built with Qt 6 + QScintilla\n\n"
"Margin-driven UI with offset display,\n"
"fold markers, and status flags.");
}
RcxController* MainWindow::activeController() const {
auto* sub = m_mdiArea->activeSubWindow();
if (sub && m_tabs.contains(sub))
return m_tabs[sub].ctrl;
return nullptr;
}
MainWindow::TabState* MainWindow::activeTab() {
auto* sub = m_mdiArea->activeSubWindow();
if (sub && m_tabs.contains(sub))
return &m_tabs[sub];
return nullptr;
}
void MainWindow::updateWindowTitle() {
auto* sub = m_mdiArea->activeSubWindow();
if (sub && m_tabs.contains(sub)) {
auto& tab = m_tabs[sub];
QString name = tab.doc->filePath.isEmpty() ? "Untitled"
: QFileInfo(tab.doc->filePath).fileName();
if (tab.doc->modified) name += " *";
setWindowTitle(name + " - ReclassX");
} else {
setWindowTitle("ReclassX");
}
}
} // namespace rcx
// ── Entry point ──
int main(int argc, char* argv[]) {
#ifdef _WIN32
SetUnhandledExceptionFilter(crashHandler);
#endif
QApplication app(argc, argv);
app.setApplicationName("ReclassX");
app.setOrganizationName("ReclassX");
app.setStyle("Fusion"); // Fusion style respects dark palette well
// Global dark palette
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, QColor("#1e1e1e"));
darkPalette.setColor(QPalette::WindowText, QColor("#d4d4d4"));
darkPalette.setColor(QPalette::Base, QColor("#252526"));
darkPalette.setColor(QPalette::AlternateBase, QColor("#2a2d2e"));
darkPalette.setColor(QPalette::Text, QColor("#d4d4d4"));
darkPalette.setColor(QPalette::Button, QColor("#333333"));
darkPalette.setColor(QPalette::ButtonText, QColor("#d4d4d4"));
darkPalette.setColor(QPalette::Highlight, QColor("#264f78"));
darkPalette.setColor(QPalette::HighlightedText, QColor("#ffffff"));
darkPalette.setColor(QPalette::ToolTipBase, QColor("#252526"));
darkPalette.setColor(QPalette::ToolTipText, QColor("#d4d4d4"));
darkPalette.setColor(QPalette::Mid, QColor("#3c3c3c"));
darkPalette.setColor(QPalette::Dark, QColor("#1e1e1e"));
darkPalette.setColor(QPalette::Light, QColor("#505050"));
app.setPalette(darkPalette);
rcx::MainWindow window;
bool screenshotMode = app.arguments().contains("--screenshot");
if (screenshotMode)
window.setAttribute(Qt::WA_DontShowOnScreen);
window.show();
// Always auto-open PE header demo on startup
QMetaObject::invokeMethod(&window, "newFile");
if (screenshotMode) {
QString out = "screenshot.png";
int idx = app.arguments().indexOf("--screenshot");
if (idx + 1 < app.arguments().size())
out = app.arguments().at(idx + 1);
QTimer::singleShot(1000, [&window, &app, out]() {
QDir().mkpath(QFileInfo(out).absolutePath());
window.grab().save(out);
app.quit();
});
}
return app.exec();
}
#include "main.moc"

674
tests/test_compose.cpp Normal file
View File

@@ -0,0 +1,674 @@
#include <QtTest/QTest>
#include "core.h"
using namespace rcx;
class TestCompose : public QObject {
Q_OBJECT
private slots:
void testBasicStruct() {
NodeTree tree;
tree.baseAddress = 0;
Node root;
root.kind = NodeKind::Struct;
root.name = "Root";
root.parentId = 0;
root.offset = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node f1;
f1.kind = NodeKind::Hex32;
f1.name = "field_0";
f1.parentId = rootId;
f1.offset = 0;
tree.addNode(f1);
Node f2;
f2.kind = NodeKind::Float;
f2.name = "value";
f2.parentId = rootId;
f2.offset = 4;
tree.addNode(f2);
NullProvider prov;
ComposeResult result = compose(tree, prov);
// Header + 2 fields + footer = 4 lines
QCOMPARE(result.meta.size(), 4);
// Header is fold head
QVERIFY(result.meta[0].foldHead);
QCOMPARE(result.meta[0].lineKind, LineKind::Header);
// Fields are not fold heads
QVERIFY(!result.meta[1].foldHead);
QVERIFY(!result.meta[2].foldHead);
// Footer
QCOMPARE(result.meta[3].lineKind, LineKind::Footer);
// Offset text
QCOMPARE(result.meta[0].offsetText, QString("+0x0"));
QCOMPARE(result.meta[1].offsetText, QString("+0x0"));
QCOMPARE(result.meta[2].offsetText, QString("+0x4"));
// Header is expanded by default (fold indicator in line text)
QVERIFY(!result.meta[0].foldCollapsed);
}
void testVec3Continuation() {
NodeTree tree;
tree.baseAddress = 0;
Node root;
root.kind = NodeKind::Struct;
root.name = "Root";
root.parentId = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node v;
v.kind = NodeKind::Vec3;
v.name = "pos";
v.parentId = rootId;
v.offset = 0;
tree.addNode(v);
NullProvider prov;
ComposeResult result = compose(tree, prov);
// Header + 3 Vec3 lines + footer = 5 lines
QCOMPARE(result.meta.size(), 5);
// Line 1 (first Vec3 component): not continuation
QVERIFY(!result.meta[1].isContinuation);
QCOMPARE(result.meta[1].offsetText, QString("+0x0"));
// Lines 2-3: continuation
QVERIFY(result.meta[2].isContinuation);
QCOMPARE(result.meta[2].offsetText, QString(" \u00B7"));
QVERIFY(result.meta[3].isContinuation);
QCOMPARE(result.meta[3].offsetText, QString(" \u00B7"));
// Continuation marker
QVERIFY(result.meta[2].markerMask & (1u << M_CONT));
QVERIFY(result.meta[3].markerMask & (1u << M_CONT));
}
void testPaddingMarker() {
NodeTree tree;
tree.baseAddress = 0;
Node root;
root.kind = NodeKind::Struct;
root.name = "R";
root.parentId = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node pad;
pad.kind = NodeKind::Padding;
pad.name = "pad";
pad.parentId = rootId;
pad.offset = 0;
tree.addNode(pad);
NullProvider prov;
ComposeResult result = compose(tree, prov);
// Header + padding + footer = 3
QCOMPARE(result.meta.size(), 3);
QVERIFY(result.meta[1].markerMask & (1u << M_PAD));
}
void testNullPointerMarker() {
NodeTree tree;
tree.baseAddress = 0;
Node root;
root.kind = NodeKind::Struct;
root.name = "R";
root.parentId = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node ptr;
ptr.kind = NodeKind::Pointer64;
ptr.name = "ptr";
ptr.parentId = rootId;
ptr.offset = 0;
tree.addNode(ptr);
// Provider with zeros (null ptr)
QByteArray data(64, '\0');
FileProvider prov(data);
ComposeResult result = compose(tree, prov);
QCOMPARE(result.meta.size(), 3);
QVERIFY(result.meta[1].markerMask & (1u << M_PTR0));
}
void testCollapsedStruct() {
NodeTree tree;
tree.baseAddress = 0;
Node root;
root.kind = NodeKind::Struct;
root.name = "Root";
root.parentId = 0;
root.collapsed = true;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node f;
f.kind = NodeKind::Hex32;
f.name = "field";
f.parentId = rootId;
f.offset = 0;
tree.addNode(f);
NullProvider prov;
ComposeResult result = compose(tree, prov);
// Collapsed: header + footer only = 2 lines
QCOMPARE(result.meta.size(), 2);
QVERIFY(result.meta[0].foldHead);
}
void testUnreadablePointerNoRead() {
// A pointer at an unreadable address should get M_ERR, not M_PTR0
NodeTree tree;
tree.baseAddress = 0;
Node root;
root.kind = NodeKind::Struct;
root.name = "R";
root.parentId = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node ptr;
ptr.kind = NodeKind::Pointer64;
ptr.name = "ptr";
ptr.parentId = rootId;
ptr.offset = 0;
tree.addNode(ptr);
// Provider with only 4 bytes — not enough for Pointer64 (8 bytes)
QByteArray data(4, '\0');
FileProvider prov(data);
ComposeResult result = compose(tree, prov);
QCOMPARE(result.meta.size(), 3);
// Should have M_ERR, should NOT have M_PTR0
QVERIFY(result.meta[1].markerMask & (1u << M_ERR));
QVERIFY(!(result.meta[1].markerMask & (1u << M_PTR0)));
}
void testFoldLevels() {
NodeTree tree;
tree.baseAddress = 0;
Node root;
root.kind = NodeKind::Struct;
root.name = "Root";
root.parentId = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node child;
child.kind = NodeKind::Struct;
child.name = "Child";
child.parentId = rootId;
child.offset = 0;
int ci = tree.addNode(child);
uint64_t childId = tree.nodes[ci].id;
Node leaf;
leaf.kind = NodeKind::Hex8;
leaf.name = "x";
leaf.parentId = childId;
leaf.offset = 0;
tree.addNode(leaf);
NullProvider prov;
ComposeResult result = compose(tree, prov);
// Root header (depth 0, head) -> 0x400 | 0x2000
QCOMPARE(result.meta[0].foldLevel, 0x400 | 0x2000);
QCOMPARE(result.meta[0].depth, 0);
// Child header (depth 1, head) -> 0x401 | 0x2000
QCOMPARE(result.meta[1].foldLevel, 0x401 | 0x2000);
QCOMPARE(result.meta[1].depth, 1);
// Leaf (depth 2, not head) -> 0x402
QCOMPARE(result.meta[2].foldLevel, 0x402);
QCOMPARE(result.meta[2].depth, 2);
}
void testNestedStruct() {
NodeTree tree;
tree.baseAddress = 0;
Node root;
root.kind = NodeKind::Struct;
root.name = "Outer";
root.parentId = 0;
root.offset = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node f1;
f1.kind = NodeKind::UInt32;
f1.name = "flags";
f1.parentId = rootId;
f1.offset = 0;
tree.addNode(f1);
Node inner;
inner.kind = NodeKind::Struct;
inner.name = "Inner";
inner.parentId = rootId;
inner.offset = 4;
int ii = tree.addNode(inner);
uint64_t innerId = tree.nodes[ii].id;
Node f2;
f2.kind = NodeKind::UInt16;
f2.name = "x";
f2.parentId = innerId;
f2.offset = 0;
tree.addNode(f2);
Node f3;
f3.kind = NodeKind::UInt16;
f3.name = "y";
f3.parentId = innerId;
f3.offset = 2;
tree.addNode(f3);
NullProvider prov;
ComposeResult result = compose(tree, prov);
// Outer header + flags + Inner header + x + y + Inner footer + Outer footer = 7
QCOMPARE(result.meta.size(), 7);
// Outer header
QCOMPARE(result.meta[0].lineKind, LineKind::Header);
QCOMPARE(result.meta[0].depth, 0);
QVERIFY(result.meta[0].foldHead);
// flags field
QCOMPARE(result.meta[1].lineKind, LineKind::Field);
QCOMPARE(result.meta[1].depth, 1);
// Inner header
QCOMPARE(result.meta[2].lineKind, LineKind::Header);
QCOMPARE(result.meta[2].depth, 1);
QVERIFY(result.meta[2].foldHead);
QCOMPARE(result.meta[2].foldLevel, 0x401 | 0x2000);
// Inner fields at depth 2
QCOMPARE(result.meta[3].depth, 2);
QCOMPARE(result.meta[3].foldLevel, 0x402);
QCOMPARE(result.meta[4].depth, 2);
// Inner footer
QCOMPARE(result.meta[5].lineKind, LineKind::Footer);
QCOMPARE(result.meta[5].depth, 1);
// Outer footer
QCOMPARE(result.meta[6].lineKind, LineKind::Footer);
QCOMPARE(result.meta[6].depth, 0);
}
void testPointerDerefExpansion() {
NodeTree tree;
tree.baseAddress = 0;
// Main struct
Node main;
main.kind = NodeKind::Struct;
main.name = "Main";
main.parentId = 0;
main.offset = 0;
int mi = tree.addNode(main);
uint64_t mainId = tree.nodes[mi].id;
Node magic;
magic.kind = NodeKind::UInt32;
magic.name = "magic";
magic.parentId = mainId;
magic.offset = 0;
tree.addNode(magic);
// Template struct (separate root)
Node tmpl;
tmpl.kind = NodeKind::Struct;
tmpl.name = "VTable";
tmpl.parentId = 0;
tmpl.offset = 200; // far away so standalone rendering uses offset 200
int ti = tree.addNode(tmpl);
uint64_t tmplId = tree.nodes[ti].id;
Node fn1;
fn1.kind = NodeKind::UInt64;
fn1.name = "fn_one";
fn1.parentId = tmplId;
fn1.offset = 0;
tree.addNode(fn1);
Node fn2;
fn2.kind = NodeKind::UInt64;
fn2.name = "fn_two";
fn2.parentId = tmplId;
fn2.offset = 8;
tree.addNode(fn2);
// Pointer in Main referencing VTable
Node ptr;
ptr.kind = NodeKind::Pointer64;
ptr.name = "vtable_ptr";
ptr.parentId = mainId;
ptr.offset = 4;
ptr.refId = tmplId;
tree.addNode(ptr);
// Provider: pointer at offset 4 points to address 100
QByteArray data(256, '\0');
uint64_t ptrVal = 100;
memcpy(data.data() + 4, &ptrVal, 8);
// Some data at the pointer target
uint64_t v1 = 0xDEADBEEF;
memcpy(data.data() + 100, &v1, 8);
uint64_t v2 = 0xCAFEBABE;
memcpy(data.data() + 108, &v2, 8);
FileProvider prov(data);
ComposeResult result = compose(tree, prov);
// Main: header + magic + ptr(fold head) + VTable header + fn1 + fn2 + VTable footer + Main footer = 8
// VTable standalone: header + fn1 + fn2 + footer = 4
// Total = 12
QCOMPARE(result.meta.size(), 12);
// Main header
QCOMPARE(result.meta[0].lineKind, LineKind::Header);
QCOMPARE(result.meta[0].depth, 0);
// magic field
QCOMPARE(result.meta[1].lineKind, LineKind::Field);
QCOMPARE(result.meta[1].depth, 1);
// Pointer as fold head
QCOMPARE(result.meta[2].lineKind, LineKind::Field);
QCOMPARE(result.meta[2].depth, 1);
QVERIFY(result.meta[2].foldHead);
QCOMPARE(result.meta[2].nodeKind, NodeKind::Pointer64);
// Expanded VTable header at depth 2
QCOMPARE(result.meta[3].lineKind, LineKind::Header);
QCOMPARE(result.meta[3].depth, 2);
// Expanded fields at depth 3
QCOMPARE(result.meta[4].depth, 3);
QCOMPARE(result.meta[5].depth, 3);
// Expanded VTable footer
QCOMPARE(result.meta[6].lineKind, LineKind::Footer);
QCOMPARE(result.meta[6].depth, 2);
// Main footer
QCOMPARE(result.meta[7].lineKind, LineKind::Footer);
QCOMPARE(result.meta[7].depth, 0);
}
void testPointerDerefNull() {
NodeTree tree;
tree.baseAddress = 0;
Node main;
main.kind = NodeKind::Struct;
main.name = "Main";
main.parentId = 0;
main.offset = 0;
int mi = tree.addNode(main);
uint64_t mainId = tree.nodes[mi].id;
Node tmpl;
tmpl.kind = NodeKind::Struct;
tmpl.name = "Target";
tmpl.parentId = 0;
tmpl.offset = 200;
int ti = tree.addNode(tmpl);
uint64_t tmplId = tree.nodes[ti].id;
Node tf;
tf.kind = NodeKind::UInt32;
tf.name = "field";
tf.parentId = tmplId;
tf.offset = 0;
tree.addNode(tf);
Node ptr;
ptr.kind = NodeKind::Pointer64;
ptr.name = "ptr";
ptr.parentId = mainId;
ptr.offset = 0;
ptr.refId = tmplId;
tree.addNode(ptr);
// All zeros = null pointer
QByteArray data(256, '\0');
FileProvider prov(data);
ComposeResult result = compose(tree, prov);
// Main: header + ptr(fold head, no expansion) + footer = 3
// Target standalone: header + field + footer = 3
// Total = 6
QCOMPARE(result.meta.size(), 6);
// Pointer is fold head but has no children (null ptr)
QCOMPARE(result.meta[1].lineKind, LineKind::Field);
QVERIFY(result.meta[1].foldHead);
// Next line is Main footer (no expansion)
QCOMPARE(result.meta[2].lineKind, LineKind::Footer);
QCOMPARE(result.meta[2].depth, 0);
}
void testPointerDerefCollapsed() {
NodeTree tree;
tree.baseAddress = 0;
Node main;
main.kind = NodeKind::Struct;
main.name = "Main";
main.parentId = 0;
main.offset = 0;
int mi = tree.addNode(main);
uint64_t mainId = tree.nodes[mi].id;
Node tmpl;
tmpl.kind = NodeKind::Struct;
tmpl.name = "Target";
tmpl.parentId = 0;
tmpl.offset = 200;
int ti = tree.addNode(tmpl);
uint64_t tmplId = tree.nodes[ti].id;
Node tf;
tf.kind = NodeKind::UInt32;
tf.name = "field";
tf.parentId = tmplId;
tf.offset = 0;
tree.addNode(tf);
Node ptr;
ptr.kind = NodeKind::Pointer64;
ptr.name = "ptr";
ptr.parentId = mainId;
ptr.offset = 0;
ptr.refId = tmplId;
ptr.collapsed = true; // collapsed
tree.addNode(ptr);
// Non-null pointer
QByteArray data(256, '\0');
uint64_t ptrVal = 100;
memcpy(data.data(), &ptrVal, 8);
FileProvider prov(data);
ComposeResult result = compose(tree, prov);
// Main: header + ptr(fold head, collapsed) + footer = 3
// Target standalone: header + field + footer = 3
// Total = 6
QCOMPARE(result.meta.size(), 6);
// Pointer is fold head
QVERIFY(result.meta[1].foldHead);
// No expansion — next is Main footer
QCOMPARE(result.meta[2].lineKind, LineKind::Footer);
QCOMPARE(result.meta[2].depth, 0);
}
void testPointerDerefCycle() {
NodeTree tree;
tree.baseAddress = 0;
Node main;
main.kind = NodeKind::Struct;
main.name = "Main";
main.parentId = 0;
main.offset = 0;
int mi = tree.addNode(main);
uint64_t mainId = tree.nodes[mi].id;
// Template struct with a self-referencing pointer
Node tmpl;
tmpl.kind = NodeKind::Struct;
tmpl.name = "Recursive";
tmpl.parentId = 0;
tmpl.offset = 200;
int ti = tree.addNode(tmpl);
uint64_t tmplId = tree.nodes[ti].id;
Node tf;
tf.kind = NodeKind::UInt32;
tf.name = "data";
tf.parentId = tmplId;
tf.offset = 0;
tree.addNode(tf);
// Self-referencing pointer inside the template
Node backPtr;
backPtr.kind = NodeKind::Pointer64;
backPtr.name = "self";
backPtr.parentId = tmplId;
backPtr.offset = 4;
backPtr.refId = tmplId; // points back to same struct
tree.addNode(backPtr);
// Pointer in Main → Recursive
Node ptr;
ptr.kind = NodeKind::Pointer64;
ptr.name = "ptr";
ptr.parentId = mainId;
ptr.offset = 0;
ptr.refId = tmplId;
tree.addNode(ptr);
// Provider: main ptr at offset 0 points to 100
// Inside expansion: backPtr at offset 100+4=104 also points to 100
QByteArray data(256, '\0');
uint64_t ptrVal = 100;
memcpy(data.data(), &ptrVal, 8); // main ptr → 100
memcpy(data.data() + 104, &ptrVal, 8); // backPtr at 104 → 100
FileProvider prov(data);
ComposeResult result = compose(tree, prov);
// Must not infinite-loop. Verify we got a finite result.
QVERIFY(result.meta.size() > 0);
QVERIFY(result.meta.size() < 100); // sanity: bounded output
// First expansion happens: Main header + ptr fold head + Recursive header + data + backPtr fold head
// Second expansion blocked by cycle guard: no children under backPtr
// Then: Recursive footer + Main footer
// Plus standalone Recursive rendering
// The exact count depends on cycle guard behavior but must be finite
QCOMPARE(result.meta[0].lineKind, LineKind::Header); // Main header
QVERIFY(result.meta[1].foldHead); // ptr fold head
QCOMPARE(result.meta[2].lineKind, LineKind::Header); // Recursive header (expansion)
}
void testStructFooterSizeof() {
NodeTree tree;
tree.baseAddress = 0;
Node root;
root.kind = NodeKind::Struct;
root.name = "Sized";
root.parentId = 0;
root.offset = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node f1;
f1.kind = NodeKind::UInt32;
f1.name = "a";
f1.parentId = rootId;
f1.offset = 0;
tree.addNode(f1);
Node f2;
f2.kind = NodeKind::UInt64;
f2.name = "b";
f2.parentId = rootId;
f2.offset = 4;
tree.addNode(f2);
NullProvider prov;
ComposeResult result = compose(tree, prov);
// Footer is the last line
int lastLine = result.meta.size() - 1;
QCOMPARE(result.meta[lastLine].lineKind, LineKind::Footer);
// Footer text should contain sizeof=0xC (4+8=12=0xC)
QString footerText = result.text.split('\n').last();
QVERIFY(footerText.contains("sizeof=0xC"));
}
void testLineMetaHasNodeId() {
using namespace rcx;
NodeTree tree;
tree.baseAddress = 0;
Node root; root.kind = NodeKind::Struct; root.name = "Root"; root.parentId = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node f; f.kind = NodeKind::Hex32; f.name = "x"; f.parentId = rootId; f.offset = 0;
tree.addNode(f);
NullProvider prov;
ComposeResult result = compose(tree, prov);
for (int i = 0; i < result.meta.size(); i++) {
QVERIFY2(result.meta[i].nodeId != 0,
qPrintable(QString("Line %1 has nodeId=0").arg(i)));
int ni = result.meta[i].nodeIdx;
QVERIFY(ni >= 0 && ni < tree.nodes.size());
QCOMPARE(result.meta[i].nodeId, tree.nodes[ni].id);
}
}
};
QTEST_MAIN(TestCompose)
#include "test_compose.moc"

557
tests/test_core.cpp Normal file
View File

@@ -0,0 +1,557 @@
#include <QtTest/QTest>
#include "core.h"
class TestCore : public QObject {
Q_OBJECT
private slots:
void testSizeForKind() {
QCOMPARE(rcx::sizeForKind(rcx::NodeKind::Hex8), 1);
QCOMPARE(rcx::sizeForKind(rcx::NodeKind::Hex16), 2);
QCOMPARE(rcx::sizeForKind(rcx::NodeKind::Hex32), 4);
QCOMPARE(rcx::sizeForKind(rcx::NodeKind::Hex64), 8);
QCOMPARE(rcx::sizeForKind(rcx::NodeKind::Float), 4);
QCOMPARE(rcx::sizeForKind(rcx::NodeKind::Double), 8);
QCOMPARE(rcx::sizeForKind(rcx::NodeKind::Vec3), 12);
QCOMPARE(rcx::sizeForKind(rcx::NodeKind::Mat4x4), 64);
QCOMPARE(rcx::sizeForKind(rcx::NodeKind::Struct), 0);
}
void testLinesForKind() {
QCOMPARE(rcx::linesForKind(rcx::NodeKind::Hex32), 1);
QCOMPARE(rcx::linesForKind(rcx::NodeKind::Vec2), 2);
QCOMPARE(rcx::linesForKind(rcx::NodeKind::Vec3), 3);
QCOMPARE(rcx::linesForKind(rcx::NodeKind::Vec4), 4);
QCOMPARE(rcx::linesForKind(rcx::NodeKind::Mat4x4), 4);
}
void testKindStringRoundTrip() {
for (int i = 0; i <= static_cast<int>(rcx::NodeKind::Array); i++) {
auto kind = static_cast<rcx::NodeKind>(i);
QString s = rcx::kindToString(kind);
QCOMPARE(rcx::kindFromString(s), kind);
}
}
void testNodeTree_addAndChildren() {
rcx::NodeTree tree;
rcx::Node root;
root.kind = rcx::NodeKind::Struct;
root.name = "Root";
root.parentId = 0;
int ri = tree.addNode(root);
QCOMPARE(ri, 0);
uint64_t rootId = tree.nodes[ri].id;
rcx::Node child;
child.kind = rcx::NodeKind::Hex32;
child.name = "field";
child.parentId = rootId;
child.offset = 0;
tree.addNode(child);
auto children = tree.childrenOf(rootId);
QCOMPARE(children.size(), 1);
QCOMPARE(children[0], 1);
auto roots = tree.childrenOf(0);
QCOMPARE(roots.size(), 1);
QCOMPARE(roots[0], 0);
}
void testNodeTree_depth() {
rcx::NodeTree tree;
rcx::Node a; a.kind = rcx::NodeKind::Struct; a.name = "A"; a.parentId = 0;
int ai = tree.addNode(a);
uint64_t aId = tree.nodes[ai].id;
rcx::Node b; b.kind = rcx::NodeKind::Struct; b.name = "B"; b.parentId = aId;
int bi = tree.addNode(b);
uint64_t bId = tree.nodes[bi].id;
rcx::Node c; c.kind = rcx::NodeKind::Hex8; c.name = "c"; c.parentId = bId;
tree.addNode(c);
QCOMPARE(tree.depthOf(0), 0);
QCOMPARE(tree.depthOf(1), 1);
QCOMPARE(tree.depthOf(2), 2);
}
void testNodeTree_computeOffset() {
rcx::NodeTree tree;
tree.baseAddress = 0x1000;
rcx::Node root; root.kind = rcx::NodeKind::Struct; root.name = "R";
root.parentId = 0; root.offset = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
rcx::Node f; f.kind = rcx::NodeKind::Hex32; f.name = "f";
f.parentId = rootId; f.offset = 16;
tree.addNode(f);
QCOMPARE(tree.computeOffset(1), 16);
}
void testNodeTree_jsonRoundTrip() {
rcx::NodeTree tree;
tree.baseAddress = 0xDEAD;
rcx::Node root; root.kind = rcx::NodeKind::Struct; root.name = "Test";
root.parentId = 0; root.offset = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
rcx::Node child; child.kind = rcx::NodeKind::Float; child.name = "val";
child.parentId = rootId; child.offset = 8;
tree.addNode(child);
QJsonObject json = tree.toJson();
rcx::NodeTree tree2 = rcx::NodeTree::fromJson(json);
QCOMPARE(tree2.baseAddress, (uint64_t)0xDEAD);
QCOMPARE(tree2.nodes.size(), 2);
QCOMPARE(tree2.nodes[0].name, QString("Test"));
QCOMPARE(tree2.nodes[1].kind, rcx::NodeKind::Float);
QCOMPARE(tree2.nodes[1].offset, 8);
}
void testFileProvider() {
QByteArray data(16, '\0');
data[0] = 0x42;
data[4] = 0x10;
data[5] = 0x20;
rcx::FileProvider prov(data);
QVERIFY(prov.isValid());
QCOMPARE(prov.size(), 16);
QCOMPARE(prov.readU8(0), (uint8_t)0x42);
QCOMPARE(prov.readU16(4), (uint16_t)0x2010);
}
void testNullProvider() {
rcx::NullProvider prov;
QVERIFY(!prov.isValid());
QVERIFY(!prov.isReadable(0, 1));
QCOMPARE(prov.readU8(0), (uint8_t)0);
QCOMPARE(prov.readU32(0), (uint32_t)0);
}
void testIsReadable() {
QByteArray data(16, '\0');
rcx::FileProvider prov(data);
QVERIFY(prov.isReadable(0, 4));
QVERIFY(prov.isReadable(0, 16));
QVERIFY(!prov.isReadable(0, 17));
QVERIFY(!prov.isReadable(15, 2));
QVERIFY(prov.isReadable(15, 1));
}
void testStableNodeIds() {
rcx::NodeTree tree;
rcx::Node a; a.kind = rcx::NodeKind::Struct; a.name = "A"; a.parentId = 0;
int ai = tree.addNode(a);
QCOMPARE(tree.nodes[ai].id, (uint64_t)1);
rcx::Node b; b.kind = rcx::NodeKind::Hex32; b.name = "B"; b.parentId = tree.nodes[ai].id;
int bi = tree.addNode(b);
QCOMPARE(tree.nodes[bi].id, (uint64_t)2);
QCOMPARE(tree.indexOfId(1), 0);
QCOMPARE(tree.indexOfId(2), 1);
QCOMPARE(tree.indexOfId(99), -1);
}
void testByteSizeDynamic() {
rcx::Node n;
n.kind = rcx::NodeKind::UTF8;
n.strLen = 128;
QCOMPARE(n.byteSize(), 128);
n.kind = rcx::NodeKind::UTF16;
n.strLen = 32;
QCOMPARE(n.byteSize(), 64); // 32 * 2
n.kind = rcx::NodeKind::Float;
QCOMPARE(n.byteSize(), 4); // falls back to sizeForKind
}
void testSubtreeCycleSafe() {
rcx::NodeTree tree;
rcx::Node a; a.kind = rcx::NodeKind::Struct; a.name = "A"; a.parentId = 0;
int ai = tree.addNode(a);
uint64_t aId = tree.nodes[ai].id;
// Create a child that points back to A's id as parent — not a cycle per se,
// but test that subtree collection terminates
rcx::Node b; b.kind = rcx::NodeKind::Hex8; b.name = "B"; b.parentId = aId;
tree.addNode(b);
// Should return both nodes without hanging
auto sub = tree.subtreeIndices(aId);
QCOMPARE(sub.size(), 2);
QVERIFY(sub.contains(0));
QVERIFY(sub.contains(1));
}
void testIsReadableOverflow() {
QByteArray data(16, '\0');
rcx::FileProvider prov(data);
// Normal cases
QVERIFY(prov.isReadable(0, 16));
QVERIFY(!prov.isReadable(0, 17));
// Large address
QVERIFY(!prov.isReadable(0xFFFFFFFFFFFFFFFFULL, 1));
// Negative len
QVERIFY(!prov.isReadable(0, -1));
// Zero len is readable
QVERIFY(prov.isReadable(0, 0));
QVERIFY(prov.isReadable(16, 0));
}
void testAlignmentFor() {
QCOMPARE(rcx::alignmentFor(rcx::NodeKind::Hex8), 1);
QCOMPARE(rcx::alignmentFor(rcx::NodeKind::Hex16), 2);
QCOMPARE(rcx::alignmentFor(rcx::NodeKind::Hex32), 4);
QCOMPARE(rcx::alignmentFor(rcx::NodeKind::Hex64), 8);
QCOMPARE(rcx::alignmentFor(rcx::NodeKind::Float), 4);
QCOMPARE(rcx::alignmentFor(rcx::NodeKind::Double), 8);
QCOMPARE(rcx::alignmentFor(rcx::NodeKind::Vec3), 4);
QCOMPARE(rcx::alignmentFor(rcx::NodeKind::Mat4x4), 4);
QCOMPARE(rcx::alignmentFor(rcx::NodeKind::UTF8), 1);
QCOMPARE(rcx::alignmentFor(rcx::NodeKind::UTF16), 2);
QCOMPARE(rcx::alignmentFor(rcx::NodeKind::Struct), 1);
}
void testDepthOfCycle() {
rcx::NodeTree tree;
// Create two nodes that reference each other as parents
rcx::Node a; a.kind = rcx::NodeKind::Struct; a.name = "A"; a.parentId = 0;
int ai = tree.addNode(a);
uint64_t aId = tree.nodes[ai].id;
rcx::Node b; b.kind = rcx::NodeKind::Struct; b.name = "B"; b.parentId = aId;
int bi = tree.addNode(b);
uint64_t bId = tree.nodes[bi].id;
// Manually create a cycle: A's parent → B
tree.nodes[ai].parentId = bId;
tree.invalidateIdCache();
// Should not hang — cycle detection terminates
int d = tree.depthOf(ai);
QVERIFY(d < 100);
}
void testComputeOffsetCycle() {
rcx::NodeTree tree;
rcx::Node a; a.kind = rcx::NodeKind::Struct; a.name = "A"; a.parentId = 0; a.offset = 10;
int ai = tree.addNode(a);
uint64_t aId = tree.nodes[ai].id;
rcx::Node b; b.kind = rcx::NodeKind::Struct; b.name = "B"; b.parentId = aId; b.offset = 20;
int bi = tree.addNode(b);
uint64_t bId = tree.nodes[bi].id;
// Create cycle: A → B → A
tree.nodes[ai].parentId = bId;
tree.invalidateIdCache();
// Should not hang
int off = tree.computeOffset(ai);
Q_UNUSED(off);
QVERIFY(true); // reaching here means no hang
}
void testProviderWrite() {
QByteArray data(16, '\0');
rcx::FileProvider prov(data);
QVERIFY(prov.isWritable());
QByteArray patch;
patch.append((char)0x42);
patch.append((char)0x43);
QVERIFY(prov.writeBytes(0, patch));
QCOMPARE(prov.readU8(0), (uint8_t)0x42);
QCOMPARE(prov.readU8(1), (uint8_t)0x43);
// Write past end should fail
QVERIFY(!prov.writeBytes(15, patch));
// NullProvider is not writable
rcx::NullProvider np;
QVERIFY(!np.isWritable());
}
void testComputeOffsetLarge() {
// Verify computeOffset returns int64_t that doesn't overflow
rcx::NodeTree tree;
rcx::Node root; root.kind = rcx::NodeKind::Struct; root.name = "R";
root.parentId = 0; root.offset = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
rcx::Node child; child.kind = rcx::NodeKind::Hex8; child.name = "f";
child.parentId = rootId; child.offset = 0x7FFFFFFF; // max int32
tree.addNode(child);
int64_t off = tree.computeOffset(1);
QCOMPARE(off, (int64_t)0x7FFFFFFF);
}
void testKindMetaCompleteness() {
// Every NodeKind enum value must have a KindMeta entry
for (int i = 0; i <= static_cast<int>(rcx::NodeKind::Array); i++) {
auto kind = static_cast<rcx::NodeKind>(i);
const rcx::KindMeta* m = rcx::kindMeta(kind);
QVERIFY2(m != nullptr,
qPrintable(QString("Missing KindMeta for kind %1").arg(i)));
QCOMPARE(m->kind, kind);
QVERIFY(m->name != nullptr);
QVERIFY(m->typeName != nullptr);
QVERIFY(m->lines >= 1);
QVERIFY(m->align >= 1);
}
// sizeForKind/linesForKind/alignmentFor must agree with table
for (const auto& m : rcx::kKindMeta) {
QCOMPARE(rcx::sizeForKind(m.kind), m.size);
QCOMPARE(rcx::linesForKind(m.kind), m.lines);
QCOMPARE(rcx::alignmentFor(m.kind), m.align);
}
}
void testColumnSpan_field() {
rcx::LineMeta lm;
lm.lineKind = rcx::LineKind::Field;
lm.depth = 1;
lm.isContinuation = false;
lm.nodeIdx = 0;
// kFoldCol (3) + depth*3 = 6
auto ts = rcx::typeSpanFor(lm);
QVERIFY(ts.valid);
QCOMPARE(ts.start, 6);
QCOMPARE(ts.end, 16); // 6 + 10
auto ns = rcx::nameSpanFor(lm);
QVERIFY(ns.valid);
QCOMPARE(ns.start, 18); // 6 + 10 + 2
QCOMPARE(ns.end, 42); // 18 + 24
auto vs = rcx::valueSpanFor(lm, 60);
QVERIFY(vs.valid);
QCOMPARE(vs.start, 44); // 18 + 24 + 2
QCOMPARE(vs.end, 60);
}
void testColumnSpan_continuation() {
rcx::LineMeta lm;
lm.lineKind = rcx::LineKind::Continuation;
lm.depth = 1;
lm.isContinuation = true;
lm.nodeIdx = 0;
QVERIFY(!rcx::typeSpanFor(lm).valid);
QVERIFY(!rcx::nameSpanFor(lm).valid);
auto vs = rcx::valueSpanFor(lm, 60);
QVERIFY(vs.valid);
QCOMPARE(vs.start, 6 + 10 + 24 + 4); // kFoldCol+indent + COL_TYPE + COL_NAME + 4
QCOMPARE(vs.end, 60);
}
void testColumnSpan_headerFooter() {
rcx::LineMeta lm;
lm.lineKind = rcx::LineKind::Header;
lm.depth = 0;
lm.nodeIdx = 0;
QVERIFY(!rcx::typeSpanFor(lm).valid);
QVERIFY(!rcx::nameSpanFor(lm).valid);
QVERIFY(!rcx::valueSpanFor(lm, 40).valid);
lm.lineKind = rcx::LineKind::Footer;
QVERIFY(!rcx::typeSpanFor(lm).valid);
QVERIFY(!rcx::nameSpanFor(lm).valid);
QVERIFY(!rcx::valueSpanFor(lm, 40).valid);
}
void testColumnSpan_depth0() {
rcx::LineMeta lm;
lm.lineKind = rcx::LineKind::Field;
lm.depth = 0;
lm.isContinuation = false;
lm.nodeIdx = 0;
// kFoldCol (3) + depth*3(0) = 3
auto ts = rcx::typeSpanFor(lm);
QVERIFY(ts.valid);
QCOMPARE(ts.start, 3);
QCOMPARE(ts.end, 13); // 3 + 10
auto ns = rcx::nameSpanFor(lm);
QVERIFY(ns.valid);
QCOMPARE(ns.start, 15); // 3 + 10 + 2
QCOMPARE(ns.end, 39); // 15 + 24
auto vs = rcx::valueSpanFor(lm, 50);
QVERIFY(vs.valid);
QCOMPARE(vs.start, 41); // 15 + 24 + 2
QCOMPARE(vs.end, 50);
}
void testNodeIdJsonRoundTrip() {
rcx::NodeTree tree;
rcx::Node n; n.kind = rcx::NodeKind::Float; n.name = "x"; n.parentId = 0;
tree.addNode(n);
tree.addNode(n);
QJsonObject json = tree.toJson();
rcx::NodeTree t2 = rcx::NodeTree::fromJson(json);
QCOMPARE(t2.nodes[0].id, tree.nodes[0].id);
QCOMPARE(t2.nodes[1].id, tree.nodes[1].id);
QVERIFY(t2.m_nextId >= 3);
}
void testStructSpan() {
using namespace rcx;
NodeTree tree;
tree.baseAddress = 0;
// Struct with UInt32 (offset 0, 4 bytes) + UInt64 (offset 4, 8 bytes)
Node root;
root.kind = NodeKind::Struct;
root.name = "Root";
root.parentId = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node f1;
f1.kind = NodeKind::UInt32;
f1.name = "a";
f1.parentId = rootId;
f1.offset = 0;
tree.addNode(f1);
Node f2;
f2.kind = NodeKind::UInt64;
f2.name = "b";
f2.parentId = rootId;
f2.offset = 4;
tree.addNode(f2);
// Span = max(0+4, 4+8) = 12
QCOMPARE(tree.structSpan(rootId), 12);
// Nested struct: inner at offset 0 with a UInt64 at offset 0 (size 8)
NodeTree tree2;
Node outer;
outer.kind = NodeKind::Struct;
outer.name = "Outer";
outer.parentId = 0;
int oi = tree2.addNode(outer);
uint64_t outerId = tree2.nodes[oi].id;
Node inner;
inner.kind = NodeKind::Struct;
inner.name = "Inner";
inner.parentId = outerId;
inner.offset = 0;
int ii = tree2.addNode(inner);
uint64_t innerId = tree2.nodes[ii].id;
Node leaf;
leaf.kind = NodeKind::UInt64;
leaf.name = "x";
leaf.parentId = innerId;
leaf.offset = 0;
tree2.addNode(leaf);
// Inner span = 8, outer span = max(0+8) = 8
QCOMPARE(tree2.structSpan(innerId), 8);
QCOMPARE(tree2.structSpan(outerId), 8);
// Empty struct = 0
NodeTree tree3;
Node empty;
empty.kind = NodeKind::Struct;
empty.name = "Empty";
empty.parentId = 0;
int ei = tree3.addNode(empty);
QCOMPARE(tree3.structSpan(tree3.nodes[ei].id), 0);
}
void testNormalizePreferAncestors() {
using namespace rcx;
NodeTree tree;
// Root -> A -> leaf
Node root; root.kind = NodeKind::Struct; root.name = "R"; root.parentId = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node a; a.kind = NodeKind::Struct; a.name = "A"; a.parentId = rootId;
int ai = tree.addNode(a);
uint64_t aId = tree.nodes[ai].id;
Node leaf; leaf.kind = NodeKind::Hex8; leaf.name = "x"; leaf.parentId = aId;
int li = tree.addNode(leaf);
uint64_t leafId = tree.nodes[li].id;
// Select root + leaf: leaf should be pruned (root is ancestor)
QSet<uint64_t> sel = {rootId, leafId};
QSet<uint64_t> norm = tree.normalizePreferAncestors(sel);
QCOMPARE(norm.size(), 1);
QVERIFY(norm.contains(rootId));
// Select A + leaf: leaf pruned (A is ancestor)
sel = {aId, leafId};
norm = tree.normalizePreferAncestors(sel);
QCOMPARE(norm.size(), 1);
QVERIFY(norm.contains(aId));
// Select root + A: A pruned (root is ancestor)
sel = {rootId, aId};
norm = tree.normalizePreferAncestors(sel);
QCOMPARE(norm.size(), 1);
QVERIFY(norm.contains(rootId));
// Select only leaf: nothing pruned
sel = {leafId};
norm = tree.normalizePreferAncestors(sel);
QCOMPARE(norm.size(), 1);
QVERIFY(norm.contains(leafId));
}
void testNormalizePreferDescendants() {
using namespace rcx;
NodeTree tree;
Node root; root.kind = NodeKind::Struct; root.name = "R"; root.parentId = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node a; a.kind = NodeKind::UInt32; a.name = "a"; a.parentId = rootId;
int ai = tree.addNode(a);
uint64_t aId = tree.nodes[ai].id;
Node b; b.kind = NodeKind::UInt32; b.name = "b"; b.parentId = rootId; b.offset = 4;
int bi = tree.addNode(b);
uint64_t bId = tree.nodes[bi].id;
// Select root + a + b: root dropped (has selected descendants)
QSet<uint64_t> sel = {rootId, aId, bId};
QSet<uint64_t> norm = tree.normalizePreferDescendants(sel);
QCOMPARE(norm.size(), 2);
QVERIFY(norm.contains(aId));
QVERIFY(norm.contains(bId));
QVERIFY(!norm.contains(rootId));
// Select root + a: root dropped, a kept
sel = {rootId, aId};
norm = tree.normalizePreferDescendants(sel);
QCOMPARE(norm.size(), 1);
QVERIFY(norm.contains(aId));
// Select only root: nothing dropped (no descendants selected)
sel = {rootId};
norm = tree.normalizePreferDescendants(sel);
QCOMPARE(norm.size(), 1);
QVERIFY(norm.contains(rootId));
}
};
QTEST_MAIN(TestCore)
#include "test_core.moc"

442
tests/test_editor.cpp Normal file
View File

@@ -0,0 +1,442 @@
#include <QtTest/QTest>
#include <QtTest/QSignalSpy>
#include <QApplication>
#include <QKeyEvent>
#include <QFocusEvent>
#include <Qsci/qsciscintilla.h>
#include "editor.h"
#include "core.h"
using namespace rcx;
// Minimal provider for testing
static FileProvider makeTestProvider() {
QByteArray data(256, '\0');
// Write known values: uint16_t=23117 at offset 0, Hex64 at offset 8
uint16_t u16 = 23117;
memcpy(data.data(), &u16, 2);
uint64_t h64 = 0x4D5A900000000000ULL;
memcpy(data.data() + 8, &h64, 8);
return FileProvider(data);
}
// Build a simple tree with a struct containing a few fields
static NodeTree makeTestTree() {
NodeTree tree;
tree.baseAddress = 0;
Node root;
root.kind = NodeKind::Struct;
root.name = "TestStruct";
root.parentId = 0;
root.offset = 0;
int ri = tree.addNode(root);
uint64_t rootId = tree.nodes[ri].id;
Node f1;
f1.kind = NodeKind::UInt16;
f1.name = "field_u16";
f1.parentId = rootId;
f1.offset = 0;
tree.addNode(f1);
Node f2;
f2.kind = NodeKind::Hex64;
f2.name = "field_hex";
f2.parentId = rootId;
f2.offset = 8;
tree.addNode(f2);
return tree;
}
class TestEditor : public QObject {
Q_OBJECT
private:
RcxEditor* m_editor = nullptr;
ComposeResult m_result;
private slots:
void initTestCase() {
m_editor = new RcxEditor();
m_editor->resize(800, 600);
m_editor->show();
QVERIFY(QTest::qWaitForWindowExposed(m_editor));
NodeTree tree = makeTestTree();
FileProvider prov = makeTestProvider();
m_result = compose(tree, prov);
m_editor->applyDocument(m_result);
}
void cleanupTestCase() {
delete m_editor;
}
// ── Test: inline edit lifecycle (begin → commit → re-edit) ──
void testInlineEditReEntry() {
// Move cursor to line 1 (first field inside struct)
m_editor->scintilla()->setCursorPosition(1, 0);
// Should not be editing
QVERIFY(!m_editor->isEditing());
// Begin edit on Name column
bool ok = m_editor->beginInlineEdit(EditTarget::Name, 1);
QVERIFY(ok);
QVERIFY(m_editor->isEditing());
// Cancel the edit
m_editor->cancelInlineEdit();
QVERIFY(!m_editor->isEditing());
// Re-apply document (simulates controller refresh)
m_editor->applyDocument(m_result);
// Should be able to edit again
ok = m_editor->beginInlineEdit(EditTarget::Name, 1);
QVERIFY(ok);
QVERIFY(m_editor->isEditing());
// Cancel again
m_editor->cancelInlineEdit();
QVERIFY(!m_editor->isEditing());
}
// ── Test: commit inline edit then re-edit same line ──
void testCommitThenReEdit() {
m_editor->applyDocument(m_result);
m_editor->scintilla()->setCursorPosition(1, 0);
// Begin value edit
bool ok = m_editor->beginInlineEdit(EditTarget::Value, 1);
QVERIFY(ok);
QVERIFY(m_editor->isEditing());
// Simulate Enter key → commit (via signal spy)
QSignalSpy spy(m_editor, &RcxEditor::inlineEditCommitted);
QKeyEvent enter(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
QApplication::sendEvent(m_editor->scintilla(), &enter);
// Should have emitted commit signal and exited edit mode
QCOMPARE(spy.count(), 1);
QVERIFY(!m_editor->isEditing());
// Re-apply document (simulates refresh)
m_editor->applyDocument(m_result);
// Must be able to edit the same line again
ok = m_editor->beginInlineEdit(EditTarget::Value, 1);
QVERIFY(ok);
QVERIFY(m_editor->isEditing());
m_editor->cancelInlineEdit();
}
// ── Test: mouse click during edit commits it ──
void testMouseClickCommitsEdit() {
m_editor->applyDocument(m_result);
bool ok = m_editor->beginInlineEdit(EditTarget::Name, 1);
QVERIFY(ok);
QVERIFY(m_editor->isEditing());
// Simulate mouse click on viewport — should commit (save), not cancel
QSignalSpy commitSpy(m_editor, &RcxEditor::inlineEditCommitted);
QSignalSpy cancelSpy(m_editor, &RcxEditor::inlineEditCancelled);
QMouseEvent click(QEvent::MouseButtonPress, QPointF(10, 10),
QPointF(10, 10), Qt::LeftButton,
Qt::LeftButton, Qt::NoModifier);
QApplication::sendEvent(m_editor->scintilla()->viewport(), &click);
QVERIFY(!m_editor->isEditing());
QCOMPARE(commitSpy.count(), 1);
QCOMPARE(cancelSpy.count(), 0);
}
// ── Test: FocusOut during edit commits it ──
void testFocusOutCommitsEdit() {
m_editor->applyDocument(m_result);
// Give focus to the scintilla widget first
m_editor->scintilla()->setFocus();
QApplication::processEvents();
bool ok = m_editor->beginInlineEdit(EditTarget::Name, 1);
QVERIFY(ok);
QVERIFY(m_editor->isEditing());
QSignalSpy commitSpy(m_editor, &RcxEditor::inlineEditCommitted);
QSignalSpy cancelSpy(m_editor, &RcxEditor::inlineEditCancelled);
// Create a dummy widget and transfer focus to it (triggers real FocusOut)
QWidget dummy;
dummy.show();
QVERIFY(QTest::qWaitForWindowExposed(&dummy));
dummy.setFocus();
QApplication::processEvents(); // process focus change + deferred timer
QVERIFY(!m_editor->isEditing());
QCOMPARE(commitSpy.count(), 1);
QCOMPARE(cancelSpy.count(), 0);
// Restore focus to editor for subsequent tests
m_editor->scintilla()->setFocus();
QApplication::processEvents();
}
// ── Test: type edit begins and can be cancelled ──
void testTypeEditCancel() {
m_editor->applyDocument(m_result);
// Begin type edit on a field line
bool ok = m_editor->beginInlineEdit(EditTarget::Type, 1);
QVERIFY(ok);
QVERIFY(m_editor->isEditing());
// Process deferred events (showTypeAutocomplete is deferred via QTimer)
QApplication::processEvents();
// First Escape closes autocomplete popup (if active) or cancels edit
QKeyEvent esc1(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier);
QApplication::sendEvent(m_editor->scintilla(), &esc1);
// If autocomplete was open, first Esc only closed popup; need second Esc
if (m_editor->isEditing()) {
QKeyEvent esc2(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier);
QApplication::sendEvent(m_editor->scintilla(), &esc2);
}
QVERIFY(!m_editor->isEditing());
}
// ── Test: edit on header line (Name is valid, Type/Value invalid) ──
void testHeaderLineEdit() {
m_editor->applyDocument(m_result);
// Line 0 should be the struct header
const LineMeta* lm = m_editor->metaForLine(0);
QVERIFY(lm);
QCOMPARE(lm->lineKind, LineKind::Header);
// Type edit on header should fail (no type span)
bool ok = m_editor->beginInlineEdit(EditTarget::Type, 0);
QVERIFY(!ok);
QVERIFY(!m_editor->isEditing());
// Name edit on header should succeed (dynamic span)
ok = m_editor->beginInlineEdit(EditTarget::Name, 0);
QVERIFY(ok);
QVERIFY(m_editor->isEditing());
m_editor->cancelInlineEdit();
}
// ── Test: footer line rejects all edits ──
void testFooterLineEdit() {
m_editor->applyDocument(m_result);
// Find the footer line
int footerLine = -1;
for (int i = 0; i < m_result.meta.size(); i++) {
if (m_result.meta[i].lineKind == LineKind::Footer) {
footerLine = i;
break;
}
}
QVERIFY(footerLine >= 0);
QVERIFY(!m_editor->beginInlineEdit(EditTarget::Type, footerLine));
QVERIFY(!m_editor->beginInlineEdit(EditTarget::Name, footerLine));
QVERIFY(!m_editor->beginInlineEdit(EditTarget::Value, footerLine));
QVERIFY(!m_editor->isEditing());
}
// ── Test: showTypeAutocomplete populates list (check via SCI_AUTOCACTIVE) ──
void testTypeAutocompleteShows() {
m_editor->applyDocument(m_result);
bool ok = m_editor->beginInlineEdit(EditTarget::Type, 1);
QVERIFY(ok);
// Process deferred timer (autocomplete is deferred)
QApplication::processEvents();
// Check if the user list is active
long active = m_editor->scintilla()->SendScintilla(
QsciScintillaBase::SCI_AUTOCACTIVE);
QVERIFY2(active != 0, "Autocomplete list should be active after type edit begins");
// Cancel
m_editor->cancelInlineEdit();
m_editor->applyDocument(m_result);
}
// ── Test: parseValue accepts space-separated hex bytes ──
void testParseValueHexWithSpaces() {
bool ok;
// Hex8 with spaces (single byte, but test the .remove(' '))
QByteArray b = fmt::parseValue(NodeKind::Hex8, "4D", &ok);
QVERIFY(ok);
QCOMPARE((uint8_t)b[0], (uint8_t)0x4D);
// Hex32 with space-separated bytes
b = fmt::parseValue(NodeKind::Hex32, "DE AD BE EF", &ok);
QVERIFY(ok);
QCOMPARE(b.size(), 4);
uint32_t v32;
memcpy(&v32, b.data(), 4);
QCOMPARE(v32, (uint32_t)0xDEADBEEF);
// Hex64 with space-separated bytes
b = fmt::parseValue(NodeKind::Hex64, "4D 5A 90 00 00 00 00 00", &ok);
QVERIFY(ok);
QCOMPARE(b.size(), 8);
uint64_t v64;
memcpy(&v64, b.data(), 8);
QCOMPARE(v64, (uint64_t)0x4D5A900000000000ULL);
// Hex64 continuous (should still work)
b = fmt::parseValue(NodeKind::Hex64, "4D5A900000000000", &ok);
QVERIFY(ok);
memcpy(&v64, b.data(), 8);
QCOMPARE(v64, (uint64_t)0x4D5A900000000000ULL);
// Hex64 with 0x prefix and spaces
b = fmt::parseValue(NodeKind::Hex64, "0x4D 5A 90 00 00 00 00 00", &ok);
QVERIFY(ok);
}
// ── Test: type autocomplete accepts typed input and commits ──
void testTypeAutocompleteTypingAndCommit() {
m_editor->applyDocument(m_result);
bool ok = m_editor->beginInlineEdit(EditTarget::Type, 1);
QVERIFY(ok);
// Process deferred autocomplete
QApplication::processEvents();
// Verify autocomplete is active
long active = m_editor->scintilla()->SendScintilla(
QsciScintillaBase::SCI_AUTOCACTIVE);
QVERIFY2(active != 0, "Autocomplete should be active");
// Simulate typing 'i' — filters to typeName entries starting with 'i'
QKeyEvent keyI(QEvent::KeyPress, Qt::Key_I, Qt::NoModifier, "i");
QApplication::sendEvent(m_editor->scintilla(), &keyI);
// Still editing
QVERIFY(m_editor->isEditing());
// Simulate Enter to select from autocomplete (handled synchronously)
QSignalSpy spy(m_editor, &RcxEditor::inlineEditCommitted);
QKeyEvent enter(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
QApplication::sendEvent(m_editor->scintilla(), &enter);
// Should have committed immediately (no deferred timer for type edits)
QCOMPARE(spy.count(), 1);
QVERIFY(!m_editor->isEditing());
// The committed text should be a valid typeName starting with 'i'
QList<QVariant> args = spy.first();
QString committedText = args.at(3).toString();
QVERIFY2(committedText.startsWith('i'),
qPrintable("Expected typeName starting with 'i', got: " + committedText));
m_editor->applyDocument(m_result);
}
// ── Test: type edit click-away commits original (no change) ──
void testTypeEditClickAwayNoChange() {
m_editor->applyDocument(m_result);
bool ok = m_editor->beginInlineEdit(EditTarget::Type, 1);
QVERIFY(ok);
// Process deferred autocomplete
QApplication::processEvents();
// Click away on viewport — should commit (not cancel)
QSignalSpy commitSpy(m_editor, &RcxEditor::inlineEditCommitted);
QMouseEvent click(QEvent::MouseButtonPress, QPointF(10, 10),
QPointF(10, 10), Qt::LeftButton,
Qt::LeftButton, Qt::NoModifier);
QApplication::sendEvent(m_editor->scintilla()->viewport(), &click);
QVERIFY(!m_editor->isEditing());
QCOMPARE(commitSpy.count(), 1);
// The committed text should be the original typeName (no change)
QList<QVariant> args = commitSpy.first();
QString committedText = args.at(3).toString();
QVERIFY2(committedText == "uint16_t",
qPrintable("Expected 'uint16_t', got: " + committedText));
m_editor->applyDocument(m_result);
}
// ── Test: column span hit-testing for cursor shape ──
void testColumnSpanHitTest() {
m_editor->applyDocument(m_result);
// Line 1 is a field line (UInt16), verify spans are valid
const LineMeta* lm = m_editor->metaForLine(1);
QVERIFY(lm);
QCOMPARE(lm->lineKind, LineKind::Field);
// Type span should be valid for field lines
ColumnSpan ts = RcxEditor::typeSpan(*lm);
QVERIFY(ts.valid);
QVERIFY(ts.start < ts.end);
// Name span should be valid for field lines
ColumnSpan ns = RcxEditor::nameSpan(*lm);
QVERIFY(ns.valid);
QVERIFY(ns.start < ns.end);
// Value span should be valid for field lines
QString lineText;
int len = (int)m_editor->scintilla()->SendScintilla(
QsciScintillaBase::SCI_LINELENGTH, (unsigned long)1);
QVERIFY(len > 0);
ColumnSpan vs = RcxEditor::valueSpan(*lm, len);
QVERIFY(vs.valid);
QVERIFY(vs.start < vs.end);
// Footer line should have no valid type/name spans
int footerLine = -1;
for (int i = 0; i < m_result.meta.size(); i++) {
if (m_result.meta[i].lineKind == LineKind::Footer) {
footerLine = i;
break;
}
}
QVERIFY(footerLine >= 0);
const LineMeta* flm = m_editor->metaForLine(footerLine);
QVERIFY(flm);
ColumnSpan fts = RcxEditor::typeSpan(*flm);
QVERIFY(!fts.valid);
ColumnSpan fns = RcxEditor::nameSpan(*flm);
QVERIFY(!fns.valid);
ColumnSpan fvs = RcxEditor::valueSpan(*flm, 10);
QVERIFY(!fvs.valid);
}
// ── Test: selectedNodeIndices ──
void testSelectedNodeIndices() {
m_editor->applyDocument(m_result);
// Put cursor on first field line
m_editor->scintilla()->setCursorPosition(1, 0);
QSet<int> sel = m_editor->selectedNodeIndices();
QCOMPARE(sel.size(), 1);
// The node index should match the first field
const LineMeta* lm = m_editor->metaForLine(1);
QVERIFY(lm);
QVERIFY(sel.contains(lm->nodeIdx));
}
};
QTEST_MAIN(TestEditor)
#include "test_editor.moc"

248
tests/test_format.cpp Normal file
View File

@@ -0,0 +1,248 @@
#include <QtTest/QTest>
#include "core.h"
using namespace rcx;
class TestFormat : public QObject {
Q_OBJECT
private slots:
void testTypeName() {
QString s = fmt::typeName(NodeKind::Float);
QVERIFY(s.trimmed() == "float");
QCOMPARE(s.size(), 10); // COL_TYPE
}
void testFmtInt32() {
QCOMPARE(fmt::fmtInt32(-42), QString("-42"));
QCOMPARE(fmt::fmtInt32(0), QString("0"));
}
void testFmtFloat() {
QString s = fmt::fmtFloat(3.14159f);
QVERIFY(s.contains("3.14"));
}
void testFmtBool() {
QCOMPARE(fmt::fmtBool(1), QString("true"));
QCOMPARE(fmt::fmtBool(0), QString("false"));
}
void testFmtPointer64_null() {
QCOMPARE(fmt::fmtPointer64(0), QString("-> NULL"));
}
void testFmtPointer64_nonNull() {
QString s = fmt::fmtPointer64(0x400000);
QVERIFY(s.startsWith("-> 0x"));
QVERIFY(s.contains("400000"));
}
void testFmtOffsetMargin_primary() {
QCOMPARE(fmt::fmtOffsetMargin(0x10, false), QString("+0x10"));
QCOMPARE(fmt::fmtOffsetMargin(0, false), QString("+0x0"));
}
void testFmtOffsetMargin_continuation() {
QCOMPARE(fmt::fmtOffsetMargin(0x10, true), QString(" \u00B7"));
}
void testFmtStructHeader() {
Node n;
n.kind = NodeKind::Struct;
n.name = "Test";
QString s = fmt::fmtStructHeader(n, 0);
QVERIFY(s.contains("struct"));
QVERIFY(s.contains("Test"));
QVERIFY(s.contains("{"));
}
void testFmtStructFooter() {
Node n;
n.kind = NodeKind::Struct;
n.name = "Test";
QString s = fmt::fmtStructFooter(n, 0);
QVERIFY(s.contains("};"));
QVERIFY(s.contains("Test"));
}
void testIndent() {
QCOMPARE(fmt::indent(0), QString(""));
QCOMPARE(fmt::indent(1), QString(" "));
QCOMPARE(fmt::indent(3), QString(" "));
}
void testParseValueInt32() {
bool ok;
QByteArray b = fmt::parseValue(NodeKind::Int32, "-42", &ok);
QVERIFY(ok);
QCOMPARE(b.size(), 4);
int32_t v;
memcpy(&v, b.data(), 4);
QCOMPARE(v, -42);
}
void testParseValueFloat() {
bool ok;
QByteArray b = fmt::parseValue(NodeKind::Float, "3.14", &ok);
QVERIFY(ok);
QCOMPARE(b.size(), 4);
float v;
memcpy(&v, b.data(), 4);
QVERIFY(qAbs(v - 3.14f) < 0.01f);
}
void testParseValueHex32() {
bool ok;
QByteArray b = fmt::parseValue(NodeKind::Hex32, "DEADBEEF", &ok);
QVERIFY(ok);
QCOMPARE(b.size(), 4);
uint32_t v;
memcpy(&v, b.data(), 4);
QCOMPARE(v, (uint32_t)0xDEADBEEF);
}
void testParseValueBool() {
bool ok;
QByteArray b = fmt::parseValue(NodeKind::Bool, "true", &ok);
QVERIFY(ok);
QCOMPARE(b.size(), 1);
QCOMPARE((uint8_t)b[0], (uint8_t)1);
b = fmt::parseValue(NodeKind::Bool, "false", &ok);
QVERIFY(ok);
QCOMPARE((uint8_t)b[0], (uint8_t)0);
// Unknown token should fail
fmt::parseValue(NodeKind::Bool, "banana", &ok);
QVERIFY(!ok);
}
void testParseValueHex0xPrefix() {
bool ok;
// Hex32 with 0x prefix should work
QByteArray b = fmt::parseValue(NodeKind::Hex32, "0xDEADBEEF", &ok);
QVERIFY(ok);
uint32_t v;
memcpy(&v, b.data(), 4);
QCOMPARE(v, (uint32_t)0xDEADBEEF);
// Pointer64 with 0x prefix
b = fmt::parseValue(NodeKind::Pointer64, "0x0000000000400000", &ok);
QVERIFY(ok);
uint64_t v64;
memcpy(&v64, b.data(), 8);
QCOMPARE(v64, (uint64_t)0x400000);
}
void testParseValueOverflow() {
bool ok;
// UInt8: 300 exceeds uint8_t max (255) → should fail
fmt::parseValue(NodeKind::UInt8, "300", &ok);
QVERIFY(!ok);
// UInt8: 255 should succeed
QByteArray b = fmt::parseValue(NodeKind::UInt8, "255", &ok);
QVERIFY(ok);
QCOMPARE((uint8_t)b[0], (uint8_t)255);
// Int8: 200 exceeds int8_t max (127) → should fail
fmt::parseValue(NodeKind::Int8, "200", &ok);
QVERIFY(!ok);
// Int8: -129 below min → should fail
fmt::parseValue(NodeKind::Int8, "-129", &ok);
QVERIFY(!ok);
// Int8: -128 is valid
b = fmt::parseValue(NodeKind::Int8, "-128", &ok);
QVERIFY(ok);
int8_t sv;
memcpy(&sv, b.data(), 1);
QCOMPARE(sv, (int8_t)-128);
// UInt16: 70000 exceeds uint16_t max → should fail
fmt::parseValue(NodeKind::UInt16, "70000", &ok);
QVERIFY(!ok);
// Hex8: 0x1FF exceeds uint8_t → should fail
fmt::parseValue(NodeKind::Hex8, "1FF", &ok);
QVERIFY(!ok);
// Hex16: 0x1FFFF exceeds uint16_t → should fail
fmt::parseValue(NodeKind::Hex16, "1FFFF", &ok);
QVERIFY(!ok);
}
void testReadValueBoundsCheck() {
// Vec2 subLine=2 (out of bounds) should return "?"
QByteArray data(16, '\0');
FileProvider prov(data);
Node n;
n.kind = NodeKind::Vec2;
n.name = "v";
QCOMPARE(fmt::readValue(n, prov, 0, 2), QString("?"));
QCOMPARE(fmt::readValue(n, prov, 0, -1), QString("?"));
// Vec3 subLine=3 (out of bounds)
n.kind = NodeKind::Vec3;
QCOMPARE(fmt::readValue(n, prov, 0, 3), QString("?"));
// Vec3 subLine=2 (valid)
QVERIFY(fmt::readValue(n, prov, 0, 2) != QString("?"));
}
void testEditableValueBasic() {
QByteArray data(16, '\0');
// Write a known float value
float val = 3.14f;
memcpy(data.data(), &val, 4);
FileProvider prov(data);
Node n;
n.kind = NodeKind::Float;
n.name = "f";
QString s = fmt::editableValue(n, prov, 0, 0);
QVERIFY(s.contains("3.14"));
// Vec2 out of bounds → "?"
n.kind = NodeKind::Vec2;
QCOMPARE(fmt::editableValue(n, prov, 0, 2), QString("?"));
}
void testParseValueEmptyString() {
bool ok;
// Empty UTF8 should succeed (caller pads)
QByteArray b = fmt::parseValue(NodeKind::UTF8, "", &ok);
QVERIFY(ok);
QVERIFY(b.isEmpty());
// Empty non-string should fail
fmt::parseValue(NodeKind::Int32, "", &ok);
QVERIFY(!ok);
}
void testFmtStructFooterWithSize() {
Node n;
n.kind = NodeKind::Struct;
n.name = "Test";
// With size
QString s1 = fmt::fmtStructFooter(n, 0, 0x14);
QVERIFY(s1.contains("};"));
QVERIFY(s1.contains("Test"));
QVERIFY(s1.contains("sizeof=0x14"));
// Size 0 → no sizeof
QString s2 = fmt::fmtStructFooter(n, 0, 0);
QVERIFY(s2.contains("};"));
QVERIFY(!s2.contains("sizeof"));
// Default (no size arg) → no sizeof
QString s3 = fmt::fmtStructFooter(n, 0);
QVERIFY(s3.contains("};"));
QVERIFY(!s3.contains("sizeof"));
}
};
QTEST_MAIN(TestFormat)
#include "test_format.moc"

BIN
third_party/QScintilla_src.tar.gz vendored Normal file

Binary file not shown.

6853
third_party/qscintilla/ChangeLog vendored Normal file

File diff suppressed because it is too large Load Diff

674
third_party/qscintilla/LICENSE vendored Normal file
View File

@@ -0,0 +1,674 @@
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>.

604
third_party/qscintilla/NEWS vendored Normal file
View File

@@ -0,0 +1,604 @@
v2.14.1 7th June 2023
- Bug fixes.
v2.14.0 24th April 2023
- Added the QsciLexerAsm, QsciLexerMASM and QsciLexerNASM classes.
- Added the QsciLexerHex, QsciLexerIntelHex, QsciLexerSRec and
QsciLexerTekHex classes.
- Bug fixes.
v2.13.4 6th December 2022
- Added the .api files for Python v3.10 and v3.11.
- Bug fixes.
v2.13.3 25th April 2022
- Bug fixes.
v2.13.2 15th March 2022
- Bug fixes that only affect iOS.
v2.13.1 12th October 2021
- Documented how to build for multiple architectures on macOS.
- Bug fixes.
v2.13.0 13th June 2021
- Added the QsciPrinter::printRange() overload that uses a supplied QPainter
to render the pages.
- Improved the appearence of the auto-completion popup.
- Bug fixes.
v2.12.1 4th March 2021
- Packaging bug fixes.
v2.12.0 23rd February 2021
- Added support for Qt6.
- Removed support for Qt4 and Qt5 earlier than v5.11.0.
- sdists are now provided.
v2.11.6 23rd November 2020
- Added the --qsci-translations-dir option to sip-wheel.
- Added the .api file for Python v3.9.
- Build system changes.
- Bug fixes.
v2.11.5 10th June 2020
- The bundled .api files are now included in Python wheels if the
QScintilla.api file is enabled.
- Bug fixes.
v2.11.4 19th December 2019
- An administrative release with no code changes.
v2.11.3 3rd November 2019
- Added support for SIP v5.
- On macOS the install name of the C++ library is now relative to @rpath.
v2.11.2 26th June 2019
- Added QsciScintilla::findMatchingBrace().
- QsciScintiila::clear() is no longer undoable and instead clears the undo
history.
- Added support for building with WASM.
- Added the .api file for Python v3.8.
- Bug fixes.
v2.11.1 14th February 2019
- There is a small (but potentially incompatible) change to the signature of
a QsciScintillaBase::SendScintilla() overload which may require an explicit
cast to be added.
- Bug fixes.
v2.11 10th February 2019
- Based on Scintilla v3.10.1.
- Added setCaretLineFrameWidth() to QsciScintilla.
- The findFirst() and findFirstInSelection() methods of QsciScintilla now
support Cxx11 regular expressions.
- Added cancelFind() to QsciScintilla.
- Added GradientIndicator and CentreGradientIndicator to
QsciScintilla::IndicatorStyle.
- Added WrapIndentDeeplyIndented to QsciScintilla::WrapIndentMode.
- Added ReverseLines to QsciCommand::Command.
- Deprecated QsciLexer::styleBitsNeeded().
- Added the AddingPatchAdded, RemovingPatchAdded, AddingPatchRemoved and
RemovingPatchRemoved styles to QsciLexerDiff.
- Added the DoubleQuotedFString, SingleQuotedFString,
TripleSingleQuotedFString and TripleDoubleQuotedFString styles to
QsciLexerPython.
- Added SCLEX_INDENT, SCLEX_MAXIMA and SCLEX_STATA to QsciScintillaBase.
- Added SCI_SETACCESSIBILITY, SCI_GETACCESSIBILITY, SCI_GETCARETLINEFRAME,
SCI_SETCARETLINEFRAME, SCI_SETCOMMANDEVENTS, SCI_GETCOMMANDEVENTS,
SCI_LINEREVERSE and SCI_GETMOVEEXTENDSSELECTION to QsciScintillaBase.
- Added SCI_GETLINECHARACTERINDEX, SCI_ALLOCATELINECHARACTERINDEX,
SCI_RELEASELINECHARACTERINDEX, SCI_LINEFROMINDEXPOSITION,
SCI_INDEXPOSITIONFROMLINE, SCI_COUNTCODEUNITS and
SCI_POSITIONRELATIVECODEUNITS to QsciScintillaBase.
- Added SC_LINECHARACTERINDEX_NONE, SC_LINECHARACTERINDEX_UTF32 and
SC_LINECHARACTERINDEX_UTF16 to QsciScintillaBase.
- Added SCI_GETNAMEDSTYLES, SCI_NAMEOFSTYLE, SCI_TAGSOFSTYLE and
SCI_DESCRIPTIONOFSTYLE to QsciScintillaBase.
- Added the SCN_AUTOCSELECTIONCHANGE and SCN_URIDROPPED() signals to
QsciScintillaBase.
- Added the overloaded SCN_USERLISTSELECTION() signal to QsciScintillaBase.
- Added INDIC_GRADIENT and INDIC_GRADIENTCENTRE to QsciScintillaBase.
- Added SC_PRINT_SCREENCOLOURS to QsciScintillaBase.
- Added SC_WRAPINDENT_DEEPINDENT to QsciScintillaBase.
- Added SCI_GETDOCUMENTOPTIONS, SC_DOCUMENTOPTION_DEFAULT,
SC_DOCUMENTOPTION_STYLES_NONE and SC_DOCUMENTOPTION_TEXT_LARGE to
QsciScintillaBase.
v2.10.8 1st October 2018
- Bug fixes.
v2.10.7 2nd July 2018
- Bug fixes.
v2.10.6 24th June 2018
- A pseudo-release to create a version number for updated Python wheels.
v2.10.5 23rd June 2018
- Added the QsciLexerEDIFACT class.
- Added setStyle() to QsciStyle.
- Control-wheel scroll will now zoom in and out of the document.
- Buffered drawing is now disabled by default.
- The Python bindings create a PEP 376 .dist-info directory on installation
that provides version information for dependent packages and allows pip to
uninstall.
- Added the --no-dist-info option to the Python bindings' configure.py.
- Bug fixes.
v2.10.4 10th April 2018
- Bug fixes.
v2.10.3 26th February 2018
- Added accessibility support.
- Added the API file for Python v3.7.
v2.10.2 23rd November 2017
- Added setScrollWidth() , scrollWidth, setScrollWidthTracking() and
scrollWidthTracking() to QsciScintilla.
- Bug fixes.
v2.10.1 3rd July 2017
- Changed the default font on macOS to Menlo 12pt.
- Added previously internal lexer methods to the Python bindings.
v2.10 20th February 2017
- Based on Scintilla v3.7.2.
- Added the QsciLexerJSON class.
- Added the QsciLexerMarkdown class.
- Added replaceHorizontalScrollBar() and replaceVerticalScrollBar() to
QsciScintillaBase.
- Added bytes() and a corresponding text() overload to QsciScintilla.
- Added EdgeMultipleLines to QsciScintilla::EdgeMode.
- Added addEdgeColumn() and clearEdgeColumns() to QsciScintilla.
- Added the marginRightClicked() signal to QsciScintilla.
- Added SymbolMarginColor to QsciScintilla::MarginType.
- Added setMarginBackgroundColor() and marginBackgroundColor() to
QsciScintilla.
- Added setMargins() and margins() to QsciScintilla.
- Added TriangleIndicator and TriangleCharacterIndicator to
QsciScintilla::IndicatorStyle.
- Added WsVisibleOnlyInIndent to QsciScintilla::WhitespaceVisibility.
- Added TabDrawMode, setTabDrawMode() and tabDrawMode() to QsciScintilla.
- Added InstanceProperty to QsciLexerCoffeeScript.
- Added EDGE_MULTILINE to QsciScintillaBase.
- Added INDIC_POINT and INDIC_POINTCHARACTER to QsciScintillaBase.
- Added SC_AC_FILLUP, SC_AC_DOUBLECLICK, SC_AC_TAB, SC_AC_NEWLINE and
SC_AC_COMMAND to QsciScintillaBase.
- Added SC_CASE_CAMEL to QsciScintillaBase.
- Added SC_CHARSET_CYRILLIC and SC_CHARSET_OEM866 to QsciScintillaBase.
- Added SC_FOLDDISPLAYTEXT_HIDDEN, SC_FOLDDISPLAYTEXT_STANDARD and
SC_FOLDDISPLAYTEXT_BOXED to QsciScintillaBase.
- Added SC_IDLESTYLING_NONE, SC_IDLESTYLING_TOVISIBLE,
SC_IDLESTYLING_AFTERVISIBLE and SC_IDLESTYLING_ALL to QsciScintillaBase.
- Added SC_MARGIN_COLOUR to QsciScintillaBase.
- Added SC_POPUP_NEVER, SC_POPUP_ALL and SC_POPUP_TEXT to QsciScintillaBase.
- Added SCI_FOLDDISPLAYTEXTSETSTYLE and SCI_TOGGLEFOLDSHOWTEXT to
QsciScintillaBase.
- Added SCI_GETIDLESTYLING and SCI_SETIDLESTYLING to QsciScintillaBase.
- Added SCI_GETMARGINBACKN and SCI_SETMARGINBACKN to QsciScintillaBase.
- Added SCI_GETMARGINS and SCI_SETMARGINS to QsciScintillaBase.
- Added SCI_GETMOUSEWHEELCAPTURES and SCI_SETMOUSEWHEELCAPTURES to
QsciScintillaBase.
- Added SCI_GETTABDRAWMODE and SCI_SETTABDRAWMODE to QsciScintillaBase.
- Added SCI_ISRANGEWORD to QsciScintillaBase.
- Added SCI_MULTIEDGEADDLINE and SCI_MULTIEDGECLEARALL to QsciScintillaBase.
- Added SCI_MULTIPLESELECTADDNEXT and SCI_MULTIPLESELECTADDEACH to
QsciScintillaBase.
- Added SCI_TARGETWHOLEDOCUMENT to QsciScintillaBase.
- Added SCLEX_JSON and SCLEX_EDIFACT to QsciScintillaBase.
- Added SCTD_LONGARROW and SCTD_STRIKEOUT to QsciScintillaBase.
- Added SCVS_NOWRAPLINESTART to QsciScintillaBase.
- Added SCWS_VISIBLEONLYININDENT to QsciScintillaBase.
- Added STYLE_FOLDDISPLAYTEXT to QsciScintillaBase.
- Added the SCN_AUTOCCOMPLETED() signal to QsciScintillaBase.
- Added the overloaded SCN_AUTOCSELECTION() and SCN_USERLISTSELECTION()
signals to QsciScintillaBase.
- Added the SCN_MARGINRIGHTCLICK() signal to QsciScintillaBase.
- Renamed SCI_GETTARGETRANGE to SCI_GETTARGETTEXT in QsciScintillaBase.
- Removed SCI_GETKEYSUNICODE and SCI_SETKEYSUNICODE to QsciScintillaBase.
- The autoCompletionFillups(), autoCompletionWordSeparators(), blockEnd(),
blockLookback(), blockStart(), blockStartKeyword(), braceStyle(),
caseSensitive(), indentationGuideView() and defaultStyle() methods of
QsciLexer are no longer marked as internal and are exposed to Python so
that they may be used by QsciLexerCustom sub-classes.
- The name of the library has been changed to include the major version
number of the version of Qt it is built against (ie. 4 or 5).
v2.9.4 25th December 2016
- Added the .api file for Python v3.6.
- Bug fixes.
v2.9.3 25th July 2016
- Bug fixes.
v2.9.2 18th April 2016
- Added support for a PEP 484 stub file for the Python extension module.
v2.9.1 24th October 2015
- Added the .api file for Python v3.5.
- Bug fixes.
v2.9 20th April 2015
- Based on Scintilla v3.5.4.
- Added UserLiteral, InactiveUserLiteral, TaskMarker, InactiveTaskMarker,
EscapeSequence, InactiveEscapeSequence, setHighlightBackQuotedStrings(),
highlightBackQuotedStrings(), setHighlightEscapeSequences(),
highlightEscapeSequences(), setVerbatimStringEscapeSequencesAllowed() and
verbatimStringEscapeSequencesAllowed() to QsciLexerCPP.
- Added CommentKeyword, DeclareInputPort, DeclareOutputPort,
DeclareInputOutputPort, PortConnection and the inactive versions of all
styles to QsciLexerVerilog.
- Added CommentBlock to QsciLexerVHDL.
- Added AnnotationIndented to QsciScintilla::AnnotationDisplay.
- Added FullBoxIndicator, ThickCompositionIndicator, ThinCompositionIndicator
and TextColorIndicator to QsciScintilla::IndicatorStyle.
- Added setIndicatorHoverForegroundColor() and setIndicatorHoverStyle() to
QsciScintilla.
- Added Bookmark to QsciScintilla::MarkerSymbol.
- Added WrapWhitespace to QsciScintilla::WrapMode.
- Added SCLEX_AS, SCLEX_BIBTEX, SCLEX_DMAP, SCLEX_DMIS, SCLEX_IHEX,
SCLEX_REGISTRY, SCLEX_SREC and SCLEX_TEHEX to QsciScintillaBase.
- Added SCI_CHANGEINSERTION to QsciScintillaBase.
- Added SCI_CLEARTABSTOPS, SCI_ADDTABSTOP and SCI_GETNEXTTABSTOP to
QsciScintillaBase.
- Added SCI_GETIMEINTERACTION, SCI_SETIMEINTERACTION, SC_IME_WINDOWED and
SC_IME_INLINE to QsciScintillaBase.
- Added SC_MARK_BOOKMARK to QsciScintillaBase.
- Added INDIC_COMPOSITIONTHIN, INDIC_FULLBOX, INDIC_TEXTFORE, INDIC_IME,
INDIC_IME_MAX, SC_INDICVALUEBIT, SC_INDICVALUEMASK,
SC_INDICFLAG_VALUEBEFORE, SCI_INDICSETHOVERSTYLE, SCI_INDICGETHOVERSTYLE,
SCI_INDICSETHOVERFORE, SCI_INDICGETHOVERFORE, SCI_INDICSETFLAGS and
SCI_INDICGETFLAGS to QsciScintillaBase.
- Added SCI_SETTARGETRANGE and SCI_GETTARGETRANGE to QsciScintillaBase.
- Added SCFIND_CXX11REGEX to QsciScintillaBase.
- Added SCI_CALLTIPSETPOSSTART to QsciScintillaBase.
- Added SC_FOLDFLAG_LINESTATE to QsciScintillaBase.
- Added SC_WRAP_WHITESPACE to QsciScintillaBase.
- Added SC_PHASES_ONE, SC_PHASES_TWO, SC_PHASES_MULTIPLE, SCI_GETPHASESDRAW
and SCI_SETPHASESDRAW to QsciScintillaBase.
- Added SC_STATUS_OK, SC_STATUS_FAILURE, SC_STATUS_BADALLOC,
SC_STATUS_WARN_START and SC_STATUS_WARNREGEX to QsciScintillaBase.
- Added SC_MULTIAUTOC_ONCE, SC_MULTIAUTOC_EACH, SCI_AUTOCSETMULTI and
SCI_AUTOCGETMULTI to QsciScintillaBase.
- Added ANNOTATION_INDENTED to QsciScintillaBase.
- Added SCI_DROPSELECTIONN to QsciScintillaBase.
- Added SC_TECHNOLOGY_DIRECTWRITERETAIN and SC_TECHNOLOGY_DIRECTWRITEDC to
QsciScintillaBase.
- Added SC_LINE_END_TYPE_DEFAULT, SC_LINE_END_TYPE_UNICODE,
SCI_GETLINEENDTYPESSUPPORTED, SCI_SETLINEENDTYPESALLOWED,
SCI_GETLINEENDTYPESALLOWED and SCI_GETLINEENDTYPESACTIVE to
QsciScintillaBase.
- Added SCI_ALLOCATESUBSTYLES, SCI_GETSUBSTYLESSTART, SCI_GETSUBSTYLESLENGTH,
SCI_GETSTYLEFROMSUBSTYLE, SCI_GETPRIMARYSTYLEFROMSTYLE, SCI_FREESUBSTYLES,
SCI_SETIDENTIFIERS, SCI_DISTANCETOSECONDARYSTYLES and SCI_GETSUBSTYLEBASES
to QsciScintillaBase.
- Added SC_MOD_INSERTCHECK and SC_MOD_CHANGETABSTOPS to QsciScintillaBase.
- Qt v3 and PyQt v3 are no longer supported.
v2.8.4 11th September 2014
- Added setHotspotForegroundColor(), resetHotspotForegroundColor(),
setHotspotBackgroundColor(), resetHotspotBackgroundColor(),
setHotspotUnderline() and setHotspotWrap() to QsciScintilla.
- Added SCI_SETHOTSPOTSINGLELINE to QsciScintillaBase.
- Bug fixes.
v2.8.3 3rd July 2014
- Added the QsciLexerCoffeeScript class.
- Font sizes are now handled as floating point values rather than integers.
- Bug fixes.
v2.8.2 26th May 2014
- Added the QsciLexerAVS class.
- Added the QsciLexerPO class.
- Added the --sysroot, --no-sip-files and --no-qsci-api options to the Python
bindings' configure.py.
- Cross-compilation (specifically to iOS and Android) is now supported.
- configure.py has been refactored and relicensed so that it can be used as a
template for wrapping other bindings.
- Bug fixes.
v2.8.1 14th March 2014
- Added support for iOS and Android.
- Added support for retina displays.
- A qscintilla2.prf file is installed so that application .pro files only
need to add CONFIG += qscintilla2.
- Updated the keywords recognised by the Octave lexer.
- Bug fixes.
v2.8 9th November 2013
- Based on Scintilla v3.3.6.
- Added the SCN_FOCUSIN() and SCN_FOCUSOUT() signals to QsciScintillaBase.
- Added PreProcessorCommentLineDoc and InactivePreProcessorCommentLineDoc to
QsciLexerCPP.
- Added SCLEX_LITERATEHASKELL, SCLEX_KVIRC, SCLEX_RUST and SCLEX_STTXT to
QsciScintillaBase.
- Added ThickCompositionIndicator to QsciScintilla::IndicatorStyle.
- Added INDIC_COMPOSITIONTHICK to QsciScintillaBase.
- Added SC_FOLDACTION_CONTRACT, SC_FOLDACTION_EXPAND and SC_FOLDACTION_TOGGLE
to QsciScintillaBase.
- Added SCI_FOLDLINE, SCI_FOLDCHILDREN, SCI_EXPANDCHILDREN and SCI_FOLDALL to
QsciScintillaBase.
- Added SC_AUTOMATICFOLD_SHOW, SC_AUTOMATICFOLD_CLICK and
SC_AUTOMATICFOLD_CHANGE to QsciScintillaBase.
- Added SCI_SETAUTOMATICFOLD and SCI_GETAUTOMATICFOLD to QsciScintillaBase.
- Added SC_ORDER_PRESORTED, SC_ORDER_PERFORMSORT and SC_ORDER_CUSTOM to
QsciScintillaBase.
- Added SCI_AUTOCSETORDER and SCI_AUTOCGETORDER to QsciScintillaBase.
- Added SCI_POSITIONRELATIVE to QsciScintillaBase.
- Added SCI_RELEASEALLEXTENDEDSTYLES and SCI_ALLOCATEEXTENDEDSTYLES to
QsciScintillaBase.
- Added SCI_SCROLLRANGE to QsciScintillaBase.
- Added SCI_SETCARETLINEVISIBLEALWAYS and SCI_GETCARETLINEVISIBLEALWAYS to
QsciScintillaBase.
- Added SCI_SETMOUSESELECTIONRECTANGULARSWITCH and
SCI_GETMOUSESELECTIONRECTANGULARSWITCH to QsciScintillaBase.
- Added SCI_SETREPRESENTATION, SCI_GETREPRESENTATION and
SCI_CLEARREPRESENTATION to QsciScintillaBase.
- Input methods are now properly supported.
v2.7.2 16th June 2013
- The build script for the Python bindings now has a --pyqt argument for
specifying PyQt4 or PyQt5.
- The default EOL mode on OS/X is now EolUnix.
- Bug fixes.
v2.7.1 1st March 2013
- Added support for the final release of Qt v5.
- The build script for the Python bindings should now work with SIP v5.
- Bug fixes.
v2.7 8th December 2012
- Based on Scintilla v3.2.3.
- Added support for Qt v5-rc1.
- Added HashQuotedString, InactiveHashQuotedString, PreProcessorComment,
InactivePreProcessorComment, setHighlightHashQuotedStrings() and
highlightHashQuotedStrings() to QsciLexerCpp.
- Added Variable, setHSSLanguage(), HSSLanguage(), setLessLanguage(),
LessLanguage(), setSCCSLanguage() and SCCSLanguage() to QsciLexerCSS.
- Added setOverwriteMode() and overwriteMode() to QsciScintilla.
- Added wordAtLineIndex() to QsciScintilla.
- Added findFirstInSelection() to QsciScintilla.
- Added CallTipsPosition, callTipsPosition() and setCallTipsPosition() to
QsciScintilla.
- Added WrapFlagInMargin to QsciScintilla::WrapVisualFlag.
- Added SquigglePixmapIndicator to QsciScintilla::IndicatorStyle.
- The weight of a font (rather than whether it is just bold or not) is now
respected.
- Added SCLEX_AVS, SCLEX_COFFEESCRIPT, SCLEX_ECL, SCLEX_OSCRIPT,
SCLEX_TCMD and SCLEX_VISUALPROLOG to QsciScintillaBase.
- Added SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE and
SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE to QsciScintillaBase.
- Added SC_FONT_SIZE_MULTIPLIER to QsciScintillaBase.
- Added SC_WEIGHT_NORMAL, SC_WEIGHT_SEMIBOLD and SC_WEIGHT_BOLD to
QsciScintillaBase.
- Added SC_WRAPVISUALFLAG_MARGIN to QsciScintillaBase.
- Added INDIC_SQUIGGLEPIXMAP to QsciScintillaBase.
- Added SCI_AUTOCSETCASEINSENSITIVEBEHAVIOUR,
SCI_AUTOCGETCASEINSENSITIVEBEHAVIOUR, SCI_CALLTIPSETPOSITION,
SCI_COUNTCHARACTERS, SCI_CREATELOADER, SCI_DELETERANGE,
SCI_FINDINDICATORFLASH, SCI_FINDINDICATORHIDE, SCI_FINDINDICATORSHOW,
SCI_GETALLLINESVISIBLE, SCI_GETGAPPOSITION, SCI_GETPUNCTUATIONCHARS,
SCI_GETRANGEPOINTER, SCI_GETSELECTIONEMPTY, SCI_GETTECHNOLOGY,
SCI_GETWHITESPACECHARS, SCI_GETWORDCHARS, SCI_RGBAIMAGESETSCALE,
SCI_SETPUNCTUATIONCHARS, SCI_SETTECHNOLOGY, SCI_STYLESETSIZEFRACTIONAL,
SCI_STYLEGETSIZEFRACTIONAL, SCI_STYLESETWEIGHT and SCI_STYLEGETWEIGHT to
QsciScintillaBase.
- Removed SCI_GETUSEPALETTE and SCI_SETUSEPALETTE from QsciScintillaBase.
- Bug fixes.
v2.6.2 20th June 2012
- Added support for Qt v5-alpha.
- QsciLexer::wordCharacters() is now part of the public API.
- Bug fixes.
v2.6.1 10th February 2012
- Support SCI_NAMESPACE to enable all internal Scintilla classes to be put
into the Scintilla namespace.
- APIs now allow for spaces between the end of a word and the opening
parenthesis.
- Building against Qt v3 is fixed.
v2.6 11th November 2011
- Based on Scintilla v2.29.
- Added Command, command() and execute() to QsciCommand.
- Added boundTo() and find() to QsciCommandSet.
- Added createStandardContextMenu() to QsciScintilla.
- Added StraightBoxIndicator, DashesIndicator, DotsIndicator,
SquiggleLowIndicator and DotBoxIndicator to QsciScintilla::IndicatorStyle.
- Added markerDefine() to QsciScintilla.
- Added MoNone, MoSublineSelect, marginOptions() and setMarginOptions() to
QsciScintilla.
- Added registerImage() to QsciScintilla.
- Added setIndicatorOutlineColor() to QsciScintilla.
- Added setMatchedBraceIndicator(), resetMatchedBraceIndicator(),
setUnmatchedBraceIndicator() and resetUnmatchedBraceIndicator() to
QsciScintilla.
- Added highlightTripleQuotedStrings() and setHighlightTripleQuotedStrings()
to QsciLexerCpp.
- Added Label to QsciLexerLua.
- Added DoubleQuotedStringVar, Translation, RegexVar, SubstitutionVar,
BackticksVar, DoubleQuotedHereDocumentVar, BacktickHereDocumentVar,
QuotedStringQQVar, QuotedStringQXVar, QuotedStringQRVar, setFoldAtElse()
and foldAtElse() to QsciLexerPerl.
- Added highlightSubidentifiers() and setHighlightSubidentifiers() to
QsciLexerPython.
- Added INDIC_STRAIGHTBOX, INDIC_DASH, INDIC_DOTS, INDIC_SQUIGGLELOW and
INDIC_DOTBOX to QsciScintillaBase.
- Added SC_MARGINOPTION_NONE and SC_MARGINOPTION_SUBLINESELECT to
QsciScintillaBase.
- Added SC_MARK_RGBAIMAGE to QsciScintillaBase.
- Added SCI_BRACEBADLIGHTINDICATOR, SCI_BRACEHIGHLIGHTINDICATOR,
SCI_GETIDENTIFIER, SCI_GETMARGINOPTIONS, SCI_INDICGETOUTLINEALPHA,
SCI_INDICSETOUTLINEALPHA, SCI_MARKERDEFINERGBAIMAGE,
SCI_MARKERENABLEHIGHLIGHT, SCI_MARKERSETBACKSELECTED,
SCI_MOVESELECTEDLINESDOWN, SCI_MOVESELECTEDLINESUP, SCI_REGISTERRGBAIMAGE,
SCI_RGBAIMAGESETHEIGHT, SCI_RGBAIMAGESETWIDTH, SCI_SCROLLTOEND,
SCI_SCROLLTOSTART, SCI_SETEMPTYSELECTION, SCI_SETIDENTIFIER and
SCI_SETMARGINOPTIONS to QsciScintillaBase.
v2.5.1 17th April 2011
- Added QsciLexerMatlab and QsciLexerOctave.
v2.5 29th March 2011
- Based on Scintilla v2.25.
- Rectangular selections are now fully supported and compatible with SciTE.
- The signature of the fromMimeData() and toMimeData() methods of
QsciScintillaBase have changed incompatibly in order to support rectangular
selections.
- Added QsciScintilla::setAutoCompletionUseSingle() to replace the now
deprecated setAutoCompletionShowSingle().
- Added QsciScintilla::autoCompletionUseSingle() to replace the now
deprecated autoCompletionShowSingle().
- QsciScintilla::setAutoCompletionCaseSensitivity() is no longer ignored if a
lexer has been set.
- Added FullRectangle, LeftRectangle and Underline to the
QsciScintilla::MarkerSymbol enum.
- Added setExtraAscent(), extraAscent(), setExtraDescent() and extraDescent()
to QsciScintilla.
- Added setWhitespaceSize() and whitespaceSize() to QsciScintilla.
- Added replaceSelectedText() to QsciScintilla.
- Added setWhitespaceBackgroundColor() and setWhitespaceForegroundColor() to
QsciScintilla.
- Added setWrapIndentMode() and wrapIndentMode() to QsciScintilla.
- Added setFirstVisibleLine() to QsciScintilla.
- Added setContractedFolds() and contractedFolds() to QsciScintilla.
- Added the SCN_HOTSPOTRELEASECLICK() signal to QsciScintillaBase.
- The signature of the QsciScintillaBase::SCN_UPDATEUI() signal has changed.
- Added the RawString and inactive styles to QsciLexerCPP.
- Added MediaRule to QsciLexerCSS.
- Added BackquoteString, RawString, KeywordSet5, KeywordSet6 and KeywordSet7
to QsciLexerD.
- Added setDjangoTemplates(), djangoTemplates(), setMakoTemplates() and
makoTemplates() to QsciLexerHTML.
- Added KeywordSet5, KeywordSet6, KeywordSet7 and KeywordSet8 to
QsciLexerLua.
- Added setInitialSpaces() and initialSpaces() to QsciLexerProperties.
- Added setFoldCompact(), foldCompact(), setStringsOverNewlineAllowed() and
stringsOverNewlineAllowed() to QsciLexerPython.
- Added setFoldComments(), foldComments(), setFoldCompact() and foldCompact()
to QsciLexerRuby.
- Added setFoldComments() and foldComments(), and removed setFoldCompact()
and foldCompact() from QsciLexerTCL.
- Added setFoldComments(), foldComments(), setFoldCompact(), foldCompact(),
setProcessComments(), processComments(), setProcessIf(), and processIf() to
QsciLexerTeX.
- Added QuotedIdentifier, setDottedWords(), dottedWords(), setFoldAtElse(),
foldAtElse(), setFoldOnlyBegin(), foldOnlyBegin(), setHashComments(),
hashComments(), setQuotedIdentifiers() and quotedIdentifiers() to
QsciLexerSQL.
- The Python bindings now allow optional arguments to be specified as keyword
arguments.
- The Python bindings will now build using the protected-is-public hack if
possible.
v2.4.6 23rd December 2010
- Added support for indicators to the high-level API, i.e. added the
IndicatorStyle enum, the clearIndicatorRange(), fillIndicatorRange(),
indicatorDefine(), indicatorDrawUnder(), setIndicatorDrawUnder() and
setIndicatorForegroundColor methods, and the indicatorClicked() and
indicatorReleased() signals to QsciScintilla.
- Added support for the Key style in QsciLexerProperties.
- Added an API file for Python v2.7.
- Added the --no-timestamp command line option to the Python bindings'
configure.py.
v2.4.5 31st August 2010
- A bug fix release.
v2.4.4 12th July 2010
- Added the canInsertFromMimeData(), fromMimeData() and toMimeData() methods
to QsciScintillaBase.
- QsciScintilla::markerDefine() now allows existing markers to be redefined.
v2.4.3 17th March 2010
- Added clearFolds() to QsciScintilla.
v2.4.2 20th January 2010
- Updated Spanish translations from Jaime Seuma.
- Fixed compilation problems with Qt v3 and Qt v4 prior to v4.5.
v2.4.1 14th January 2010
- Added the QsciLexerSpice and QsciLexerVerilog classes.
- Significant performance improvements when handling long lines.
- The Python bindings include automatically generated docstrings by default.
- Added an API file for Python v3.
v2.4 5th June 2009
- Based on Scintilla v1.78.
- Added the QsciLexerCustom, QsciStyle and QsciStyledText classes.
- Added annotate(), annotation(), clearAnnotations(), setAnnotationDisplay()
and annotationDisplay() to QsciScintilla.
- Added setMarginText(), clearMarginText(), setMarginType() and marginType()
to QsciScintilla.
- Added QsciLexer::lexerId() so that container lexers can be implemented.
- Added editor() and styleBitsNeeded() to QsciLexer.
- Added setDollarsAllowed() and dollarsAllowed() to QsciLexerCPP.
- Added setFoldScriptComments(), foldScriptComments(),
setFoldScriptHeredocs() and foldScriptHeredocs() to QsciLexerHTML.
- Added setSmartHighlighting() and smartHighlighting() to QsciLexerPascal.
(Note that the Scintilla Pascal lexer has changed so that any saved colour
and font settings will not be properly restored.)
- Added setFoldPackages(), foldPackages(), setFoldPODBlocks() and
foldPODBlocks() to QsciLexerPerl.
- Added setV2UnicodeAllowed(), v2UnicodeAllowed(), setV3BinaryOctalAllowed(),
v3BinaryOctalAllowed(), setV3BytesAllowed and v3BytesAllowed() to
QsciLexerPython.
- Added setScriptsStyled() and scriptsStyled() to QsciLexerXML.
- Added Spanish translations from Jaime Seuma.
v2.3.2 17th November 2008
- A bug fix release.
v2.3.1 6th November 2008
- Based on Scintilla v1.77.
- Added the read() and write() methods to QsciScintilla to allow a file to be
read and written while minimising the conversions.
- Added the positionFromLineIndex() and lineIndexFromPosition() methods to
QsciScintilla to convert between a Scintilla character address and a
QScintilla character address.
- Added QsciScintilla::wordAtPoint() to return the word at the given screen
coordinates.
- QSciScintilla::setSelection() now allows the carat to be left at either the
start or the end of the selection.
- 'with' is now treated as a keyword by the Python lexer.
v2.3 20th September 2008
- Based on Scintilla v1.76.
- The new QsciAbstractAPIs class allows applications to replace the default
implementation of the language APIs used for auto-completion lists and call
tips.
- Added QsciScintilla::apiContext() to allow applications to determine the
context used for auto-completion and call tips.
- Added the QsciLexerFortran, QsciLexerFortran77, QsciLexerPascal,
QsciLexerPostScript, QsciLexerTCL, QsciLexerXML and QsciLexerYAML classes.
- QsciScintilla::setFolding() will now accept an optional margin number.
v2.2 27th February 2008
- Based on Scintilla v1.75.
- A lexer's default colour, paper and font are now written to and read from
the settings.
- Windows64 is now supported.
- The signature of the QsciScintillaBase::SCN_MACRORECORD() signal has
changed slightly.
- Changed the licensing to match the current Qt licenses, including GPL v3.
v2.1 1st June 2007
- A slightly revised API, incompatible with QScintilla v2.0.
- Lexers now remember their style settings. A lexer no longer has to be the
current lexer when changing a style's color, end-of-line fill, font or
paper.
- The color(), eolFill(), font() and paper() methods of QsciLexer now return
the current values for a style rather than the default values.
- The setDefaultColor(), setDefaultFont() and setDefaultPaper() methods of
QsciLexer are no longer slots and no longer virtual.
- The defaultColor(), defaultFont() and defaultPaper() methods of QsciLexer
are no longer virtual.
- The color(), eolFill(), font() and paper() methods of all QsciLexer derived
classes (except for QsciLexer itself) have been renamed defaultColor(),
defaultEolFill(), defaultFont() and defaultPaper() respectively.
v2.0 26th May 2007
- A revised API, incompatible with QScintilla v1.
- Hugely improved autocompletion and call tips support.
- Supports both Qt v3 and Qt v4.
- Includes Python bindings.

50
third_party/qscintilla/Python/README vendored Normal file
View File

@@ -0,0 +1,50 @@
QScintilla - Python Bindings for the QScintilla Programmers Editor Widget
=========================================================================
QScintilla is a port to Qt of the Scintilla programmers editor widget. It
supports the traditional low-level Scintilla API and implements a high-level
API covering such things as auto-completion, code folding and lexer
configuration.
These Python bindings implement a single extension module that sits on top of
PyQt5 and wraps both the low-level and high-level APIs.
Author
------
QScintilla is copyright (c) Riverbank Computing Limited. Its homepage is
https://www.riverbankcomputing.com/software/qscintilla/.
Support may be obtained from the QScintilla mailing list at
https://www.riverbankcomputing.com/mailman/listinfo/qscintilla/.
License
-------
QScintilla is released under the GPL v3 license and under a commercial license
that allows for the development of proprietary applications.
Documentation
-------------
The documentation for the latest release can be found
`here <https://www.riverbankcomputing.com/static/Docs/QScintilla/>`__.
Installation
------------
The GPL version of QScintilla can be installed from PyPI::
pip install QScintilla
The wheels include a statically linked copy of the QScintilla C++ library.
``pip`` will also build and install the bindings from the sdist package but
Qt's ``qmake`` tool must be on ``PATH``.
The ``sip-install`` tool will also install the bindings from the sdist package
but will allow you to configure many aspects of the installation.

View File

@@ -0,0 +1,22 @@
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <Qsci/qsciglobal.h>
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
QFile outf(argv[1]);
if (!outf.open(QIODevice::WriteOnly|QIODevice::Truncate|QIODevice::Text))
return 1;
QTextStream out(&outf);
out << QSCINTILLA_VERSION << '\n';
out << QSCINTILLA_VERSION_STR << '\n';
return 0;
}

212
third_party/qscintilla/Python/project.py vendored Normal file
View File

@@ -0,0 +1,212 @@
# This is the build script for the QScintilla Python bindings.
#
# Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
#
# This file is part of QScintilla.
#
# This file may be used under the terms of the GNU General Public License
# version 3.0 as published by the Free Software Foundation and appearing in
# the file LICENSE included in the packaging of this file. Please review the
# following information to ensure the GNU General Public License version 3.0
# requirements will be met: http://www.gnu.org/copyleft/gpl.html.
#
# If you do not wish to use this file under the terms of the GPL version 3.0
# then you may purchase a commercial license. For more information contact
# info@riverbankcomputing.com.
#
# This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
# WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
import os
from pyqtbuild import PyQtBindings, PyQtProject
from sipbuild import Option
class QScintilla(PyQtProject):
""" The QScintilla project. """
def __init__(self):
""" Initialise the project. """
super().__init__()
self.bindings_factories = [Qsci]
# If there is a 'src' subdirectory then we are part of an sdist rather
# than a full source distribution. If part of an sdist then the
# QScintilla source is compiled along with the bindings. Otherwise an
# external (ie. already built) QScintilla library is used (which may be
# static or dynamic).
self.qsci_external_lib = not os.path.isdir('src')
def apply_user_defaults(self, tool):
""" Set default values for user options that haven't been set yet. """
super().apply_user_defaults(tool)
if not self.qsci_external_lib:
# If a directory to install the .api files was given then add the
# bundled .api files as well.
if self.api_dir:
self.wheel_includes.append(
('qsci/api/python/*.api', self.api_dir))
if self.qsci_translations_dir:
self.wheel_includes.append(
('src/*.qm', self.qsci_translations_dir))
def get_options(self):
""" Return the list of configurable options. """
options = super().get_options()
# The directory within the wheel to install the translation files to.
options.append(
Option('qsci_translations_dir',
help="the QScintilla translation files will be installed in DIR",
metavar="DIR", tools=['wheel']))
return options
class Qsci(PyQtBindings):
""" The Qsci bindings. """
def __init__(self, project):
""" Initialise the bindings. """
if project.qsci_external_lib:
qmake_CONFIG = ['qscintilla2']
else:
qmake_CONFIG = []
super().__init__(project, 'Qsci', qmake_CONFIG=qmake_CONFIG)
def apply_user_defaults(self, tool):
""" Set default values for user options that haven't been set yet. """
project = self.project
qt6 = (project.builder.qt_version >= 0x060000)
# Set the name of the .sip file now that we know the Qt version number.
self.sip_file = 'qscimod6.sip' if qt6 else 'qscimod5.sip'
if self.project.qsci_external_lib:
if self.qsci_features_dir is not None:
os.environ['QMAKEFEATURES'] = os.path.abspath(
self.qsci_features_dir)
if self.qsci_include_dir is not None:
self.include_dirs.append(
os.path.abspath(self.qsci_include_dir))
if self.qsci_library_dir is not None:
self.library_dirs.append(
os.path.abspath(self.qsci_library_dir))
else:
# We configure CONFIG and QT textually because it's too late to
# update qmake_CONFIG and qmake_QT.
self.builder_settings.append('QT += widgets')
if project.py_platform != 'ios':
self.builder_settings.append('QT += printsupport')
if project.py_platform in ('darwin', 'ios') and not qt6:
self.builder_settings.append('QT += macextras')
self.builder_settings.append(
'CONFIG += warn_off thread exceptions')
self.define_macros.extend(
['SCINTILLA_QT', 'SCI_LEXER',
'INCLUDE_DEPRECATED_FEATURES'])
self._add_internal_lib_sources()
super().apply_user_defaults(tool)
def get_options(self):
""" Return the list of configurable options. """
options = super().get_options()
if self.project.qsci_external_lib:
# The directory containing the features file.
options.append(
Option('qsci_features_dir',
help="the qscintilla2.prf features file is in DIR",
metavar="DIR"))
# The directory containing the include directory.
options.append(
Option('qsci_include_dir',
help="the Qsci include file directory is in DIR",
metavar="DIR"))
# The directory containing the library.
options.append(
Option('qsci_library_dir',
help="the QScintilla library is in DIR",
metavar="DIR"))
return options
def handle_test_output(self, test_output):
""" Handle the output from the external test program and return True if
the bindings are buildable.
"""
project = self.project
installed_version = int(test_output[0])
installed_version_str = test_output[1]
if project.version != installed_version:
project.progress(
"QScintilla v{0} is required but QScintilla v{1} is "
"installed.".format(project.version_str,
installed_version_str))
return False
return True
def is_buildable(self):
""" Return True if the bindings are buildable. """
# We need to check the compatibility of an external QScintilla library.
if self.project.qsci_external_lib:
return super().is_buildable()
return True
def _add_dir_sources(self, dname):
""" Add the headers and sources from a particular directory. """
for fn in os.listdir(dname):
# Skip the printer support on iOS.
if self.project.py_platform == 'ios' and fn.startswith('qsciprinter.'):
continue
if fn.endswith('.h'):
self.headers.append(os.path.join(dname, fn))
elif fn.endswith('.cpp'):
self.sources.append(os.path.join(dname, fn))
def _add_internal_lib_sources(self):
""" Add to the lists of include directories, header files and source
files to build the QScintilla library.
"""
include_dirs = ['src']
for dn in ('include', 'lexers', 'lexlib', 'src'):
include_dirs.append(os.path.join('scintilla', dn))
self._add_dir_sources(os.path.join('src', 'Qsci'))
for dn in include_dirs:
self._add_dir_sources(dn)
self.include_dirs.extend(include_dirs)

View File

@@ -0,0 +1,16 @@
# Specify the build system.
[build-system]
requires = ["sip >=6.0.2, <7", "PyQt-builder >=1.6, <2"]
build-backend = "sipbuild.api"
# Specify the PEP 566 metadata for the project.
[tool.sip.metadata]
name = "QScintilla"
version = "2.14.1"
summary = "Python bindings for the QScintilla programmers editor widget"
home-page = "https://www.riverbankcomputing.com/software/qscintilla/"
author = "Riverbank Computing Limited"
author-email = "info@riverbankcomputing.com"
license = "GPL v3"
description-file = "README"
requires-dist = "PyQt5 (>=5.15.4)"

View File

@@ -0,0 +1,16 @@
# Specify the build system.
[build-system]
requires = ["sip >=6.0.2, <7", "PyQt-builder >=1.6, <2"]
build-backend = "sipbuild.api"
# Specify the PEP 566 metadata for the project.
[tool.sip.metadata]
name = "PyQt6-QScintilla"
version = "2.14.1"
summary = "Python bindings for the QScintilla programmers editor widget"
home-page = "https://www.riverbankcomputing.com/software/qscintilla/"
author = "Riverbank Computing Limited"
author-email = "info@riverbankcomputing.com"
license = "GPL v3"
description-file = "README"
requires-dist = "PyQt6 (>=6.0.3)"

View File

@@ -0,0 +1,42 @@
// This is the SIP interface definition for QsciAbstractAPIs.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciAbstractAPIs : QObject
{
%TypeHeaderCode
#include <Qsci/qsciabstractapis.h>
%End
public:
QsciAbstractAPIs(QsciLexer *lexer /TransferThis/);
virtual ~QsciAbstractAPIs();
QsciLexer *lexer() const;
virtual void updateAutoCompletionList(const QStringList &context,
QStringList &list /In, Out/) = 0;
virtual void autoCompletionSelected(const QString &selection);
virtual QStringList callTips(const QStringList &context, int commas,
QsciScintilla::CallTipsStyle style, QList<int> &shifts) = 0;
private:
QsciAbstractAPIs(const QsciAbstractAPIs &);
};

View File

@@ -0,0 +1,58 @@
// This is the SIP interface definition for QsciAPIs.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciAPIs : QsciAbstractAPIs
{
%TypeHeaderCode
#include <Qsci/qsciapis.h>
%End
public:
QsciAPIs(QsciLexer *lexer /TransferThis/);
virtual ~QsciAPIs();
void add(const QString &entry);
void clear();
bool load(const QString &fname);
void remove(const QString &entry);
void prepare();
void cancelPreparation();
QString defaultPreparedName() const;
bool isPrepared(const QString &filename = QString()) const;
bool loadPrepared(const QString &filename = QString());
bool savePrepared(const QString &filename = QString()) const;
virtual bool event(QEvent *e);
QStringList installedAPIFiles() const;
virtual void updateAutoCompletionList(const QStringList &context,
QStringList &list /In, Out/);
virtual void autoCompletionSelected(const QString &selection);
virtual QStringList callTips(const QStringList &context, int commas,
QsciScintilla::CallTipsStyle style, QList<int> &shifts);
signals:
void apiPreparationCancelled();
void apiPreparationStarted();
void apiPreparationFinished();
private:
QsciAPIs(const QsciAPIs &);
};

View File

@@ -0,0 +1,143 @@
// This is the SIP interface definition for QsciCommand.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciCommand
{
%TypeHeaderCode
#include <Qsci/qscicommand.h>
%End
public:
enum Command {
LineDown,
LineDownExtend,
LineDownRectExtend,
LineScrollDown,
LineUp,
LineUpExtend,
LineUpRectExtend,
LineScrollUp,
ScrollToStart,
ScrollToEnd,
VerticalCentreCaret,
ParaDown,
ParaDownExtend,
ParaUp,
ParaUpExtend,
CharLeft,
CharLeftExtend,
CharLeftRectExtend,
CharRight,
CharRightExtend,
CharRightRectExtend,
WordLeft,
WordLeftExtend,
WordRight,
WordRightExtend,
WordLeftEnd,
WordLeftEndExtend,
WordRightEnd,
WordRightEndExtend,
WordPartLeft,
WordPartLeftExtend,
WordPartRight,
WordPartRightExtend,
Home,
HomeExtend,
HomeRectExtend,
HomeDisplay,
HomeDisplayExtend,
HomeWrap,
HomeWrapExtend,
VCHome,
VCHomeExtend,
VCHomeRectExtend,
VCHomeWrap,
VCHomeWrapExtend,
LineEnd,
LineEndExtend,
LineEndRectExtend,
LineEndDisplay,
LineEndDisplayExtend,
LineEndWrap,
LineEndWrapExtend,
DocumentStart,
DocumentStartExtend,
DocumentEnd,
DocumentEndExtend,
PageUp,
PageUpExtend,
PageUpRectExtend,
PageDown,
PageDownExtend,
PageDownRectExtend,
StutteredPageUp,
StutteredPageUpExtend,
StutteredPageDown,
StutteredPageDownExtend,
Delete,
DeleteBack,
DeleteBackNotLine,
DeleteWordLeft,
DeleteWordRight,
DeleteWordRightEnd,
DeleteLineLeft,
DeleteLineRight,
LineDelete,
LineCut,
LineCopy,
LineTranspose,
LineDuplicate,
SelectAll,
MoveSelectedLinesUp,
MoveSelectedLinesDown,
SelectionDuplicate,
SelectionLowerCase,
SelectionUpperCase,
SelectionCut,
SelectionCopy,
Paste,
EditToggleOvertype,
Newline,
Formfeed,
Tab,
Backtab,
Cancel,
Undo,
Redo,
ZoomIn,
ZoomOut,
ReverseLines,
};
Command command() const;
void execute();
void setKey(int key);
void setAlternateKey(int altkey);
int key() const;
int alternateKey() const;
static bool validKey(int key);
QString description() const;
private:
QsciCommand(QsciScintilla *qs, Command cmd, int key, int altkey,
const char *desc);
QsciCommand(const QsciCommand &);
};

View File

@@ -0,0 +1,44 @@
// This is the SIP interface definition for the QsciCommandSet.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciCommandSet
{
%TypeHeaderCode
#include <Qsci/qscicommandset.h>
%End
public:
bool readSettings(QSettings &qs, const char *prefix = "/Scintilla");
bool writeSettings(QSettings &qs, const char *prefix = "/Scintilla");
QList<QsciCommand *> &commands();
void clearKeys();
void clearAlternateKeys();
QsciCommand *boundTo(int key) const;
QsciCommand *find(QsciCommand::Command command) const;
private:
QsciCommandSet(QsciScintilla *qs);
~QsciCommandSet();
QsciCommandSet(const QsciCommandSet &);
};

View File

@@ -0,0 +1,32 @@
// This is the SIP interface definition for QsciDocument.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciDocument
{
%TypeHeaderCode
#include <Qsci/qscidocument.h>
%End
public:
QsciDocument();
virtual ~QsciDocument();
QsciDocument(const QsciDocument &);
};

View File

@@ -0,0 +1,90 @@
// This is the SIP interface definition for QsciLexer.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexer : QObject
{
%TypeHeaderCode
#include <Qsci/qscilexer.h>
%End
public:
QsciLexer(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexer();
virtual const char *language() const = 0;
virtual const char *lexer() const;
virtual int lexerId() const;
QsciAbstractAPIs *apis() const;
virtual const char *autoCompletionFillups() const /Encoding="None"/;
virtual QStringList autoCompletionWordSeparators() const;
int autoIndentStyle();
virtual const char *blockEnd(int *style = 0) const /Encoding="None"/;
virtual int blockLookback() const;
virtual const char *blockStart(int *style = 0) const /Encoding="None"/;
virtual const char *blockStartKeyword(int *style = 0) const /Encoding="None"/;
virtual int braceStyle() const;
virtual bool caseSensitive() const;
virtual QColor color(int style) const;
virtual bool eolFill(int style) const;
virtual QFont font(int style) const;
virtual int indentationGuideView() const;
virtual const char *keywords(int set) const;
virtual QString description(int style) const = 0;
virtual QColor paper(int style) const;
QColor defaultColor() const;
virtual QColor defaultColor(int style) const;
virtual bool defaultEolFill(int style) const;
QFont defaultFont() const;
virtual QFont defaultFont(int style) const;
QColor defaultPaper() const;
virtual QColor defaultPaper(int style) const;
virtual int defaultStyle() const;
QsciScintilla *editor() const;
virtual void refreshProperties();
void setAPIs(QsciAbstractAPIs *apis);
void setDefaultColor(const QColor &c);
void setDefaultFont(const QFont &f);
void setDefaultPaper(const QColor &c);
virtual int styleBitsNeeded() const;
virtual const char *wordCharacters() const;
bool readSettings(QSettings &qs, const char *prefix = "/Scintilla");
bool writeSettings(QSettings &qs, const char *prefix = "/Scintilla") const;
public slots:
virtual void setAutoIndentStyle(int autoindentstyle);
virtual void setColor(const QColor &c, int style = -1);
virtual void setEolFill(bool eolfill, int style = -1);
virtual void setFont(const QFont &f, int style = -1);
virtual void setPaper(const QColor &c, int style = -1);
signals:
void colorChanged(const QColor &c, int style);
void eolFillChanged(bool eolfilled, int style);
void fontChanged(const QFont &f, int style);
void paperChanged(const QColor &c, int style);
void propertyChanged(const char *prop, const char *val);
protected:
virtual bool readProperties(QSettings &qs, const QString &prefix);
virtual bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexer(const QsciLexer &);
};

View File

@@ -0,0 +1,74 @@
// This is the SIP interface definition for QsciLexerAsm.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerAsm : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerasm.h>
%End
public:
enum {
Default,
Comment,
Number,
DoubleQuotedString,
Operator,
Identifier,
CPUInstruction,
FPUInstruction,
Register,
Directive,
DirectiveOperand,
BlockComment,
SingleQuotedString,
UnclosedString,
ExtendedInstruction,
CommentDirective,
};
QsciLexerAsm(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerAsm();
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
void refreshProperties();
bool foldComments() const;
bool foldCompact() const;
QChar commentDelimiter() const;
bool foldSyntaxBased() const;
public slots:
virtual void setFoldComments(bool fold);
virtual void setFoldCompact(bool fold);
virtual void setCommentDelimiter(QChar delimeter);
virtual void setFoldSyntaxBased(bool syntax_based);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerAsm(const QsciLexerAsm &);
};

View File

@@ -0,0 +1,73 @@
// This is the SIP interface definition for QsciLexerAVS.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerAVS : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexeravs.h>
%End
public:
enum {
Default,
BlockComment,
NestedBlockComment,
LineComment,
Number,
Operator,
Identifier,
String,
TripleString,
Keyword,
Filter,
Plugin,
Function,
ClipProperty,
KeywordSet6
};
QsciLexerAVS(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerAVS();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
QFont defaultFont(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
const char *wordCharacters() const;
int braceStyle() const;
void refreshProperties();
bool foldComments() const;
bool foldCompact() const;
public slots:
virtual void setFoldComments(bool fold);
virtual void setFoldCompact(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerAVS(const QsciLexerAVS &);
};

View File

@@ -0,0 +1,74 @@
// This is the SIP interface definition for QsciLexerBash.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerBash : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerbash.h>
%End
public:
enum {
Default,
Error,
Comment,
Number,
Keyword,
DoubleQuotedString,
SingleQuotedString,
Operator,
Identifier,
Scalar,
ParameterExpansion,
Backticks,
HereDocumentDelimiter,
SingleQuotedHereDocument
};
QsciLexerBash(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerBash();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
const char *wordCharacters() const;
int braceStyle() const;
void refreshProperties();
bool foldComments() const;
bool foldCompact() const;
public slots:
virtual void setFoldComments(bool fold);
virtual void setFoldCompact(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerBash(const QsciLexerBash &);
};

View File

@@ -0,0 +1,56 @@
// This is the SIP interface definition for QsciLexerBatch.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerBatch : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerbatch.h>
%End
public:
enum {
Default,
Comment,
Keyword,
Label,
HideCommandChar,
ExternalCommand,
Variable,
Operator
};
QsciLexerBatch(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerBatch();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
const char *wordCharacters() const;
bool caseSensitive() const;
private:
QsciLexerBatch(const QsciLexerBatch &);
};

View File

@@ -0,0 +1,69 @@
// This is the SIP interface definition for QsciLexerCMake.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerCMake : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexercmake.h>
%End
public:
enum {
Default,
Comment,
String,
StringLeftQuote,
StringRightQuote,
Function,
Variable,
Label,
KeywordSet3,
BlockWhile,
BlockForeach,
BlockIf,
BlockMacro,
StringVariable,
Number
};
QsciLexerCMake(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerCMake();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
void refreshProperties();
bool foldAtElse() const;
public slots:
virtual void setFoldAtElse(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerCMake(const QsciLexerCMake &);
};

View File

@@ -0,0 +1,90 @@
// This is the SIP interface definition for QsciLexerCoffeeScript.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerCoffeeScript : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexercoffeescript.h>
%End
public:
enum {
Default,
Comment,
CommentLine,
CommentDoc,
Number,
Keyword,
DoubleQuotedString,
SingleQuotedString,
UUID,
PreProcessor,
Operator,
Identifier,
UnclosedString,
VerbatimString,
Regex,
CommentLineDoc,
KeywordSet2,
CommentDocKeyword,
CommentDocKeywordError,
GlobalClass,
CommentBlock,
BlockRegex,
BlockRegexComment,
InstanceProperty,
};
QsciLexerCoffeeScript(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerCoffeeScript();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
const char *wordCharacters() const;
QStringList autoCompletionWordSeparators() const;
const char *blockEnd(int *style = 0) const /Encoding="None"/;
const char *blockStart(int *style = 0) const /Encoding="None"/;
const char *blockStartKeyword(int *style = 0) const /Encoding="None"/;
int braceStyle() const;
void refreshProperties();
bool dollarsAllowed() const;
void setDollarsAllowed(bool allowed);
bool foldComments() const;
void setFoldComments(bool fold);
bool foldCompact() const;
void setFoldCompact(bool fold);
bool stylePreprocessor() const;
void setStylePreprocessor(bool style);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerCoffeeScript(const QsciLexerCoffeeScript &);
};

View File

@@ -0,0 +1,138 @@
// This is the SIP interface definition for QsciLexerCPP.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerCPP : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexercpp.h>
%End
public:
enum {
Default,
InactiveDefault,
Comment,
InactiveComment,
CommentLine,
InactiveCommentLine,
CommentDoc,
InactiveCommentDoc,
Number,
InactiveNumber,
Keyword,
InactiveKeyword,
DoubleQuotedString,
InactiveDoubleQuotedString,
SingleQuotedString,
InactiveSingleQuotedString,
UUID,
InactiveUUID,
PreProcessor,
InactivePreProcessor,
Operator,
InactiveOperator,
Identifier,
InactiveIdentifier,
UnclosedString,
InactiveUnclosedString,
VerbatimString,
InactiveVerbatimString,
Regex,
InactiveRegex,
CommentLineDoc,
InactiveCommentLineDoc,
KeywordSet2,
InactiveKeywordSet2,
CommentDocKeyword,
InactiveCommentDocKeyword,
CommentDocKeywordError,
InactiveCommentDocKeywordError,
GlobalClass,
InactiveGlobalClass,
RawString,
InactiveRawString,
TripleQuotedVerbatimString,
InactiveTripleQuotedVerbatimString,
HashQuotedString,
InactiveHashQuotedString,
PreProcessorComment,
InactivePreProcessorComment,
PreProcessorCommentLineDoc,
InactivePreProcessorCommentLineDoc,
UserLiteral,
InactiveUserLiteral,
TaskMarker,
InactiveTaskMarker,
EscapeSequence,
InactiveEscapeSequence,
};
QsciLexerCPP(QObject *parent /TransferThis/ = 0,
bool caseInsensitiveKeywords = false);
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
const char *wordCharacters() const;
QStringList autoCompletionWordSeparators() const;
const char *blockEnd(int *style = 0) const /Encoding="None"/;
const char *blockStart(int *style = 0) const /Encoding="None"/;
const char *blockStartKeyword(int *style = 0) const /Encoding="None"/;
int braceStyle() const;
void refreshProperties();
bool foldAtElse() const;
bool foldComments() const;
bool foldCompact() const;
bool foldPreprocessor() const;
bool stylePreprocessor() const;
void setDollarsAllowed(bool allowed);
bool dollarsAllowed() const;
void setHighlightTripleQuotedStrings(bool enable);
bool highlightTripleQuotedStrings() const;
void setHighlightHashQuotedStrings(bool enable);
bool highlightHashQuotedStrings() const;
void setHighlightBackQuotedStrings(bool enabled);
bool highlightBackQuotedStrings() const;
void setHighlightEscapeSequences(bool enabled);
bool highlightEscapeSequences() const;
void setVerbatimStringEscapeSequencesAllowed(bool allowed);
bool verbatimStringEscapeSequencesAllowed() const;
public slots:
virtual void setFoldAtElse(bool fold);
virtual void setFoldComments(bool fold);
virtual void setFoldCompact(bool fold);
virtual void setFoldPreprocessor(bool fold);
virtual void setStylePreprocessor(bool style);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerCPP(const QsciLexerCPP &);
};

View File

@@ -0,0 +1,41 @@
// This is the SIP interface definition for QsciLexerCSharp.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerCSharp : QsciLexerCPP
{
%TypeHeaderCode
#include <Qsci/qscilexercsharp.h>
%End
public:
QsciLexerCSharp(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerCSharp();
const char *language() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
private:
QsciLexerCSharp(const QsciLexerCSharp &);
};

View File

@@ -0,0 +1,88 @@
// This is the SIP interface definition for QsciLexerCSS.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerCSS : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexercss.h>
%End
public:
enum {
Default,
Tag,
ClassSelector,
PseudoClass,
UnknownPseudoClass,
Operator,
CSS1Property,
UnknownProperty,
Value,
Comment,
IDSelector,
Important,
AtRule,
DoubleQuotedString,
SingleQuotedString,
CSS2Property,
Attribute,
CSS3Property,
PseudoElement,
ExtendedCSSProperty,
ExtendedPseudoClass,
ExtendedPseudoElement,
MediaRule,
Variable,
};
QsciLexerCSS(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerCSS();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
QFont defaultFont(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
const char *wordCharacters() const;
const char *blockEnd(int *style = 0) const /Encoding="None"/;
void refreshProperties();
bool foldComments() const;
bool foldCompact() const;
void setHSSLanguage(bool enable);
bool HSSLanguage() const;
void setLessLanguage(bool enable);
bool LessLanguage() const;
void setSCSSLanguage(bool enable);
bool SCSSLanguage() const;
public slots:
virtual void setFoldComments(bool fold);
virtual void setFoldCompact(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerCSS(const QsciLexerCSS &);
};

View File

@@ -0,0 +1,42 @@
// This is the SIP interface definition for QsciLexerCustom.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerCustom : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexercustom.h>
%End
public:
QsciLexerCustom(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerCustom();
virtual void setEditor(QsciScintilla *editor);
virtual int styleBitsNeeded() const;
void setStyling(int length, int style);
void setStyling(int length, const QsciStyle &style);
void startStyling(int pos, int styleBits = 0);
virtual void styleText(int start, int end) = 0;
private:
QsciLexerCustom(const QsciLexerCustom &);
};

View File

@@ -0,0 +1,88 @@
// This is the SIP interface definition for QsciLexerD.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerD : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerd.h>
%End
public:
enum {
Default,
Comment,
CommentLine,
CommentDoc,
CommentNested,
Number,
Keyword,
KeywordSecondary,
KeywordDoc,
Typedefs,
String,
UnclosedString,
Character,
Operator,
Identifier,
CommentLineDoc,
CommentDocKeyword,
CommentDocKeywordError,
BackquoteString,
RawString,
KeywordSet5,
KeywordSet6,
KeywordSet7,
};
QsciLexerD(QObject *parent /TransferThis/ = 0);
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
const char *wordCharacters() const;
QStringList autoCompletionWordSeparators() const;
const char *blockEnd(int *style = 0) const /Encoding="None"/;
const char *blockStart(int *style = 0) const /Encoding="None"/;
const char *blockStartKeyword(int *style = 0) const /Encoding="None"/;
int braceStyle() const;
void refreshProperties();
bool foldAtElse() const;
bool foldComments() const;
bool foldCompact() const;
public slots:
virtual void setFoldAtElse(bool fold);
virtual void setFoldComments(bool fold);
virtual void setFoldCompact(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerD(const QsciLexerD &);
};

View File

@@ -0,0 +1,54 @@
// This is the SIP interface definition for QsciLexerDiff.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerDiff : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerdiff.h>
%End
public:
enum {
Default,
Comment,
Command,
Header,
Position,
LineRemoved,
LineAdded,
LineChanged,
AddingPatchAdded,
RemovingPatchAdded,
AddingPatchRemoved,
RemovingPatchRemoved,
};
QsciLexerDiff(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerDiff();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
QString description(int style) const;
const char *wordCharacters() const;
private:
QsciLexerDiff(const QsciLexerDiff &);
};

View File

@@ -0,0 +1,50 @@
// This is the SIP interface definition for QsciLexerEDIFACT.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerEDIFACT : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexeredifact.h>
%End
public:
enum {
Default,
SegmentStart,
SegmentEnd,
ElementSeparator,
CompositeSeparator,
ReleaseSeparator,
UNASegmentHeader,
UNHSegmentHeader,
BadSegment
};
QsciLexerEDIFACT(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerEDIFACT();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
QString description(int style) const;
private:
QsciLexerEDIFACT(const QsciLexerEDIFACT &);
};

View File

@@ -0,0 +1,36 @@
// This is the SIP interface definition for QsciLexerFortran.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerFortran : QsciLexerFortran77
{
%TypeHeaderCode
#include <Qsci/qscilexerfortran.h>
%End
public:
QsciLexerFortran(QObject *parent /TransferThis/ = 0);
const char *language() const;
const char *lexer() const;
const char *keywords(int set) const;
private:
QsciLexerFortran(const QsciLexerFortran &);
};

View File

@@ -0,0 +1,71 @@
// This is the SIP interface definition for QsciLexerFortran77.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerFortran77 : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerfortran77.h>
%End
public:
enum {
Default,
Comment,
Number,
SingleQuotedString,
DoubleQuotedString,
UnclosedString,
Operator,
Identifier,
Keyword,
IntrinsicFunction,
ExtendedFunction,
PreProcessor,
DottedOperator,
Label,
Continuation,
};
QsciLexerFortran77(QObject *parent /TransferThis/ = 0);
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
int braceStyle() const;
void refreshProperties();
bool foldCompact() const;
public slots:
virtual void setFoldCompact(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerFortran77(const QsciLexerFortran77 &);
};

View File

@@ -0,0 +1,58 @@
// This is the SIP interface definition for QsciLexerHex.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerHex : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerhex.h>
%End
public:
enum {
Default,
RecordStart,
RecordType,
UnknownRecordType,
ByteCount,
IncorrectByteCount,
NoAddress,
DataAddress,
RecordCount,
StartAddress,
ExtendedAddress,
OddData,
EvenData,
UnknownData,
Checksum,
IncorrectChecksum,
TrailingGarbage,
};
QsciLexerHex(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerHex();
QColor defaultColor(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
QString description(int style) const;
private:
QsciLexerHex(const QsciLexerHex &);
};

View File

@@ -0,0 +1,181 @@
// This is the SIP interface definition for QsciLexerHTML.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerHTML : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerhtml.h>
%End
public:
enum {
Default,
Tag,
UnknownTag,
Attribute,
UnknownAttribute,
HTMLNumber,
HTMLDoubleQuotedString,
HTMLSingleQuotedString,
OtherInTag,
HTMLComment,
Entity,
XMLTagEnd,
XMLStart,
XMLEnd,
Script,
ASPAtStart,
ASPStart,
CDATA,
PHPStart,
HTMLValue,
ASPXCComment,
SGMLDefault,
SGMLCommand,
SGMLParameter,
SGMLDoubleQuotedString,
SGMLSingleQuotedString,
SGMLError,
SGMLSpecial,
SGMLEntity,
SGMLComment,
SGMLParameterComment,
SGMLBlockDefault,
JavaScriptStart,
JavaScriptDefault,
JavaScriptComment,
JavaScriptCommentLine,
JavaScriptCommentDoc,
JavaScriptNumber,
JavaScriptWord,
JavaScriptKeyword,
JavaScriptDoubleQuotedString,
JavaScriptSingleQuotedString,
JavaScriptSymbol,
JavaScriptUnclosedString,
JavaScriptRegex,
ASPJavaScriptStart,
ASPJavaScriptDefault,
ASPJavaScriptComment,
ASPJavaScriptCommentLine,
ASPJavaScriptCommentDoc,
ASPJavaScriptNumber,
ASPJavaScriptWord,
ASPJavaScriptKeyword,
ASPJavaScriptDoubleQuotedString,
ASPJavaScriptSingleQuotedString,
ASPJavaScriptSymbol,
ASPJavaScriptUnclosedString,
ASPJavaScriptRegex,
VBScriptStart,
VBScriptDefault,
VBScriptComment,
VBScriptNumber,
VBScriptKeyword,
VBScriptString,
VBScriptIdentifier,
VBScriptUnclosedString,
ASPVBScriptStart,
ASPVBScriptDefault,
ASPVBScriptComment,
ASPVBScriptNumber,
ASPVBScriptKeyword,
ASPVBScriptString,
ASPVBScriptIdentifier,
ASPVBScriptUnclosedString,
PythonStart,
PythonDefault,
PythonComment,
PythonNumber,
PythonDoubleQuotedString,
PythonSingleQuotedString,
PythonKeyword,
PythonTripleSingleQuotedString,
PythonTripleDoubleQuotedString,
PythonClassName,
PythonFunctionMethodName,
PythonOperator,
PythonIdentifier,
ASPPythonStart,
ASPPythonDefault,
ASPPythonComment,
ASPPythonNumber,
ASPPythonDoubleQuotedString,
ASPPythonSingleQuotedString,
ASPPythonKeyword,
ASPPythonTripleSingleQuotedString,
ASPPythonTripleDoubleQuotedString,
ASPPythonClassName,
ASPPythonFunctionMethodName,
ASPPythonOperator,
ASPPythonIdentifier,
PHPDefault,
PHPDoubleQuotedString,
PHPSingleQuotedString,
PHPKeyword,
PHPNumber,
PHPVariable,
PHPComment,
PHPCommentLine,
PHPDoubleQuotedVariable,
PHPOperator
};
QsciLexerHTML(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerHTML();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
const char *wordCharacters() const;
const char *autoCompletionFillups() const /Encoding="None"/;
bool caseSensitive() const;
void refreshProperties();
bool caseSensitiveTags() const;
void setDjangoTemplates(bool enable);
bool djangoTemplates() const;
bool foldCompact() const;
bool foldPreprocessor() const;
void setFoldScriptComments(bool fold);
bool foldScriptComments() const;
void setFoldScriptHeredocs(bool fold);
bool foldScriptHeredocs() const;
void setMakoTemplates(bool enable);
bool makoTemplates() const;
public slots:
virtual void setFoldCompact(bool fold);
virtual void setFoldPreprocessor(bool fold);
virtual void setCaseSensitiveTags(bool sens);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerHTML(const QsciLexerHTML &);
};

View File

@@ -0,0 +1,38 @@
// This is the SIP interface definition for QsciLexerIDL.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerIDL : QsciLexerCPP
{
%TypeHeaderCode
#include <Qsci/qscilexeridl.h>
%End
public:
QsciLexerIDL(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerIDL();
const char *language() const;
QColor defaultColor(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
private:
QsciLexerIDL(const QsciLexerIDL &);
};

View File

@@ -0,0 +1,37 @@
// This is the SIP interface definition for QsciLexerIntelHex.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerIntelHex : QsciLexerHex
{
%TypeHeaderCode
#include <Qsci/qscilexerintelhex.h>
%End
public:
QsciLexerIntelHex(QObject *parent = 0);
virtual ~QsciLexerIntelHex();
const char *language() const;
const char *lexer() const;
QString description(int style) const;
private:
QsciLexerIntelHex(const QsciLexerIntelHex &);
};

View File

@@ -0,0 +1,36 @@
// This is the SIP interface definition for QsciLexerJava.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerJava : QsciLexerCPP
{
%TypeHeaderCode
#include <Qsci/qscilexerjava.h>
%End
public:
QsciLexerJava(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerJava();
const char *language() const;
const char *keywords(int set) const;
private:
QsciLexerJava(const QsciLexerJava &);
};

View File

@@ -0,0 +1,41 @@
// This is the SIP interface definition for QsciLexerJavaScript.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerJavaScript : QsciLexerCPP
{
%TypeHeaderCode
#include <Qsci/qscilexerjavascript.h>
%End
public:
QsciLexerJavaScript(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerJavaScript();
const char *language() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
private:
QsciLexerJavaScript(const QsciLexerJavaScript &);
};

View File

@@ -0,0 +1,71 @@
// This is the SIP interface definition for QsciLexerJSON.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerJSON : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerjson.h>
%End
public:
enum {
Default,
Number,
String,
UnclosedString,
Property,
EscapeSequence,
CommentLine,
CommentBlock,
Operator,
IRI,
IRICompact,
Keyword,
KeywordLD,
Error,
};
QsciLexerJSON(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerJSON();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
void refreshProperties();
void setHighlightComments(bool highlight);
bool highlightComments() const;
void setHighlightEscapeSequences(bool highlight);
bool highlightEscapeSequences() const;
void setFoldCompact(bool fold);
bool foldCompact() const;
protected:
bool readProperties(QSettings &qs,const QString &prefix);
bool writeProperties(QSettings &qs,const QString &prefix) const;
private:
QsciLexerJSON(const QsciLexerJSON &);
};

View File

@@ -0,0 +1,79 @@
// This is the SIP interface definition for QsciLexerLua.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerLua : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerlua.h>
%End
public:
enum {
Default,
Comment,
LineComment,
Number,
Keyword,
String,
Character,
LiteralString,
Preprocessor,
Operator,
Identifier,
UnclosedString,
BasicFunctions,
StringTableMathsFunctions,
CoroutinesIOSystemFacilities,
KeywordSet5,
KeywordSet6,
KeywordSet7,
KeywordSet8,
Label,
};
QsciLexerLua(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerLua();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
QStringList autoCompletionWordSeparators() const;
const char *blockStart(int *style = 0) const /Encoding="None"/;
int braceStyle() const;
void refreshProperties();
bool foldCompact() const;
public slots:
virtual void setFoldCompact(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerLua(const QsciLexerLua &);
};

View File

@@ -0,0 +1,52 @@
// This is the SIP interface definition for QsciLexerMakefile.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerMakefile : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexermakefile.h>
%End
public:
enum {
Default,
Comment,
Preprocessor,
Variable,
Operator,
Target,
Error
};
QsciLexerMakefile(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerMakefile();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
QString description(int style) const;
const char *wordCharacters() const;
private:
QsciLexerMakefile(const QsciLexerMakefile &);
};

View File

@@ -0,0 +1,65 @@
// This is the SIP interface definition for QsciLexerMarkdown.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerMarkdown : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexermarkdown.h>
%End
public:
enum {
Default,
Special,
StrongEmphasisAsterisks,
StrongEmphasisUnderscores,
EmphasisAsterisks,
EmphasisUnderscores,
Header1,
Header2,
Header3,
Header4,
Header5,
Header6,
Prechar,
UnorderedListItem,
OrderedListItem,
BlockQuote,
StrikeOut,
HorizontalRule,
Link,
CodeBackticks,
CodeDoubleBackticks,
CodeBlock,
};
QsciLexerMarkdown(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerMarkdown();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
QString description(int style) const;
private:
QsciLexerMarkdown(const QsciLexerMarkdown &);
};

View File

@@ -0,0 +1,36 @@
// This is the SIP interface definition for QsciLexerMASM.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerMASM : QsciLexerAsm
{
%TypeHeaderCode
#include <Qsci/qscilexermasm.h>
%End
public:
QsciLexerMASM(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerMASM();
const char *language() const;
const char *lexer() const;
private:
QsciLexerMASM(const QsciLexerMASM &);
};

View File

@@ -0,0 +1,52 @@
// This is the SIP interface definition for QsciLexerMatlab.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerMatlab : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexermatlab.h>
%End
public:
enum {
Default,
Comment,
Command,
Number,
Keyword,
SingleQuotedString,
Operator,
Identifier,
DoubleQuotedString
};
QsciLexerMatlab(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerMatlab();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
QFont defaultFont(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
private:
QsciLexerMatlab(const QsciLexerMatlab &);
};

View File

@@ -0,0 +1,36 @@
// This is the SIP interface definition for QsciLexerNASM.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerNASM : QsciLexerAsm
{
%TypeHeaderCode
#include <Qsci/qscilexernasm.h>
%End
public:
QsciLexerNASM(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerNASM();
const char *language() const;
const char *lexer() const;
private:
QsciLexerNASM(const QsciLexerNASM &);
};

View File

@@ -0,0 +1,37 @@
// This is the SIP interface definition for QsciLexerOctave.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerOctave : QsciLexerMatlab
{
%TypeHeaderCode
#include <Qsci/qscilexeroctave.h>
%End
public:
QsciLexerOctave(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerOctave();
const char *language() const;
const char *lexer() const;
const char *keywords(int set) const;
private:
QsciLexerOctave(const QsciLexerOctave &);
};

View File

@@ -0,0 +1,82 @@
// This is the SIP interface definition for QsciLexerPascal.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerPascal : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerpascal.h>
%End
public:
enum {
Default,
Identifier,
Comment,
CommentParenthesis,
CommentLine,
PreProcessor,
PreProcessorParenthesis,
Number,
HexNumber,
Keyword,
SingleQuotedString,
UnclosedString,
Character,
Operator,
Asm,
};
QsciLexerPascal(QObject *parent /TransferThis/ = 0);
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
QStringList autoCompletionWordSeparators() const;
const char *blockEnd(int *style = 0) const /Encoding="None"/;
const char *blockStart(int *style = 0) const /Encoding="None"/;
const char *blockStartKeyword(int *style = 0) const /Encoding="None"/;
int braceStyle() const;
void refreshProperties();
bool foldComments() const;
bool foldCompact() const;
bool foldPreprocessor() const;
void setSmartHighlighting(bool enabled);
bool smartHighlighting() const;
public slots:
virtual void setFoldComments(bool fold);
virtual void setFoldCompact(bool fold);
virtual void setFoldPreprocessor(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerPascal(const QsciLexerPascal &);
};

View File

@@ -0,0 +1,111 @@
// This is the SIP interface definition for QsciLexerPerl.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerPerl : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerperl.h>
%End
public:
enum {
Default,
Error,
Comment,
POD,
Number,
Keyword,
DoubleQuotedString,
SingleQuotedString,
Operator,
Identifier,
Scalar,
Array,
Hash,
SymbolTable,
Regex,
Substitution,
Backticks,
DataSection,
HereDocumentDelimiter,
SingleQuotedHereDocument,
DoubleQuotedHereDocument,
BacktickHereDocument,
QuotedStringQ,
QuotedStringQQ,
QuotedStringQX,
QuotedStringQR,
QuotedStringQW,
PODVerbatim,
SubroutinePrototype,
FormatIdentifier,
FormatBody,
DoubleQuotedStringVar,
Translation,
RegexVar,
SubstitutionVar,
BackticksVar,
DoubleQuotedHereDocumentVar,
BacktickHereDocumentVar,
QuotedStringQQVar,
QuotedStringQXVar,
QuotedStringQRVar,
};
QsciLexerPerl(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerPerl();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
const char *wordCharacters() const;
QStringList autoCompletionWordSeparators() const;
const char *blockEnd(int *style = 0) const /Encoding="None"/;
const char *blockStart(int *style = 0) const /Encoding="None"/;
int braceStyle() const;
void refreshProperties();
bool foldComments() const;
bool foldCompact() const;
void setFoldAtElse(bool fold);
bool foldAtElse() const;
void setFoldPackages(bool fold);
bool foldPackages() const;
void setFoldPODBlocks(bool fold);
bool foldPODBlocks() const;
public slots:
virtual void setFoldComments(bool fold);
virtual void setFoldCompact(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerPerl(const QsciLexerPerl &);
};

View File

@@ -0,0 +1,69 @@
// This is the SIP interface definition for QsciLexerPO.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerPO : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerpo.h>
%End
public:
enum {
Default,
Comment,
MessageId,
MessageIdText,
MessageString,
MessageStringText,
MessageContext,
MessageContextText,
Fuzzy,
ProgrammerComment,
Reference,
Flags,
MessageIdTextEOL,
MessageStringTextEOL,
MessageContextTextEOL
};
QsciLexerPO(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerPO();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
QFont defaultFont(int style) const;
QString description(int style) const;
void refreshProperties();
bool foldComments() const;
bool foldCompact() const;
public slots:
virtual void setFoldComments(bool fold);
virtual void setFoldCompact(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerPO(const QsciLexerPO &);
};

View File

@@ -0,0 +1,78 @@
// This is the SIP interface definition for QsciLexerPostScript.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerPostScript : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerpostscript.h>
%End
public:
enum {
Default,
Comment,
DSCComment,
DSCCommentValue,
Number,
Name,
Keyword,
Literal,
ImmediateEvalLiteral,
ArrayParenthesis,
DictionaryParenthesis,
ProcedureParenthesis,
Text,
HexString,
Base85String,
BadStringCharacter
};
QsciLexerPostScript(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerPostScript();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
int braceStyle() const;
void refreshProperties();
bool tokenize() const;
int level() const;
bool foldCompact() const;
bool foldAtElse() const;
public slots:
virtual void setTokenize(bool tokenize);
virtual void setLevel(int level);
virtual void setFoldCompact(bool fold);
virtual void setFoldAtElse(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerPostScript(const QsciLexerPostScript &);
};

View File

@@ -0,0 +1,79 @@
// This is the SIP interface definition for QsciLexerPOV.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerPOV : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerpov.h>
%End
public:
enum {
Default,
Comment,
CommentLine,
Number,
Operator,
Identifier,
String,
UnclosedString,
Directive,
BadDirective,
ObjectsCSGAppearance,
TypesModifiersItems,
PredefinedIdentifiers,
PredefinedFunctions,
KeywordSet6,
KeywordSet7,
KeywordSet8
};
QsciLexerPOV(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerPOV();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
const char *wordCharacters() const;
int braceStyle() const;
void refreshProperties();
bool foldComments() const;
bool foldCompact() const;
bool foldDirectives() const;
public slots:
virtual void setFoldComments(bool fold);
virtual void setFoldCompact(bool fold);
virtual void setFoldDirectives(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerPOV(const QsciLexerPOV &);
};

View File

@@ -0,0 +1,63 @@
// This is the SIP interface definition for QsciLexerProperties.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerProperties : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerproperties.h>
%End
public:
enum {
Default,
Comment,
Section,
Assignment,
DefaultValue,
Key
};
QsciLexerProperties(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerProperties();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
QString description(int style) const;
const char *wordCharacters() const;
void refreshProperties();
bool foldCompact() const;
void setInitialSpaces(bool enable);
bool initialSpaces() const;
public slots:
virtual void setFoldCompact(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerProperties(const QsciLexerProperties &);
};

View File

@@ -0,0 +1,105 @@
// This is the SIP interface definition for QsciLexerPython.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerPython : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerpython.h>
%End
public:
enum {
Default,
Comment,
Number,
DoubleQuotedString,
SingleQuotedString,
Keyword,
TripleSingleQuotedString,
TripleDoubleQuotedString,
ClassName,
FunctionMethodName,
Operator,
Identifier,
CommentBlock,
UnclosedString,
HighlightedIdentifier,
Decorator,
DoubleQuotedFString,
SingleQuotedFString,
TripleSingleQuotedFString,
TripleDoubleQuotedFString,
};
enum IndentationWarning {
NoWarning,
Inconsistent,
TabsAfterSpaces,
Spaces,
Tabs
};
QsciLexerPython(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerPython();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
QStringList autoCompletionWordSeparators() const;
int blockLookback() const;
const char *blockStart(int *style = 0) const /Encoding="None"/;
int braceStyle() const;
int indentationGuideView() const;
void refreshProperties();
bool foldComments() const;
void setFoldCompact(bool fold);
bool foldCompact() const;
bool foldQuotes() const;
QsciLexerPython::IndentationWarning indentationWarning() const;
void setHighlightSubidentifiers(bool enabled);
bool highlightSubidentifiers() const;
void setStringsOverNewlineAllowed(bool allowed);
bool stringsOverNewlineAllowed() const;
void setV2UnicodeAllowed(bool allowed);
bool v2UnicodeAllowed() const;
void setV3BinaryOctalAllowed(bool allowed);
bool v3BinaryOctalAllowed() const;
void setV3BytesAllowed(bool allowed);
bool v3BytesAllowed() const;
public slots:
virtual void setFoldComments(bool fold);
virtual void setFoldQuotes(bool fold);
virtual void setIndentationWarning(QsciLexerPython::IndentationWarning warn);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerPython(const QsciLexerPython &);
};

View File

@@ -0,0 +1,91 @@
// This is the SIP interface definition for QsciLexerRuby.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerRuby : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerruby.h>
%End
public:
enum {
Default,
Error,
Comment,
POD,
Number,
Keyword,
DoubleQuotedString,
SingleQuotedString,
ClassName,
FunctionMethodName,
Operator,
Identifier,
Regex,
Global,
Symbol,
ModuleName,
InstanceVariable,
ClassVariable,
Backticks,
DataSection,
HereDocumentDelimiter,
HereDocument,
PercentStringq,
PercentStringQ,
PercentStringx,
PercentStringr,
PercentStringw,
DemotedKeyword,
Stdin,
Stdout,
Stderr
};
QsciLexerRuby(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerRuby();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int) const;
QString description(int style) const;
const char *blockEnd(int *style = 0) const /Encoding="None"/;
const char *blockStart(int *style = 0) const /Encoding="None"/;
const char *blockStartKeyword(int *style = 0) const /Encoding="None"/;
int braceStyle() const;
void refreshProperties();
void setFoldComments(bool fold);
bool foldComments() const;
void setFoldCompact(bool fold);
bool foldCompact() const;
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerRuby(const QsciLexerRuby &);
};

View File

@@ -0,0 +1,54 @@
// This is the SIP interface definition for QsciLexerSpice.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerSpice : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerspice.h>
%End
public:
enum {
Default,
Identifier,
Command,
Function,
Parameter,
Number,
Delimiter,
Value,
Comment
};
QsciLexerSpice(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerSpice();
const char *language() const;
const char *lexer() const;
const char *keywords(int set) const;
QColor defaultColor(int style) const;
QFont defaultFont(int style) const;
QString description(int style) const;
int braceStyle() const;
private:
QsciLexerSpice(const QsciLexerSpice &);
};

View File

@@ -0,0 +1,93 @@
// This is the SIP interface definition for QsciLexerSQL.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerSQL : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexersql.h>
%End
public:
enum {
Default,
Comment,
CommentLine,
CommentDoc,
Number,
Keyword,
DoubleQuotedString,
SingleQuotedString,
PlusKeyword,
PlusPrompt,
Operator,
Identifier,
PlusComment,
CommentLineHash,
CommentDocKeyword,
CommentDocKeywordError,
KeywordSet5,
KeywordSet6,
KeywordSet7,
KeywordSet8,
QuotedIdentifier,
QuotedOperator,
};
QsciLexerSQL(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerSQL();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
int braceStyle() const;
void refreshProperties();
bool backslashEscapes() const;
void setDottedWords(bool enable);
bool dottedWords() const;
void setFoldAtElse(bool fold);
bool foldAtElse() const;
bool foldComments() const;
bool foldCompact() const;
void setFoldOnlyBegin(bool fold);
bool foldOnlyBegin() const;
void setHashComments(bool enable);
bool hashComments() const;
void setQuotedIdentifiers(bool enable);
bool quotedIdentifiers() const;
public slots:
virtual void setBackslashEscapes(bool enable);
virtual void setFoldComments(bool fold);
virtual void setFoldCompact(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerSQL(const QsciLexerSQL &);
};

View File

@@ -0,0 +1,37 @@
// This is the SIP interface definition for QsciLexerSRec.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerSRec : QsciLexerHex
{
%TypeHeaderCode
#include <Qsci/qscilexersrec.h>
%End
public:
QsciLexerSRec(QObject *parent = 0);
virtual ~QsciLexerSRec();
const char *language() const;
const char *lexer() const;
QString description(int style) const;
private:
QsciLexerSRec(const QsciLexerSRec &);
};

View File

@@ -0,0 +1,77 @@
// This is the SIP interface definition for QsciLexerTCL.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerTCL : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexertcl.h>
%End
public:
enum {
Default,
Comment,
CommentLine,
Number,
QuotedKeyword,
QuotedString,
Operator,
Identifier,
Substitution,
SubstitutionBrace,
Modifier,
ExpandKeyword,
TCLKeyword,
TkKeyword,
ITCLKeyword,
TkCommand,
KeywordSet6,
KeywordSet7,
KeywordSet8,
KeywordSet9,
CommentBox,
CommentBlock
};
QsciLexerTCL(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerTCL();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
int braceStyle() const;
void refreshProperties();
void setFoldComments(bool fold);
bool foldComments() const;
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerTCL(const QsciLexerTCL &);
};

View File

@@ -0,0 +1,37 @@
// This is the SIP interface definition for QsciLexerTekHex.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerTekHex : QsciLexerHex
{
%TypeHeaderCode
#include <Qsci/qscilexertekhex.h>
%End
public:
QsciLexerTekHex(QObject *parent = 0);
virtual ~QsciLexerTekHex();
const char *language() const;
const char *lexer() const;
QString description(int style) const;
private:
QsciLexerTekHex(const QsciLexerTekHex &);
};

View File

@@ -0,0 +1,63 @@
// This is the SIP interface definition for QsciLexerTeX.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerTeX : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexertex.h>
%End
public:
enum {
Default,
Special,
Group,
Symbol,
Command,
Text
};
QsciLexerTeX(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerTeX();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
const char *wordCharacters() const;
void refreshProperties();
void setFoldComments(bool fold);
bool foldComments() const;
void setFoldCompact(bool fold);
bool foldCompact() const;
void setProcessComments(bool enable);
bool processComments() const;
void setProcessIf(bool enable);
bool processIf() const;
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerTeX(const QsciLexerTeX &);
};

View File

@@ -0,0 +1,106 @@
// This is the SIP interface definition for QsciLexerVerilog.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerVerilog : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexerverilog.h>
%End
public:
enum {
Default,
InactiveDefault,
Comment,
InactiveComment,
CommentLine,
InactiveCommentLine,
CommentBang,
InactiveCommentBang,
Number,
InactiveNumber,
Keyword,
InactiveKeyword,
String,
InactiveString,
KeywordSet2,
InactiveKeywordSet2,
SystemTask,
InactiveSystemTask,
Preprocessor,
InactivePreprocessor,
Operator,
InactiveOperator,
Identifier,
InactiveIdentifier,
UnclosedString,
InactiveUnclosedString,
UserKeywordSet,
InactiveUserKeywordSet,
CommentKeyword,
InactiveCommentKeyword,
DeclareInputPort,
InactiveDeclareInputPort,
DeclareOutputPort,
InactiveDeclareOutputPort,
DeclareInputOutputPort,
InactiveDeclareInputOutputPort,
PortConnection,
InactivePortConnection,
};
QsciLexerVerilog(QObject *parent /TransferThis/ = 0);
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
const char *wordCharacters() const;
int braceStyle() const;
void refreshProperties();
void setFoldAtElse(bool fold);
bool foldAtElse() const;
void setFoldComments(bool fold);
bool foldComments() const;
void setFoldCompact(bool fold);
bool foldCompact() const;
void setFoldPreprocessor(bool fold);
bool foldPreprocessor() const;
void setFoldAtModule(bool fold);
bool foldAtModule() const;
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerVerilog(const QsciLexerVerilog &);
};

View File

@@ -0,0 +1,81 @@
// This is the SIP interface definition for QsciLexerVHDL.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerVHDL : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexervhdl.h>
%End
public:
enum {
Default,
Comment,
CommentLine,
Number,
String,
Operator,
Identifier,
UnclosedString,
Keyword,
StandardOperator,
Attribute,
StandardFunction,
StandardPackage,
StandardType,
KeywordSet7,
CommentBlock
};
QsciLexerVHDL(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerVHDL();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
int braceStyle() const;
void refreshProperties();
bool foldComments() const;
bool foldCompact() const;
bool foldAtElse() const;
bool foldAtBegin() const;
bool foldAtParenthesis() const;
public slots:
virtual void setFoldComments(bool fold);
virtual void setFoldCompact(bool fold);
virtual void setFoldAtElse(bool fold);
virtual void setFoldAtBegin(bool fold);
virtual void setFoldAtParenthesis(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerVHDL(const QsciLexerVHDL &);
};

View File

@@ -0,0 +1,49 @@
// This is the SIP interface definition for QsciLexerXML.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerXML : QsciLexerHTML
{
%TypeHeaderCode
#include <Qsci/qscilexerxml.h>
%End
public:
QsciLexerXML(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerXML();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
void refreshProperties();
void setScriptsStyled(bool styled);
bool scriptsStyled() const;
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerXML(const QsciLexerXML &);
};

View File

@@ -0,0 +1,65 @@
// This is the SIP interface definition for QsciLexerYAML.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciLexerYAML : QsciLexer
{
%TypeHeaderCode
#include <Qsci/qscilexeryaml.h>
%End
public:
enum {
Default,
Comment,
Identifier,
Keyword,
Number,
Reference,
DocumentDelimiter,
TextBlockMarker,
SyntaxErrorMarker,
Operator
};
QsciLexerYAML(QObject *parent /TransferThis/ = 0);
virtual ~QsciLexerYAML();
const char *language() const;
const char *lexer() const;
QColor defaultColor(int style) const;
bool defaultEolFill(int style) const;
QFont defaultFont(int style) const;
QColor defaultPaper(int style) const;
const char *keywords(int set) const;
QString description(int style) const;
void refreshProperties();
bool foldComments() const;
public slots:
virtual void setFoldComments(bool fold);
protected:
bool readProperties(QSettings &qs, const QString &prefix);
bool writeProperties(QSettings &qs, const QString &prefix) const;
private:
QsciLexerYAML(const QsciLexerYAML &);
};

View File

@@ -0,0 +1,44 @@
// This is the SIP interface definition for QsciMacro.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciMacro : QObject
{
%TypeHeaderCode
#include <Qsci/qscimacro.h>
%End
public:
QsciMacro(QsciScintilla *parent /TransferThis/);
QsciMacro(const QString &asc, QsciScintilla *parent /TransferThis/);
virtual ~QsciMacro();
void clear();
bool load(const QString &asc);
QString save() const;
public slots:
virtual void play();
virtual void startRecording();
virtual void endRecording();
private:
QsciMacro(const QsciMacro &);
};

View File

@@ -0,0 +1,23 @@
// This is the SIP interface definition for the Qsci module of PyQt5.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
%Module(name=PyQt5.Qsci, keyword_arguments="Optional", use_limited_api=True)
%Include qscimodcommon.sip

View File

@@ -0,0 +1,23 @@
// This is the SIP interface definition for the Qsci module of PyQt6.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
%Module(name=PyQt6.Qsci, keyword_arguments="Optional", use_limited_api=True)
%Include qscimodcommon.sip

View File

@@ -0,0 +1,112 @@
// This is the SIP interface definition for the parts of the Qsci module common
// to PyQt5 and PyQt6.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
%Copying
Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
This file is part of QScintilla.
This file may be used under the terms of the GNU General Public License
version 3.0 as published by the Free Software Foundation and appearing in
the file LICENSE included in the packaging of this file. Please review the
following information to ensure the GNU General Public License version 3.0
requirements will be met: http://www.gnu.org/copyleft/gpl.html.
If you do not wish to use this file under the terms of the GPL version 3.0
then you may purchase a commercial license. For more information contact
info@riverbankcomputing.com.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
%End
%Import QtCore/QtCoremod.sip
%Import QtGui/QtGuimod.sip
%Import QtWidgets/QtWidgetsmod.sip
%If (PyQt_Printer)
%Import QtPrintSupport/QtPrintSupportmod.sip
%End
const int QSCINTILLA_VERSION;
const char *QSCINTILLA_VERSION_STR;
%Include qsciscintillabase.sip
%Include qsciscintilla.sip
%Include qsciabstractapis.sip
%Include qsciapis.sip
%Include qscicommand.sip
%Include qscicommandset.sip
%Include qscidocument.sip
%Include qscilexer.sip
%Include qscilexerasm.sip
%Include qscilexeravs.sip
%Include qscilexerbash.sip
%Include qscilexerbatch.sip
%Include qscilexercmake.sip
%Include qscilexercoffeescript.sip
%Include qscilexercpp.sip
%Include qscilexercsharp.sip
%Include qscilexercss.sip
%Include qscilexercustom.sip
%Include qscilexerd.sip
%Include qscilexerdiff.sip
%Include qscilexerfortran.sip
%Include qscilexerfortran77.sip
%Include qscilexerhex.sip
%Include qscilexerhtml.sip
%Include qscilexeridl.sip
%Include qscilexerintelhex.sip
%Include qscilexerjava.sip
%Include qscilexerjavascript.sip
%Include qscilexerjson.sip
%Include qscilexerlua.sip
%Include qscilexermakefile.sip
%Include qscilexermarkdown.sip
%Include qscilexermasm.sip
%Include qscilexermatlab.sip
%Include qscilexernasm.sip
%Include qscilexeroctave.sip
%Include qscilexerpascal.sip
%Include qscilexerperl.sip
%Include qscilexerpostscript.sip
%Include qscilexerpo.sip
%Include qscilexerpov.sip
%Include qscilexerproperties.sip
%Include qscilexerpython.sip
%Include qscilexerruby.sip
%Include qscilexerspice.sip
%Include qscilexersql.sip
%Include qscilexersrec.sip
%Include qscilexertcl.sip
%Include qscilexertekhex.sip
%Include qscilexertex.sip
%Include qscilexerverilog.sip
%Include qscilexervhdl.sip
%Include qscilexerxml.sip
%Include qscilexeryaml.sip
%Include qscimacro.sip
%Include qsciprinter.sip
%Include qscistyle.sip
%Include qscistyledtext.sip

View File

@@ -0,0 +1,47 @@
// This is the SIP interface definition for QsciPrinter.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
%If (PyQt_Printer)
class QsciPrinter : QPrinter
{
%TypeHeaderCode
#include <Qsci/qsciprinter.h>
%End
public:
QsciPrinter(QPrinter::PrinterMode mode = QPrinter::ScreenResolution);
virtual ~QsciPrinter();
virtual void formatPage(QPainter &painter, bool drawing, QRect &area,
int pagenr);
int magnification() const;
virtual void setMagnification(int magnification);
virtual int printRange(QsciScintillaBase *qsb, QPainter &painter,
int from = -1, int to = -1);
virtual int printRange(QsciScintillaBase *qsb, int from = -1, int to = -1);
QsciScintilla::WrapMode wrapMode() const;
virtual void setWrapMode(QsciScintilla::WrapMode);
private:
QsciPrinter(const QsciPrinter &);
};
%End

View File

@@ -0,0 +1,557 @@
// This is the SIP interface definition for QsciScintilla.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciScintilla : QsciScintillaBase
{
%TypeHeaderCode
#include <Qsci/qsciscintilla.h>
%End
public:
enum {
AiMaintain,
AiOpening,
AiClosing
};
enum AnnotationDisplay {
AnnotationHidden,
AnnotationStandard,
AnnotationBoxed,
AnnotationIndented,
};
enum AutoCompletionSource {
AcsNone,
AcsAll,
AcsDocument,
AcsAPIs
};
enum AutoCompletionUseSingle {
AcusNever,
AcusExplicit,
AcusAlways
};
enum BraceMatch {
NoBraceMatch,
StrictBraceMatch,
SloppyBraceMatch
};
enum CallTipsPosition {
CallTipsBelowText,
CallTipsAboveText,
};
enum CallTipsStyle {
CallTipsNone,
CallTipsNoContext,
CallTipsNoAutoCompletionContext,
CallTipsContext
};
enum EdgeMode {
EdgeNone,
EdgeLine,
EdgeBackground,
EdgeMultipleLines,
};
enum EolMode {
EolWindows,
EolUnix,
EolMac
};
enum FoldStyle {
NoFoldStyle,
PlainFoldStyle,
CircledFoldStyle,
BoxedFoldStyle,
CircledTreeFoldStyle,
BoxedTreeFoldStyle
};
enum IndicatorStyle {
PlainIndicator,
SquiggleIndicator,
TTIndicator,
DiagonalIndicator,
StrikeIndicator,
HiddenIndicator,
BoxIndicator,
RoundBoxIndicator,
StraightBoxIndicator,
FullBoxIndicator,
DashesIndicator,
DotsIndicator,
SquiggleLowIndicator,
DotBoxIndicator,
SquigglePixmapIndicator,
ThickCompositionIndicator,
ThinCompositionIndicator,
TextColorIndicator,
TriangleIndicator,
TriangleCharacterIndicator,
GradientIndicator,
CentreGradientIndicator,
};
enum {
MoNone,
MoSublineSelect,
};
enum MarginType {
SymbolMargin,
SymbolMarginDefaultForegroundColor,
SymbolMarginDefaultBackgroundColor,
NumberMargin,
TextMargin,
TextMarginRightJustified,
SymbolMarginColor,
};
enum MarkerSymbol {
Circle,
Rectangle,
RightTriangle,
SmallRectangle,
RightArrow,
Invisible,
DownTriangle,
Minus,
Plus,
VerticalLine,
BottomLeftCorner,
LeftSideSplitter,
BoxedPlus,
BoxedPlusConnected,
BoxedMinus,
BoxedMinusConnected,
RoundedBottomLeftCorner,
LeftSideRoundedSplitter,
CircledPlus,
CircledPlusConnected,
CircledMinus,
CircledMinusConnected,
Background,
ThreeDots,
ThreeRightArrows,
FullRectangle,
LeftRectangle,
Underline,
Bookmark
};
enum TabDrawMode {
TabLongArrow,
TabStrikeOut,
};
enum WhitespaceVisibility {
WsInvisible,
WsVisible,
WsVisibleAfterIndent,
WsVisibleOnlyInIndent,
};
enum WrapMode {
WrapNone,
WrapWord,
WrapCharacter,
WrapWhitespace,
};
enum WrapVisualFlag {
WrapFlagNone,
WrapFlagByText,
WrapFlagByBorder,
WrapFlagInMargin,
};
enum WrapIndentMode {
WrapIndentFixed,
WrapIndentSame,
WrapIndentIndented,
WrapIndentDeeplyIndented,
};
QsciScintilla(QWidget *parent /TransferThis/ = 0);
virtual ~QsciScintilla();
virtual QStringList apiContext(int pos, int &context_start,
int &last_word_start);
void annotate(int line, const QString &text, int style);
void annotate(int line, const QString &text, const QsciStyle &style);
void annotate(int line, const QsciStyledText &text);
void annotate(int line, const QList<QsciStyledText> &text);
QString annotation(int line) const;
AnnotationDisplay annotationDisplay() const;
void clearAnnotations(int line = -1);
bool autoCompletionCaseSensitivity() const;
bool autoCompletionFillupsEnabled() const;
bool autoCompletionReplaceWord() const;
bool autoCompletionShowSingle() const;
AutoCompletionSource autoCompletionSource() const;
int autoCompletionThreshold() const;
AutoCompletionUseSingle autoCompletionUseSingle() const;
bool autoIndent() const;
bool backspaceUnindents() const;
void beginUndoAction();
BraceMatch braceMatching() const;
QByteArray bytes(int start, int end) const;
CallTipsPosition callTipsPosition() const;
CallTipsStyle callTipsStyle() const;
int callTipsVisible() const;
void cancelFind();
void cancelList();
bool caseSensitive() const;
void clearRegisteredImages();
QColor color() const;
QList<int> contractedFolds() const;
void convertEols(EolMode mode);
QMenu *createStandardContextMenu() /Factory/;
QsciDocument document() const;
void endUndoAction();
QColor edgeColor() const;
int edgeColumn() const;
EdgeMode edgeMode() const;
EolMode eolMode() const;
bool eolVisibility() const;
int extraAscent() const;
int extraDescent() const;
virtual bool findFirst(const QString &expr, bool re, bool cs, bool wo,
bool wrap, bool forward = true, int line = -1, int index = -1,
bool show = true, bool posix = false, bool cxx11 = false);
virtual bool findFirstInSelection(const QString &expr, bool re, bool cs,
bool wo, bool forward = true, bool show = true,
bool posix = false, bool cxx11 = false);
virtual bool findNext();
bool findMatchingBrace(long &brace, long &other, BraceMatch mode);
int firstVisibleLine() const;
FoldStyle folding() const;
void getCursorPosition(int *line, int *index) const;
void getSelection(int *lineFrom, int *indexFrom, int *lineTo,
int *indexTo) const;
bool hasSelectedText() const;
int indentation(int line) const;
bool indentationGuides() const;
bool indentationsUseTabs() const;
int indentationWidth() const;
void clearIndicatorRange(int lineFrom, int indexFrom, int lineTo,
int indexTo, int indicatorNumber);
void fillIndicatorRange(int lineFrom, int indexFrom, int lineTo,
int indexTo, int indicatorNumber);
int indicatorDefine(IndicatorStyle style, int indicatorNumber = -1);
bool indicatorDrawUnder(int indicatorNumber) const;
bool isCallTipActive() const;
bool isListActive() const;
bool isModified() const;
bool isReadOnly() const;
bool isRedoAvailable() const;
bool isUndoAvailable() const;
bool isUtf8() const;
bool isWordCharacter(char ch) const;
int lineAt(const QPoint &pos) const;
void lineIndexFromPosition(int position, int *line, int *index) const;
int lineLength(int line) const;
int lines() const;
int length() const;
QsciLexer *lexer() const;
QColor marginBackgroundColor(int margin) const;
bool marginLineNumbers(int margin) const;
int marginMarkerMask(int margin) const;
int marginOptions() const;
bool marginSensitivity(int margin) const;
MarginType marginType(int margin) const;
int marginWidth(int margin) const;
int margins() const;
int markerDefine(MarkerSymbol sym, int markerNumber = -1);
int markerDefine(char ch, int markerNumber = -1);
int markerDefine(const QPixmap &pm, int markerNumber = -1);
int markerDefine(const QImage &im, int markerNumber = -1);
int markerAdd(int linenr, int markerNumber);
unsigned markersAtLine(int linenr) const;
void markerDelete(int linenr, int markerNumber = -1);
void markerDeleteAll(int markerNumber = -1);
void markerDeleteHandle(int mhandle);
int markerLine(int mhandle) const;
int markerFindNext(int linenr, unsigned mask) const;
int markerFindPrevious(int linenr, unsigned mask) const;
bool overwriteMode() const;
QColor paper() const;
int positionFromLineIndex(int line, int index) const;
bool read(QIODevice *io) /ReleaseGIL/;
virtual void recolor(int start = 0, int end = -1);
void registerImage(int id, const QPixmap &pm);
void registerImage(int id, const QImage &im);
virtual void replace(const QString &replaceStr);
void resetFoldMarginColors();
void resetHotspotBackgroundColor();
void resetHotspotForegroundColor();
int scrollWidth() const;
void setScrollWidth(int pixelWidth);
bool scrollWidthTracking() const;
void setScrollWidthTracking(bool enabled);
void setFoldMarginColors(const QColor &fore, const QColor &back);
void setAnnotationDisplay(AnnotationDisplay display);
void setAutoCompletionFillupsEnabled(bool enabled);
void setAutoCompletionFillups(const char *fillups);
void setAutoCompletionWordSeparators(const QStringList &separators);
void setCallTipsBackgroundColor(const QColor &col);
void setCallTipsForegroundColor(const QColor &col);
void setCallTipsHighlightColor(const QColor &col);
void setCallTipsPosition(CallTipsPosition position);
void setCallTipsStyle(CallTipsStyle style);
void setCallTipsVisible(int nr);
void setContractedFolds(const QList<int> &folds);
void setDocument(const QsciDocument &document);
void addEdgeColumn(int colnr, const QColor &col);
void clearEdgeColumns();
void setEdgeColor(const QColor &col);
void setEdgeColumn(int colnr);
void setEdgeMode(EdgeMode mode);
void setFirstVisibleLine(int linenr);
void setFont(const QFont &f);
void setHotspotBackgroundColor(const QColor &col);
void setHotspotForegroundColor(const QColor &col);
void setHotspotUnderline(bool enable);
void setHotspotWrap(bool enable);
void setIndicatorDrawUnder(bool under, int indicatorNumber = -1);
void setIndicatorForegroundColor(const QColor &col,
int indicatorNumber = -1);
void setIndicatorHoverForegroundColor(const QColor &col,
int indicatorNumber = -1);
void setIndicatorHoverStyle(IndicatorStyle style,
int indicatorNumber = -1);
void setIndicatorOutlineColor(const QColor &col, int indicatorNumber = -1);
void setMarginBackgroundColor(int margin, const QColor &col);
void setMarginOptions(int options);
void setMarginText(int line, const QString &text, int style);
void setMarginText(int line, const QString &text, const QsciStyle &style);
void setMarginText(int line, const QsciStyledText &text);
void setMarginText(int line, const QList<QsciStyledText> &text);
void setMarginType(int margin, MarginType type);
void clearMarginText(int line = -1);
void setMargins(int margins);
void setMarkerBackgroundColor(const QColor &col, int markerNumber = -1);
void setMarkerForegroundColor(const QColor &col, int markerNumber = -1);
void setMatchedBraceBackgroundColor(const QColor &col);
void setMatchedBraceForegroundColor(const QColor &col);
void setMatchedBraceIndicator(int indicatorNumber);
void resetMatchedBraceIndicator();
void setUnmatchedBraceBackgroundColor(const QColor &col);
void setUnmatchedBraceForegroundColor(const QColor &col);
void setUnmatchedBraceIndicator(int indicatorNumber);
void resetUnmatchedBraceIndicator();
void setWrapVisualFlags(WrapVisualFlag endFlag,
WrapVisualFlag startFlag = QsciScintilla::WrapFlagNone,
int indent = 0);
QString selectedText() const;
bool selectionToEol() const;
void setSelectionToEol(bool filled);
void setExtraAscent(int extra);
void setExtraDescent(int extra);
void setOverwriteMode(bool overwrite);
void setWhitespaceBackgroundColor(const QColor &col);
void setWhitespaceForegroundColor(const QColor &col);
void setWhitespaceSize(int size);
void setWrapIndentMode(WrapIndentMode mode);
void showUserList(int id, const QStringList &list);
QsciCommandSet *standardCommands() const;
void setTabDrawMode(TabDrawMode mode);
TabDrawMode tabDrawMode() const;
bool tabIndents() const;
int tabWidth() const;
QString text() const;
QString text(int line) const;
QString text(int start, int end) const;
int textHeight(int linenr) const;
int whitespaceSize() const;
WhitespaceVisibility whitespaceVisibility() const;
QString wordAtLineIndex(int line, int index) const;
QString wordAtPoint(const QPoint &point) const;
const char *wordCharacters() const;
WrapMode wrapMode() const;
WrapIndentMode wrapIndentMode() const;
bool write(QIODevice *io) const /ReleaseGIL/;
public slots:
virtual void append(const QString &text);
virtual void autoCompleteFromAll();
virtual void autoCompleteFromAPIs();
virtual void autoCompleteFromDocument();
virtual void callTip();
virtual void clear();
virtual void copy();
virtual void cut();
virtual void ensureCursorVisible();
virtual void ensureLineVisible(int line);
virtual void foldAll(bool children = false);
virtual void foldLine(int line);
virtual void indent(int line);
virtual void insert(const QString &text);
virtual void insertAt(const QString &text, int line, int index);
virtual void moveToMatchingBrace();
virtual void paste();
virtual void redo();
virtual void removeSelectedText();
virtual void replaceSelectedText(const QString &text);
virtual void resetSelectionBackgroundColor();
virtual void resetSelectionForegroundColor();
virtual void selectAll(bool select = true);
virtual void selectToMatchingBrace();
virtual void setAutoCompletionCaseSensitivity(bool cs);
virtual void setAutoCompletionReplaceWord(bool replace);
virtual void setAutoCompletionShowSingle(bool single);
virtual void setAutoCompletionSource(AutoCompletionSource source);
virtual void setAutoCompletionThreshold(int thresh);
virtual void setAutoCompletionUseSingle(AutoCompletionUseSingle single);
virtual void setAutoIndent(bool autoindent);
virtual void setBraceMatching(BraceMatch bm);
virtual void setBackspaceUnindents(bool unindent);
virtual void setCaretForegroundColor(const QColor &col);
virtual void setCaretLineBackgroundColor(const QColor &col);
virtual void setCaretLineFrameWidth(int width);
virtual void setCaretLineVisible(bool enable);
virtual void setCaretWidth(int width);
virtual void setColor(const QColor &col);
virtual void setCursorPosition(int line, int index);
virtual void setEolMode(EolMode mode);
virtual void setEolVisibility(bool visible);
virtual void setFolding(FoldStyle fold, int margin=2);
void clearFolds();
virtual void setIndentation(int line, int indentation);
virtual void setIndentationGuides(bool enable);
virtual void setIndentationGuidesBackgroundColor(const QColor &col);
virtual void setIndentationGuidesForegroundColor(const QColor &col);
virtual void setIndentationsUseTabs(bool tabs);
virtual void setIndentationWidth(int width);
virtual void setLexer(QsciLexer *lexer = 0);
virtual void setMarginsBackgroundColor(const QColor &col);
virtual void setMarginsFont(const QFont &f);
virtual void setMarginsForegroundColor(const QColor &col);
virtual void setMarginLineNumbers(int margin, bool lnrs);
virtual void setMarginMarkerMask(int margin, int mask);
virtual void setMarginSensitivity(int margin, bool sens);
virtual void setMarginWidth(int margin, int width);
virtual void setMarginWidth(int margin, const QString &s);
virtual void setModified(bool m);
virtual void setPaper(const QColor &c);
virtual void setReadOnly(bool ro);
virtual void setSelection(int lineFrom, int indexFrom, int lineTo,
int indexTo);
virtual void setSelectionBackgroundColor(const QColor &col);
virtual void setSelectionForegroundColor(const QColor &col);
virtual void setTabIndents(bool indent);
virtual void setTabWidth(int width);
virtual void setText(const QString &text);
virtual void setUtf8(bool cp);
virtual void setWhitespaceVisibility(WhitespaceVisibility mode);
virtual void setWrapMode(WrapMode mode);
virtual void undo();
virtual void unindent(int line);
virtual void zoomIn(int range);
virtual void zoomIn();
virtual void zoomOut(int range);
virtual void zoomOut();
virtual void zoomTo(int size);
signals:
void cursorPositionChanged(int line, int index);
void copyAvailable(bool yes);
void indicatorClicked(int line, int index, Qt::KeyboardModifiers state);
void indicatorReleased(int line, int index, Qt::KeyboardModifiers state);
void linesChanged();
void marginClicked(int margin, int line, Qt::KeyboardModifiers state);
void marginRightClicked(int margin, int line, Qt::KeyboardModifiers state);
void modificationAttempted();
void modificationChanged(bool m);
void selectionChanged();
void textChanged();
void userListActivated(int id, const QString &string);
protected:
virtual bool event(QEvent *event);
virtual void changeEvent(QEvent *event);
virtual void contextMenuEvent(QContextMenuEvent *event);
virtual void wheelEvent(QWheelEvent *event);
private:
QsciScintilla(const QsciScintilla &);
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
// This is the SIP interface definition for QsciStyle.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciStyle
{
%TypeHeaderCode
#include <Qsci/qscistyle.h>
%End
public:
enum TextCase {
OriginalCase,
UpperCase,
LowerCase
};
QsciStyle(int style = -1);
QsciStyle(int style, const QString &description, const QColor &color,
const QColor &paper, const QFont &font, bool eolFill = false);
void setStyle(int style);
int style() const;
void setDescription(const QString &description);
QString description() const;
void setColor(const QColor &color);
QColor color() const;
void setPaper(const QColor &paper);
QColor paper() const;
void setFont(const QFont &font);
QFont font() const;
void setEolFill(bool fill);
bool eolFill() const;
void setTextCase(TextCase text_case);
TextCase textCase() const;
void setVisible(bool visible);
bool visible() const;
void setChangeable(bool changeable);
bool changeable() const;
void setHotspot(bool hotspot);
bool hotspot() const;
void refresh();
};

View File

@@ -0,0 +1,33 @@
// This is the SIP interface definition for QsciStyledText.
//
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file. Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
//
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license. For more information contact
// info@riverbankcomputing.com.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
class QsciStyledText
{
%TypeHeaderCode
#include <Qsci/qscistyledtext.h>
%End
public:
QsciStyledText(const QString &text, int style);
QsciStyledText(const QString &text, const QsciStyle &style);
const QString &text();
int style() const;
};

View File

@@ -0,0 +1,22 @@
# This is the qmake file for the QScintilla plugin for Qt Designer.
TEMPLATE = lib
TARGET = qscintillaplugin
# Comment this in to build a dynamic library supporting multiple architectures
# on macOS.
#QMAKE_APPLE_DEVICE_ARCHS = x86_64 arm64
CONFIG += plugin qscintilla2
QT += designer
# Work around QTBUG-39300.
CONFIG -= android_install
HEADERS = qscintillaplugin.h
SOURCES = qscintillaplugin.cpp
target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS += target

View File

@@ -0,0 +1,167 @@
// This implements the QScintilla plugin for Qt Designer.
#include "qscintillaplugin.h"
#include <QtPlugin>
#include <Qsci/qsciscintilla.h>
static const char *qscintilla_pixmap[] = {
"22 22 35 1",
"m c #000000",
"n c #000033",
"p c #003300",
"r c #003333",
"v c #330000",
"o c #330033",
"l c #333300",
"h c #333333",
"c c #333366",
"d c #336666",
"u c #336699",
"E c #3366cc",
"k c #663333",
"i c #663366",
"b c #666666",
"e c #666699",
"A c #6666cc",
"G c #669966",
"f c #669999",
"j c #6699cc",
"y c #6699ff",
"t c #996666",
"a c #999999",
"g c #9999cc",
"s c #9999ff",
"C c #99cc99",
"x c #99cccc",
"w c #99ccff",
"F c #cc99ff",
"q c #cccccc",
"# c #ccccff",
"B c #ccffcc",
"z c #ccffff",
"D c #ffffcc",
". c none",
"........#abcda........",
"......abefghdidcf.....",
".....cadhfaehjheck....",
"....leh.m.ncbehjddo...",
"...depn.hqhqhr#mccch..",
"..bb.hcaeh.hqersjhjcd.",
".tcm.uqn.hc.uvwxhuygha",
".feh.n.hb.hhzemcwhmuAm",
"Bgehghqqme.eo#wlnysbnj",
"awhdAzn.engjepswhmuyuj",
"bCh#m.de.jpqwbmcwemlcz",
"hcb#xh.nd#qrbswfehwzbm",
"bd#d.A#zor#qmgbzwgjgws",
"ajbcuqhqzchwwbemewchmr",
"Dcn#cwmhgwehgsxbmhEjAc",
".uanauFrhbgeahAAbcbuhh",
".bohdAegcccfbbebuucmhe",
"..briuauAediddeclchhh.",
"...hcbhjccdecbceccch..",
"....nhcmeccdccephcp...",
".....crbhchhhrhhck....",
"......tcmdhohhcnG....."
};
QScintillaPlugin::QScintillaPlugin(QObject *parent)
: QObject(parent), initialized(false)
{
}
QScintillaPlugin::~QScintillaPlugin()
{
}
void QScintillaPlugin::initialize(QDesignerFormEditorInterface * /* core */)
{
initialized = true;
}
bool QScintillaPlugin::isInitialized() const
{
return initialized;
}
QWidget *QScintillaPlugin::createWidget(QWidget *parent)
{
return new QsciScintilla(parent);
}
QString QScintillaPlugin::name() const
{
return "QsciScintilla";
}
QString QScintillaPlugin::group() const
{
return "Input Widgets";
}
QIcon QScintillaPlugin::icon() const
{
return QIcon(QPixmap(qscintilla_pixmap));
}
QString QScintillaPlugin::toolTip() const
{
return "QScintilla Programmer's Editor";
}
QString QScintillaPlugin::whatsThis() const
{
return "A port to Qt of the Scintilla programmer's editor";
}
bool QScintillaPlugin::isContainer() const
{
return false;
}
QString QScintillaPlugin::domXml() const
{
return "<widget class=\"QsciScintilla\" name=\"textEdit\">\n"
" <property name=\"geometry\">\n"
" <rect>\n"
" <x>0</x>\n"
" <y>0</y>\n"
" <width>400</width>\n"
" <height>200</height>\n"
" </rect>\n"
" </property>\n"
" <property name=\"toolTip\" >\n"
" <string></string>\n"
" </property>\n"
" <property name=\"whatsThis\" >\n"
" <string></string>\n"
" </property>\n"
"</widget>\n";
}
QString QScintillaPlugin::includeFile() const
{
return "Qsci/qsciscintilla.h";
}
#if QT_VERSION < 0x050000
Q_EXPORT_PLUGIN2(qscintillaplugin, QScintillaPlugin)
#endif

View File

@@ -0,0 +1,38 @@
// This defines the QScintilla plugin for Qt Designer.
#ifndef _QSCINTILLAPLUGIN_H
#define _QSCINTILLAPLUGIN_H
#include <QtDesigner>
class QScintillaPlugin : public QObject, public QDesignerCustomWidgetInterface
{
Q_OBJECT
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface")
#endif
Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
QScintillaPlugin(QObject *parent = 0);
virtual ~QScintillaPlugin();
bool isContainer() const;
bool isInitialized() const;
QIcon icon() const;
QString domXml() const;
QString group() const;
QString includeFile() const;
QString name() const;
QString toolTip() const;
QString whatsThis() const;
QWidget *createWidget(QWidget *parent);
void initialize(QDesignerFormEditorInterface *core);
private:
bool initialized;
};
#endif

204
third_party/qscintilla/doc/README.doc vendored Normal file
View File

@@ -0,0 +1,204 @@
/*! \mainpage QScintilla - a Port to Qt v5 and Qt v6 of Scintilla
<h2>Introduction</h2>
<a href="http://www.riverbankcomputing.com/software/qscintilla/">QScintilla</a>
is a port to Qt of the <a href="http://www.scintilla.org/">Scintilla</a>
editing component.
As well as features found in standard text editing components, Scintilla
includes features especially useful when editing and debugging source code:
<ul>
<li>syntax styling with support for over 70 languages
<li>error indicators
<li>code completion
<li>call tips
<li>code folding
<li>margins can contain markers like those used in debuggers to indicate
breakpoints and the current line.
<li>recordable macros
<li>multiple views
<li>printing.
</ul>
QScintilla is a port or Scintilla to the Qt GUI toolkit from
<a href="http://www.qt.io">The Qt Company</a> and runs on any operating system
supported by Qt (eg. Windows, Linux, macOS, iOS and Android). QScintilla works
with Qt v5 and v6.
QScintilla also includes language bindings for
<a href="https://www.python.org">Python</a>. These require that
<a href="https://www.riverbankcomputing.com/software/pyqt/">PyQt</a> v5 or v6
is also installed.
This version of QScintilla is based on Scintilla v3.10.1.
<h2>Licensing</h2>
QScintilla is available under the
<a href="http://www.gnu.org/licenses/gpl.html">GNU General Public License v3</a>
and the Riverbank Commercial License.
The commercial license allows closed source applications using QScintilla to be
developed and distributed. At the moment the commercial version of QScintilla
is bundled with, but packaged separately from, the commercial version of
<a href="http://www.riverbankcomputing.com/software/pyqt/">PyQt</a>.
The Scintilla code within QScintilla is released under the following license:
<pre>
License for Scintilla and SciTE
Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation.
NEIL HODGSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS, IN NO EVENT SHALL NEIL HODGSON BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
OR PERFORMANCE OF THIS SOFTWARE.
</pre>
<h2>Installation</h2>
As supplied QScintilla will be built as a shared library/DLL and installed in
the same directories as the Qt libraries and include files.
If you wish to build a static version of the library then pass
<tt>CONFIG+=staticlib</tt> on the <tt>qmake</tt> command line.
On macOS, if you wish to build a dynamic version of the library that supports
both <tt>x86_64</tt> and <tt>arm64</tt> architectures then edit the file
<tt>qscintilla.pro</tt> in the <tt>src</tt> directory and comment in the
definition of <tt>QMAKE_APPLE_DEVICE_ARCHS</tt>. Similar changes can be made
to the <tt>.pro</tt> files for the Designer plugin and the example application.
If you want to make more significant changes to the configuration then edit the
file <tt>qscintilla.pro</tt> in the <tt>src</tt> directory.
If you do make changes, specifically to the names of the installation
directories or the name of the library, then you may also need to update the
<tt>src/features/qscintilla2.prf</tt> file.
See your <tt>qmake</tt> documentation for more details.
To build and install QScintilla, run:
<pre>
cd src
qmake
make
make install
</pre>
If you have multiple versions of Qt installed then make sure you use the
correct version of <tt>qmake</tt>.
The underlying Scintilla code may support additional compile-time options.
These can be configured by passing appropriate arguments to <tt>qmake</tt>.
For example, if you have an old C++ compiler that does not have a working
<tt>std::regex</tt> then invoke <tt>qmake</tt> as follows:
<pre>
qmake DEFINES+=NO_CXX11_REGEX=1
</pre>
<h3>Installation on Windows</h3>
Before compiling QScintilla on Windows you should remove the <tt>Qsci</tt>
directory containing the QScintilla header files from any previous
installation. This is because the <tt>Makefile</tt> generated by
<tt>qmake</tt> will find these older header files instead of the new ones.
Depending on the compiler you are using you may need to run <tt>nmake</tt>
rather than <tt>make</tt>.
If you have built a Windows DLL then you probably also want to run:
<pre>
copy %%QTDIR%\\lib\\qscintilla2.dll %%QTDIR%\\bin
</pre>
<h2>Integration with <tt>qmake</tt></h2>
To configure <tt>qmake</tt> to find your QScintilla installation, add the
following line to your application's <tt>.pro</tt> file:
<pre>
CONFIG += qscintilla2
</pre>
<h2>Qt Designer Plugin</h2>
QScintilla includes an optional plugin for Qt Designer that allows QScintilla
instances to be included in GUI designs just like any other Qt widget.
To build the plugin on all platforms, make sure QScintilla is installed and
then run (as root or administrator):
<pre>
cd designer
qmake
make
make install
</pre>
On Windows (and depending on the compiler you are using) you may need to run
<tt>nmake</tt> rather than <tt>make</tt>.
<h2>Example Application</h2>
The example application provided is a port of the standard Qt
<tt>application</tt> example with the QsciScintilla class being used instead of
Qt's QTextEdit class.
The example does not demonstrate all of the extra features of QScintilla.
To build the example, run:
<pre>
cd example
qmake
make
</pre>
On Windows (and depending on the compiler you are using) you may need to run
<tt>nmake</tt> rather than <tt>make</tt>.
<h2>Python Bindings</h2>
The Python bindings are in the <tt>Python</tt> sub-directory. You must have
either PyQt5 or PyQt6 already installed and PyQt-builder. QScintilla must also
already be built and installed.
The <tt>Python</tt> sub-directory contains a <tt>pyproject-qt5.toml</tt> file
and a <tt>pyproject-qt6.toml</tt> file. If you are building for PyQt5 and Qt
v5 then you must copy the <tt>pyproject-qt5.toml</tt> file to
<tt>pyproject.toml</tt>. If instead you are building for PyQt6 and Qt v6 then
you must copy the <tt>pyproject-qt6.toml</tt> file to <tt>pyproject.toml</tt>.
To build and install the bindings, run:
<pre>
cd Python
sip-install
</pre>
*/

View File

@@ -0,0 +1,246 @@
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org" />
<meta name="generator" content="SciTE" />
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>
Scintilla and SciTE
</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<table bgcolor="#000000" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
<td>
<img src="SciTEIco.png" border="3" height="64" width="64" alt="Scintilla icon" />
</td>
<td>
<a href="index.html" style="color:white;text-decoration:none"><font size="5">Scintilla
Component Design</font></a>
</td>
</tr>
</table>
<h2>
Top level structure
</h2>
<p>
Scintilla consists of three major layers of C++ code
</p>
<ul>
<li>
Portability Library
</li>
<li>
Core Code
</li>
<li>
Platform Events and API
</li>
</ul>
<p>
The primary purpose of this structure is to separate the platform dependent code from the
platform independent core code. This makes it easier to port Scintilla to a new platform and
ensures that most readers of the code do not have to deal with platform details. To minimise
portability problems and avoid code bloat, a conservative subset of C++ is used in Scintilla
with no exception handling, run time type information or use of the standard C++
library and with limited use of templates.
</p>
<p>
The currently supported platforms, Windows, GTK+/Linux, Cocoa and wxWidgets are fairly similar in
many ways.
Each has windows, menus and bitmaps. These features generally work in similar ways so each
has a way to move a window or draw a red line. Sometimes one platform requires a sequence of
calls rather than a single call. At other times, the differences are more profound. Reading
the Windows clipboard occurs synchronously but reading the GTK+ clipboard requires a request
call that will be asynchronously answered with a message containing the clipboard data.
The wxWidgets platform is available from the <a href="http://wxwidgets.org/">wxWidgets site</a>
</p>
<br />
<h3>
Portability Library
</h3>
<p>
This is a fairly small and thin layer over the platform's native capabilities.
</p>
<p>
The portability library is defined in Platform.h and is implemented once for each platform.
PlatWin.cxx defines the Windows variants of the methods and PlatGTK.cxx the GTK+ variants.
</p>
<p>
Several of the classes here hold platform specific object identifiers and act as proxies to
these platform objects. Most client code can thus manipulate the platform objects without
caring which is the current platform. Sometimes client code needs access to the underlying
object identifiers and this is provided by the GetID method. The underlying types of the
platform specific identifiers are typedefed to common names to allow them to be transferred
around in client code where needed.
</p>
<h4>
Point, PRectangle
</h4>
<p>
These are simple classes provided to hold the commonly used geometric primitives. A
PRectangle follows the Mac / Windows convention of not including its bottom and right sides
instead of including all its sides as is normal in GTK+. It is not called Rectangle as this may be
the name of a macro on Windows.
</p>
<h4>
ColourDesired
</h4>
<p>
This is a simple class holding an expected colour. It is internally represented as a single
32 bit integer in BGR format with 8 bits per colour, but also provides a convenient API to fetch
each component separately.
As a platform might not be able to represent the exact desired colour if it doesn't have 24 bit
depth available, it might not actually represent the exact desired colour but select a best fit
that it can actually render.
</p>
<h4>
Font
</h4>
<p>
Font holds a platform specific font identifier - HFONT for Windows, PangoFontDescription* for GTK+. It
does not own the identifier and so will not delete the platform font object in its
destructor. Client code should call Destroy at appropriate times.
</p>
<h4>
Surface
</h4>
<p>
Surface is an abstraction over each platform's concept of somewhere that graphical drawing
operations can be done. It may wrap an already created drawing place such as a window or be
used to create a bitmap that can be drawn into and later copied onto another surface. On
Windows it wraps a HDC and possibly a HBITMAP. On GTK+ it wraps a cairo_surface_t*.
Other platform specific objects are created (and correctly destroyed) whenever
required to perform drawing actions.
</p>
<p>
Drawing operations provided include drawing filled and unfilled polygons, lines, rectangles,
ellipses and text. The height and width of text as well as other details can be measured.
Operations can be clipped to a rectangle. Most of the calls are stateless with all parameters
being passed at each call. The exception to this is line drawing which is performed by
calling MoveTo and then LineTo.
</p>
<h4>
Window
</h4>
<p>
Window acts as a proxy to a platform window allowing operations such as showing, moving,
redrawing, and destroying to be performed. It contains a platform specific window identifier
- HWND for Windows, GtkWidget* for GTK+.
</p>
<h4>
ListBox
</h4>
<p>
ListBox is a subclass of Window and acts as a proxy to a platform listbox adding methods for
operations such as adding, retrieving, and selecting items.
</p>
<h4>
Menu
</h4>
<p>
Menu is a small helper class for constructing popup menus. It contains the platform specific
menu identifier - HMENU for Windows, GtkMenu* for GTK+. Most of the work in
constructing menus requires access to platform events and so is done in the Platform Events
and API layer.
</p>
<h4>
Platform
</h4>
<p>
The Platform class is used to access the facilities of the platform. System wide parameters
such as double click speed and chrome colour are available from Platform. Utility functions
such as DebugPrintf are also available from Platform.
</p>
<h3>
Core Code
</h3>
<p>
The bulk of Scintilla's code is platform independent. This is made up of the CellBuffer,
ContractionState, Document, Editor, Indicator, LineMarker, Style, ViewStyle, KeyMap,
ScintillaBase, CallTip,
and AutoComplete primary classes.
</p>
<h4>
CellBuffer
</h4>
<p>
A CellBuffer holds text and styling information, the undo stack, the assignment of line
markers to lines, and the fold structure.
</p>
<p>
A cell contains a character byte and its associated style byte. The current state of the
cell buffer is the sequence of cells that make up the text and a sequence of line information
containing the starting position of each line and any markers assigned to each line.
</p>
<p>
The undo stack holds a sequence of actions on the cell buffer. Each action is one of a text
insertion, a text deletion or an undo start action. The start actions are used to group
sequences of text insertions and deletions together so they can be undone together. To
perform an undo operation, each insertion or deletion is undone in reverse sequence.
Similarly, redo reapplies each action to the buffer in sequence. Whenever a character is
inserted in the buffer either directly through a call such as InsertString or through undo or
redo, its styling byte is initially set to zero. Client code is responsible for styling each
character whenever convenient. Styling information is not stored in undo actions.
</p>
<h4>
Document
</h4>
<p>
A document contains a CellBuffer and deals with some higher level abstractions such as
words, DBCS character sequences and line end character sequences. It is responsible for
managing the styling process and for notifying other objects when changes occur to the
document.
</p>
<h4>
Editor
</h4>
<p>
The Editor object is central to Scintilla. It is responsible for displaying a document and
responding to user actions and requests from the container. It uses ContractionState, Indicator,
LineMarker, Style, and ViewStyle objects to display the document and a KeyMap class to
map key presses to functions.
The visibility of each line is kept in the ContractionState which is also responsible for mapping
from display lines to documents lines and vice versa.
</p>
<p>
There may be multiple Editor objects attached to one Document object. Changes to a
document are broadcast to the editors through the DocWatcher mechanism.
</p>
<h4>
ScintillaBase
</h4>
<p>
ScintillaBase is a subclass of Editor and adds extra windowing features including display of
calltips, autocompletion lists and context menus. These features use CallTip and AutoComplete
objects. This class is optional so a lightweight implementation of Scintilla may bypass it if
the added functionality is not required.
</p>
<h3>
Platform Events and API
</h3>
<p>
Each platform uses different mechanisms for receiving events. On Windows, events are
received through messages and COM. On GTK+, callback functions are used.
</p>
<p>
For each platform, a class is derived from ScintillaBase (and thus from Editor). This is
ScintillaWin on Windows and ScintillaGTK on GTK+. These classes are responsible for
connecting to the platforms event mechanism and also to implement some virtual methods in
Editor and ScintillaBase which are different on the platforms. For example, this layer has to
support this difference between the synchronous Windows clipboard and the asynchronous GTK+
clipboard.
</p>
<p>
The external API is defined in this layer as each platform has different preferred styles of
API - messages on Windows and function calls on GTK+. This also allows multiple APIs to be
defined on a platform. The currently available API on GTK+ is similar to the Windows API and
does not follow platform conventions well. A second API could be implemented here that did
follow platform conventions.
</p>
</body>
</html>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org" />
<meta name="generator" content="SciTE" />
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>
Scintilla icons
</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<table bgcolor="#000000" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
<td>
<img src="SciTEIco.png" border="3" height="64" width="64" alt="Scintilla icon" />
</td>
<td>
<a href="index.html" style="color:white;text-decoration:none"><font size="5">Scintilla
and SciTE</font></a>
</td>
</tr>
</table>
<h2>
Icons
</h2>
<p>
These images may be used under the same license as Scintilla.
</p>
<p>
Drawn by Iago Rubio, Philippe Lhoste, and Neil Hodgson.
</p>
<p>
<a href="http://prdownloads.sourceforge.net/scintilla/icons1.zip?download">zip format</a> (70K)
</p>
<table>
<tr>
<td>For autocompletion lists</td>
<td colspan="3">For margin markers</td>
</tr>
<tr>
<td>12x12</td>
<td>16x16</td>
<td>24x24</td>
<td>32x32</td>
</tr>
<tr>
<td valign="top"><img src="12.png" /></td>
<td valign="top"><img src="16.png" /></td>
<td valign="top"><img src="24.png" /></td>
<td valign="top"><img src="32.png" /></td>
</tr>
</table>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,226 @@
How to write a scintilla lexer
A lexer for a particular language determines how a specified range of
text shall be colored. Writing a lexer is relatively straightforward
because the lexer need only color given text. The harder job of
determining how much text actually needs to be colored is handled by
Scintilla itself, that is, the lexer's caller.
Parameters
The lexer for language LLL has the following prototype:
static void ColouriseLLLDoc (
unsigned int startPos, int length,
int initStyle,
WordList *keywordlists[],
Accessor &styler);
The styler parameter is an Accessor object. The lexer must use this
object to access the text to be colored. The lexer gets the character
at position i using styler.SafeGetCharAt(i);
The startPos and length parameters indicate the range of text to be
recolored; the lexer must determine the proper color for all characters
in positions startPos through startPos+length.
The initStyle parameter indicates the initial state, that is, the state
at the character before startPos. States also indicate the coloring to
be used for a particular range of text.
Note: the character at StartPos is assumed to start a line, so if a
newline terminates the initStyle state the lexer should enter its
default state (or whatever state should follow initStyle).
The keywordlists parameter specifies the keywords that the lexer must
recognize. A WordList class object contains methods that simplify
the recognition of keywords. Present lexers use a helper function
called classifyWordLLL to recognize keywords. These functions show how
to use the keywordlists parameter to recognize keywords. This
documentation will not discuss keywords further.
The lexer code
The task of a lexer can be summarized briefly: for each range r of
characters that are to be colored the same, the lexer should call
styler.ColourTo(i, state)
where i is the position of the last character of the range r. The lexer
should set the state variable to the coloring state of the character at
position i and continue until the entire text has been colored.
Note 1: the styler (Accessor) object remembers the i parameter in the
previous calls to styler.ColourTo, so the single i parameter suffices to
indicate a range of characters.
Note 2: As a side effect of calling styler.ColourTo(i,state), the
coloring states of all characters in the range are remembered so that
Scintilla may set the initStyle parameter correctly on future calls to
the
lexer.
Lexer organization
There are at least two ways to organize the code of each lexer. Present
lexers use what might be called a "character-based" approach: the outer
loop iterates over characters, like this:
lengthDoc = startPos + length ;
for (unsigned int i = startPos; i < lengthDoc; i++) {
chNext = styler.SafeGetCharAt(i + 1);
<< handle special cases >>
switch(state) {
// Handlers examine only ch and chNext.
// Handlers call styler.ColorTo(i,state) if the state changes.
case state_1: << handle ch in state 1 >>
case state_2: << handle ch in state 2 >>
...
case state_n: << handle ch in state n >>
}
chPrev = ch;
}
styler.ColourTo(lengthDoc - 1, state);
An alternative would be to use a "state-based" approach. The outer loop
would iterate over states, like this:
lengthDoc = startPos+lenth ;
for ( unsigned int i = startPos ;; ) {
char ch = styler.SafeGetCharAt(i);
int new_state = 0 ;
switch ( state ) {
// scanners set new_state if they set the next state.
case state_1: << scan to the end of state 1 >> break ;
case state_2: << scan to the end of state 2 >> break ;
case default_state:
<< scan to the next non-default state and set new_state >>
}
styler.ColourTo(i, state);
if ( i >= lengthDoc ) break ;
if ( ! new_state ) {
ch = styler.SafeGetCharAt(i);
<< set state based on ch in the default state >>
}
}
styler.ColourTo(lengthDoc - 1, state);
This approach might seem to be more natural. State scanners are simpler
than character scanners because less needs to be done. For example,
there is no need to test for the start of a C string inside the scanner
for a C comment. Also this way makes it natural to define routines that
could be used by more than one scanner; for example, a scanToEndOfLine
routine.
However, the special cases handled in the main loop in the
character-based approach would have to be handled by each state scanner,
so both approaches have advantages. These special cases are discussed
below.
Special case: Lead characters
Lead bytes are part of DBCS processing for languages such as Japanese
using an encoding such as Shift-JIS. In these encodings, extended
(16-bit) characters are encoded as a lead byte followed by a trail byte.
Lead bytes are rarely of any lexical significance, normally only being
allowed within strings and comments. In such contexts, lexers should
ignore ch if styler.IsLeadByte(ch) returns TRUE.
Note: UTF-8 is simpler than Shift-JIS, so no special handling is
applied for it. All UTF-8 extended characters are >= 128 and none are
lexically significant in programming languages which, so far, use only
characters in ASCII for operators, comment markers, etc.
Special case: Folding
Folding may be performed in the lexer function. It is better to use a
separate folder function as that avoids some troublesome interaction
between styling and folding. The folder function will be run after the
lexer function if folding is enabled. The rest of this section explains
how to perform folding within the lexer function.
During initialization, lexers that support folding set
bool fold = styler.GetPropertyInt("fold");
If folding is enabled in the editor, fold will be TRUE and the lexer
should call:
styler.SetLevel(line, level);
at the end of each line and just before exiting.
The line parameter is simply the count of the number of newlines seen.
It's initial value is styler.GetLine(startPos) and it is incremented
(after calling styler.SetLevel) whenever a newline is seen.
The level parameter is the desired indentation level in the low 12 bits,
along with flag bits in the upper four bits. The indentation level
depends on the language. For C++, it is incremented when the lexer sees
a '{' and decremented when the lexer sees a '}' (outside of strings and
comments, of course).
The following flag bits, defined in Scintilla.h, may be set or cleared
in the flags parameter. The SC_FOLDLEVELWHITEFLAG flag is set if the
lexer considers that the line contains nothing but whitespace. The
SC_FOLDLEVELHEADERFLAG flag indicates that the line is a fold point.
This normally means that the next line has a greater level than present
line. However, the lexer may have some other basis for determining a
fold point. For example, a lexer might create a header line for the
first line of a function definition rather than the last.
The SC_FOLDLEVELNUMBERMASK mask denotes the level number in the low 12
bits of the level param. This mask may be used to isolate either flags
or level numbers.
For example, the C++ lexer contains the following code when a newline is
seen:
if (fold) {
int lev = levelPrev;
// Set the "all whitespace" bit if the line is blank.
if (visChars == 0)
lev |= SC_FOLDLEVELWHITEFLAG;
// Set the "header" bit if needed.
if ((levelCurrent > levelPrev) && (visChars > 0))
lev |= SC_FOLDLEVELHEADERFLAG;
styler.SetLevel(lineCurrent, lev);
// reinitialize the folding vars describing the present line.
lineCurrent++;
visChars = 0; // Number of non-whitespace characters on the line.
levelPrev = levelCurrent;
}
The following code appears in the C++ lexer just before exit:
// Fill in the real level of the next line, keeping the current flags
// as they will be filled in later.
if (fold) {
// Mask off the level number, leaving only the previous flags.
int flagsNext = styler.LevelAt(lineCurrent);
flagsNext &= ~SC_FOLDLEVELNUMBERMASK;
styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}
Don't worry about performance
The writer of a lexer may safely ignore performance considerations: the
cost of redrawing the screen is several orders of magnitude greater than
the cost of function calls, etc. Moreover, Scintilla performs all the
important optimizations; Scintilla ensures that a lexer will be called
only to recolor text that actually needs to be recolored. Finally, it
is not necessary to avoid extra calls to styler.ColourTo: the sytler
object buffers calls to ColourTo to avoid multiple updates of the
screen.
Page contributed by Edward K. Ream

View File

@@ -0,0 +1,70 @@
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="generator" content="SciTE" />
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>
Privacy Policy
</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<table bgcolor="#000000" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
<td>
<img src="SciTEIco.png" border="3" height="64" width="64" alt="Scintilla icon" />
</td>
<td>
<a href="index.html" style="color:white;text-decoration:none"><font size="5">Scintilla
and SciTE</font></a>
</td>
</tr>
</table>
<h2>
Privacy Policy for scintilla.org
</h2>
<h3>
Information Collected
</h3>
<p>
Logs are collected to allow analysis of which pages are viewed.
The advertisements collect viewing information through Google Analytics which is
used by Google and advertisers.
No personally identifiable information is collected by scintilla.org.
</p>
<h3>
External Links
</h3>
<p>
Other web sites are linked to from this site.
These web sites have their own privacy policies which may differ significantly to those of scintilla.org.
</p>
<h3>
Cookies
</h3>
<p>
A cookie is a text file placed on the hard drive of a computer by some web pages which is used to remember
when a particular user returns to that site.
The advertisements shown on the main pages may use cookies.
</p>
<h3>
Contact
</h3>
<p>
This web site is the responsibility of Neil Hodgson.
Most queries about the site contents should go to one of the mailing lists mentioned on the main pages.
Queries about the privacy policy may be sent to neilh @ scintilla.org.
</p>
<h3>
Changes to this Policy
</h3>
<p>
This policy may change. If it does then this page will be updated and the date at the bottom will change.
</p>
<p>
This policy was last updated 2 June 2015.
</p>
</body>
</html>

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