Some Improvements to the MiniZinc IDE Code Editor

19 views
Skip to first unread message

Gonzalo Hernandez

unread,
Nov 10, 2025, 1:05:39 AMNov 10
to MiniZinc
Hi Team, I want to share with you some of my improvements I’ve made to the IDE code editor while working with MiniZinc.

All in the codeeditor.cpp  file.

1. Mimicking the Tab-key behaviour using spaces (updating current implementation).
I updated the Tab-key handling so that when tabs are turned into spaces, pressing Tab inserts the correct number of spaces to reach the next indentation level, accurately mimicking real tab stops.

219 } else if (e->key() == Qt::Key_Tab) {
220 e->accept();
221 auto cursor = textCursor();
auto startBlock = document()->findBlock(cursor.selectionStart());
auto endBlock = document()->findBlock(cursor.selectionEnd());
auto partialLineSelection = startBlock.position() != cursor.selectionStart()
|| endBlock.position() + endBlock.length() - 1 != cursor.selectionEnd();
if (!cursor.hasSelection() || (startBlock == endBlock && partialLineSelection)) {
if (useTabs) {
cursor.insertText("\t");
} else {
auto posInLine = cursor.selectionStart() - startBlock.position();
auto distanceFromTabStop = 0;
auto line = startBlock.text();
for (int i = 0; i < posInLine; i++) {
if (line[i] == '\t') {
distanceFromTabStop = 0;
} else {
distanceFromTabStop = (distanceFromTabStop + 1) % indentSize;
}
}
auto toAdd = indentSize - distanceFromTabStop;
cursor.insertText(QString(" ").repeated(toAdd));
}
} else {
shiftRight();
}
ensureCursorVisible();
}

Gonzalo Hernandez

unread,
Nov 10, 2025, 1:16:45 AMNov 10
to MiniZinc
2. Smart parentheses and brackets (autocomplete and wrapping of selections).
I also added smart bracket behaviour to the editor to automatically complete (, [, and {, following the standard behaviour of modern IDEs.
This feature supports both pair insertion and wrapping of selected text.

} else if (e->key() == Qt::Key_ParenLeft) {
e->accept();
auto cursor = textCursor();
QString selected = cursor.selectedText();
cursor.insertText("(" + selected + ")");
cursor.movePosition(QTextCursor::Left);
setTextCursor(cursor);
} else if (e->key() == Qt::Key_BracketLeft) {
e->accept();
auto cursor = textCursor();
QString selected = cursor.selectedText();
cursor.insertText("[" + selected + "]");
cursor.movePosition(QTextCursor::Left);
setTextCursor(cursor);
} else if (e->key() == Qt::Key_BraceLeft) {
e->accept();
auto cursor = textCursor();
QString selected = cursor.selectedText();
cursor.insertText("{" + selected + "}");
cursor.movePosition(QTextCursor::Left);
setTextCursor(cursor);
} else if ( e->key() == Qt::Key_ParenRight ||
e->key() == Qt::Key_BracketRight ||
e->key() == Qt::Key_BraceRight ) {

QTextCursor cursor = textCursor();
if (cursor.positionInBlock() < cursor.block().length() - 1) {
cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 1);
QString charRight = cursor.selectedText();
cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 1);
QChar typedChar = e->text().isEmpty() ? QChar() : e->text().at(0);
if (typedChar.isPrint() && charRight == typedChar) {
e->accept();
cursor.movePosition(QTextCursor::Right);
setTextCursor(cursor);
return;
}
}
QPlainTextEdit::keyPressEvent(e);
}

Gonzalo Hernandez

unread,
Nov 10, 2025, 1:18:45 AMNov 10
to MiniZinc
3. Avoiding overwritting brackets or removing properly autoinserted brackets, and  removing tabs inserted using spaces.
I improved the behaviour of Backspace so that it properly interacts with auto-inserted brackets and space-based indentation. When using spaces instead of tabs, pressing Backspace in leading whitespace removes exactly one indentation level. Additionally, if the cursor is between an auto-inserted bracket pair—such as (|), [|] or {|}—pressing Backspace removes both characters together, preventing leftover unmatched brackets.

} else if (e->key() == Qt::Key_Backspace) {
QTextCursor cursor = textCursor();
if (!cursor.hasSelection() && cursor.positionInBlock() > 0) {
QString line = cursor.block().text();
int pos = cursor.positionInBlock();
if (!useTabs) {
if (line.left(pos).trimmed().isEmpty()) {
int removeCount = (pos % indentSize == 0 ? indentSize : pos % indentSize);
cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, removeCount);
cursor.removeSelectedText();
setTextCursor(cursor);
ensureCursorVisible();
e->accept();
return;
}
}
if (cursor.positionInBlock() < cursor.block().length()) {
QChar charBefore = line.at(pos - 1);
QChar charAfter = line.at(pos);
if ((charBefore == '(' && charAfter == ')') ||
(charBefore == '[' && charAfter == ']') ||
(charBefore == '{' && charAfter == '}'))
{
cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 1);
cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 2);
cursor.removeSelectedText();
setTextCursor(cursor);
ensureCursorVisible();
e->accept();
return;
}
}
}
QPlainTextEdit::keyPressEvent(e);
}
Reply all
Reply to author
Forward
0 new messages