#include "qcodeedit.h" #include #include #include #include #include #include #include #include #include #include #include QCodeEdit::QCodeEdit(QWidget * parent): QWidget(parent) { prev_lc = auto_comp_pl = -1; textCode = textLines = 0; timer = 0; _ignore_focus_out = false; es_line.format.setBackground(QColor(240, 245, 240)); es_line.format.setProperty(QTextFormat::FullWidthSelection, true); completer.setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); completer.setFocusPolicy(Qt::NoFocus); completer.setColumnCount(2); completer.setRootIsDecorated(false); completer.setHeaderHidden(true); completer.installEventFilter(this); completer.header()->setDefaultAlignment(Qt::AlignCenter); completer.header()-> #if (QT_VERSION >= 0x050000) setSectionResizeMode #else setResizeMode #endif (QHeaderView::ResizeToContents); completer.header()->setStretchLastSection(true); //completer.setColumnWidth(0, 180); completer.resize(500, 200); textCode = new QPlainTextEdit(); textLines = new QPlainTextEdit(); textCode->setFrameShadow(QFrame::Plain); textCode->setFrameShape(QFrame::NoFrame); textCode->setLineWrapMode(QPlainTextEdit::NoWrap); textCode->setTabChangesFocus(false); textCode->installEventFilter(this); textCode->viewport()->installEventFilter(this); textLines->setFrameShadow(QFrame::Plain); textLines->setFrameShape(QFrame::NoFrame); textLines->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); textLines->setFocusPolicy(Qt::NoFocus); textLines->setTextInteractionFlags(Qt::NoTextInteraction); textLines->setLineWrapMode(QPlainTextEdit::NoWrap); textLines->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); textLines->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); textLines->viewport()->setAutoFillBackground(false); textLines->viewport()->setCursor(Qt::ArrowCursor); textLines->viewport()->installEventFilter(this); textLines->setFixedWidth(textLines->fontMetrics().width(" ")); setLayout(new QBoxLayout(QBoxLayout::BottomToTop)); layout()->setContentsMargins(0, 0, 0, 0); QFrame * frame = new QFrame(); frame->setFrameShadow(QFrame::Sunken); frame->setFrameShape(QFrame::StyledPanel); frame->setLayout(new QBoxLayout(QBoxLayout::LeftToRight)); frame->layout()->setContentsMargins(0, 0, 0, 0); frame->layout()->setSpacing(0); frame->layout()->addWidget(textLines); frame->layout()->addWidget(textCode); layout()->addWidget(frame); QAction * a = new QAction(this); a->setShortcut(QKeySequence("Shift+Tab")); a->setShortcutContext(Qt::WidgetShortcut); connect(a, SIGNAL(triggered(bool)), this, SLOT(deindent())); textCode->addAction(a); a = new QAction(this); a->setShortcut(QKeySequence("Ctrl+D")); a->setShortcutContext(Qt::WidgetShortcut); connect(a, SIGNAL(triggered(bool)), this, SLOT(deleteLine())); textCode->addAction(a); frame->setFocusProxy(textCode); QTextOption to = textLines->document()->defaultTextOption(); to.setAlignment(Qt::AlignTop | Qt::AlignRight); textLines->document()->setDefaultTextOption(to); setShowSpaces(true); connect(&completer, SIGNAL(itemDoubleClicked(QTreeWidgetItem * ,int)), this, SLOT(commitCompletition())); connect(textCode->verticalScrollBar(), SIGNAL(valueChanged(int)), textLines->verticalScrollBar(), SLOT(setValue(int))); connect(textCode, SIGNAL(textChanged()), this, SLOT(updateLines())); connect(textCode, SIGNAL(textChanged()), this, SIGNAL(textChanged())); connect(textCode, SIGNAL(cursorPositionChanged()), this, SLOT(textEdit_cursorPositionChanged())); connect(textCode, SIGNAL(selectionChanged()), this, SLOT(textEdit_selectionChanged())); updateLines(); registerAutoCompletitionClass(-1, QCodeEdit::Keyword, "Words", QIcon(":/icons/code-word.png")); } QCodeEdit::~QCodeEdit() { delete textCode; delete textLines; } int QCodeEdit::skipRange(const QString & s, int pos, QChar oc, QChar cc, QChar sc) { int cnt = 0; bool skip = false; for (int i = pos - 1; i >= 0; --i) { QChar c = s[i]; if (skip) {skip = false; continue;} if (c == sc) {skip = true; continue;} if (c == cc) {cnt++; continue;} if (c == oc) {cnt--; if (cnt == 0) return i;} } return -1; } int QCodeEdit::skipCWord(const QString & s, int pos) { QChar pc(0), c(0); for (int i = pos - 1; i >= 0; --i) { pc = c; c = s[i]; if (c.isLetterOrNumber() || (c.toLatin1() == '_')) continue; if (pc.isLetter() || (pc.toLatin1() == '_')) return i + 1; return -1; } return -1; } bool QCodeEdit::matchWritten(QString s, QString w) { if (s.isEmpty() || w.isEmpty()) return true; if (s.contains(w, Qt::CaseInsensitive)) return true; int sp(0); for (int i = 0; i < w.size(); ++i, ++sp) { if (sp >= s.size()) return false; QChar wc(w[i].toLower()); bool ns = false, bl = true; while (sp < s.size()) { if (ns || s[sp].toLatin1() == '_') { if (s[sp].toLatin1() == '_') {sp++; bl = false; continue;} if (s[sp].isLower() && bl) {sp++; continue;} if (s[sp].toLower() != wc) return false; } if (s[sp].toLower() == wc) break; ns = true; sp++; } if (sp >= s.size()) return false; } return true; } QChar QCodeEdit::pairChar(QChar c) { switch (c.toLatin1()) { case '\"': return '\"'; case '(': return ')'; case ')': return '('; case '[': return ']'; case ']': return '['; default: break; } return QChar(); } bool QCodeEdit::eventFilter(QObject * o, QEvent * e) { if (textLines) { if (o == textLines->viewport()) { if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease || e->type() == QEvent::MouseMove || e->type() == QEvent::MouseButtonDblClick) { const_cast(((QMouseEvent*)e)->pos()) = QPoint(0, ((QMouseEvent*)e)->pos().y()); QApplication::sendEvent(textCode->viewport(), e); return true; } if (e->type() == QEvent::Wheel) { QApplication::sendEvent(textCode->viewport(), e); return true; } } } if (o == &completer) { //qDebug() << o << e; if (e->type() == QEvent::WindowActivate) _ignore_focus_out = true; //qDebug() << e; return QWidget::eventFilter(o, e); } if (textCode) { if (o == textCode->viewport()) { if (e->type() == QEvent::MouseButtonPress) completer.hide(); return QWidget::eventFilter(o, e); } if (o == textCode) { //qDebug() << o << e; QKeyEvent * ke; QChar kc(0); switch (e->type()) { case QEvent::KeyPress: ke = (QKeyEvent * )e; switch (ke->key()) { case Qt::Key_Space: if (ke->modifiers().testFlag(Qt::ControlModifier)) { invokeAutoCompletition(true); return true; } break; case Qt::Key_Escape: completer.hide(); break; case Qt::Key_Up: if (completer.isVisible()) { previousCompletition(); return true; } completer.hide(); if (ke->modifiers().testFlag(Qt::AltModifier)) { copyLineUp(); return true; } if (ke->modifiers().testFlag(Qt::ControlModifier) && ke->modifiers().testFlag(Qt::ShiftModifier)) { moveLineUp(); return true; } break; case Qt::Key_Down: if (completer.isVisible()) { nextCompletition(); return true; } completer.hide(); if (ke->modifiers().testFlag(Qt::AltModifier)) { copyLineDown(); return true; } if (ke->modifiers().testFlag(Qt::ControlModifier) && ke->modifiers().testFlag(Qt::ShiftModifier)) { moveLineDown(); return true; } break; case Qt::Key_Home: case Qt::Key_End: case Qt::Key_PageUp: case Qt::Key_PageDown: if (completer.isVisible()) { qApp->sendEvent(&completer, new QKeyEvent(e->type(), ke->key(), ke->modifiers())); return true; } break; case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_Backspace: case Qt::Key_Delete: if (completer.isVisible()) QMetaObject::invokeMethod(this, "invokeAutoCompletition", Qt::QueuedConnection, Q_ARG(bool, false)); break; case Qt::Key_Return: if (completer.isVisible()) { commitCompletition(); completer.hide(); return true; } if (textCode->textCursor().selectedText().isEmpty()) QMetaObject::invokeMethod(this, "autoIndent", Qt::QueuedConnection); break; case Qt::Key_Tab: if (!textCode->textCursor().selectedText().isEmpty()) { if (ke->modifiers().testFlag(Qt::ShiftModifier)) deindent(); else indent(); return true; } break; case Qt::Key_D: if (ke->modifiers().testFlag(Qt::ControlModifier)) { completer.hide(); return true; } break; default: break; } if (!ke->text().isEmpty()) kc = ke->text()[0]; if (kc == '.') { completer.hide(); QMetaObject::invokeMethod(this, "invokeAutoCompletition", Qt::QueuedConnection, Q_ARG(bool, false)); } else { if ((kc.isLetterOrNumber() || kc.toLatin1() == '_') && completer.isVisible()) QMetaObject::invokeMethod(this, "invokeAutoCompletition", Qt::QueuedConnection, Q_ARG(bool, false)); } break; case QEvent::FocusOut: if (_ignore_focus_out) { _ignore_focus_out = false; break; } case QEvent::Hide: case QEvent::HideToParent: case QEvent::MouseButtonPress: //qDebug() << e; completer.hide(); default: break; } } } return QWidget::eventFilter(o, e); } void QCodeEdit::timerEvent(QTimerEvent * ) { parse(); emit parseRequest(); killTimer(timer); timer = 0; } void QCodeEdit::applyExtraSelection() { textCode->setExtraSelections(QList() << es_line << es_selected << es_custom); } void QCodeEdit::nextCompletition() { int ci = completer.currentIndex().row(); if (ci >= completer.topLevelItemCount() - 1) return; if (completer.topLevelItem(ci + 1)->flags().testFlag(Qt::ItemIsSelectable)) completer.setCurrentItem(completer.topLevelItem(ci + 1)); else { if (ci >= completer.topLevelItemCount() - 2) return; completer.setCurrentItem(completer.topLevelItem(ci + 2)); } } void QCodeEdit::previousCompletition() { int ci = completer.currentIndex().row(); if (ci <= 0) return; if (completer.topLevelItem(ci - 1)->flags().testFlag(Qt::ItemIsSelectable)) completer.setCurrentItem(completer.topLevelItem(ci - 1)); else { if (ci <= 1) return; completer.setCurrentItem(completer.topLevelItem(ci - 2)); } } void QCodeEdit::deleteLine() { QTextCursor tc = textCode->textCursor(); tc.movePosition(QTextCursor::EndOfLine); tc.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); bool md = true; if (!tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor)) { tc.movePosition(QTextCursor::StartOfLine); tc.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); md = false; } tc.removeSelectedText(); tc.movePosition(QTextCursor::StartOfLine); if (md) tc.movePosition(QTextCursor::Down); textCode->setTextCursor(tc); } void QCodeEdit::copyLineUp() { QTextCursor tc = textCode->textCursor(); int ss = tc.selectionStart(), ss_ = ss, se = tc.selectionEnd(), se_ = se; QString st_ = tc.selection().toPlainText(); if (st_.endsWith("\n")) { st_.chop(1); se--; se_--; } tc.setPosition(ss); tc.movePosition(QTextCursor::StartOfLine); ss = tc.position(); tc.setPosition(se); tc.movePosition(QTextCursor::EndOfLine); se = tc.position(); tc.setPosition(ss); tc.setPosition(se, QTextCursor::KeepAnchor); bool ins_nl = false; if (!tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor)) ins_nl = true; QString l = tc.selectedText(); tc.beginEditBlock(); tc.setPosition(ss); if (ins_nl) l.append("\n"); tc.insertText(l); tc.setPosition(ss_); tc.setPosition(se_, QTextCursor::KeepAnchor); tc.endEditBlock(); textCode->setTextCursor(tc); } void QCodeEdit::copyLineDown() { QTextCursor tc = textCode->textCursor(); int ss = tc.selectionStart(), ss_ = ss, se = tc.selectionEnd(), se_ = se; QString st_ = tc.selection().toPlainText(); if (st_.endsWith("\n")) { st_.chop(1); se--; se_--; } tc.setPosition(ss); tc.movePosition(QTextCursor::StartOfLine); ss = tc.position(); tc.setPosition(se); tc.movePosition(QTextCursor::EndOfLine); se = tc.position(); tc.setPosition(ss); tc.setPosition(se, QTextCursor::KeepAnchor); bool ins_nl = false; if (!tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor)) ins_nl = true; QString l = tc.selectedText(); tc.beginEditBlock(); tc.setPosition(ss); ss_ += l.size(); se_ += l.size(); if (ins_nl) { l.append("\n"); ss_++; se_++; } tc.insertText(l); tc.setPosition(ss_); tc.setPosition(se_, QTextCursor::KeepAnchor); tc.endEditBlock(); textCode->setTextCursor(tc); } void QCodeEdit::moveLineUp() { QTextCursor tc = textCode->textCursor(); int ss = tc.selectionStart(), ss_ = ss, se = tc.selectionEnd(), se_ = se; QString st_ = tc.selection().toPlainText(); if (st_.endsWith("\n")) { st_.chop(1); se--; se_--; } tc.setPosition(ss); tc.movePosition(QTextCursor::StartOfLine); ss = tc.position(); tc.setPosition(se); tc.movePosition(QTextCursor::EndOfLine); se = tc.position(); tc.setPosition(ss); if (!tc.movePosition(QTextCursor::Up)) return; tc.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor); QString l = tc.selectedText(); ss -= l.size(); se -= l.size(); ss_ -= l.size(); se_ -= l.size(); tc.beginEditBlock(); tc.removeSelectedText(); tc.setPosition(se); bool de = false; if (!tc.movePosition(QTextCursor::Right)) { l.prepend("\n"); de = true; } tc.insertText(l); if (de) { tc.movePosition(QTextCursor::End); tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor); tc.removeSelectedText(); } tc.setPosition(ss_); tc.setPosition(se_, QTextCursor::KeepAnchor); tc.endEditBlock(); textCode->setTextCursor(tc); } void QCodeEdit::moveLineDown() { QTextCursor tc = textCode->textCursor(); int ss = tc.selectionStart(), ss_ = ss, se = tc.selectionEnd(), se_ = se; QString st_ = tc.selection().toPlainText(); if (st_.endsWith("\n")) { st_.chop(1); se--; se_--; } tc.setPosition(ss); tc.movePosition(QTextCursor::StartOfLine); ss = tc.position(); tc.setPosition(se); tc.movePosition(QTextCursor::EndOfLine); se = tc.position(); tc.setPosition(se); if (!tc.movePosition(QTextCursor::Right)) return; bool de = false; if (!tc.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor)) { tc.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); de = true; } QString l = tc.selectedText(); tc.beginEditBlock(); tc.removeSelectedText(); tc.setPosition(ss); if (de) l += "\n"; tc.insertText(l); if (de) { tc.movePosition(QTextCursor::End); tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor); tc.removeSelectedText(); } ss += l.size(); se += l.size(); ss_ += l.size(); se_ += l.size(); tc.setPosition(ss_); tc.setPosition(se_, QTextCursor::KeepAnchor); tc.endEditBlock(); textCode->setTextCursor(tc); } void QCodeEdit::indent() { QTextCursor tc = textCode->textCursor(); int ss = tc.selectionStart(), ss_ = ss, se = tc.selectionEnd(), se_ = se; QString st_ = tc.selection().toPlainText(); if (st_.endsWith("\n")) { st_.chop(1); se--; se_--; } tc.setPosition(ss); tc.movePosition(QTextCursor::StartOfLine); ss = tc.position(); tc.setPosition(se); tc.movePosition(QTextCursor::EndOfLine); se = tc.position(); tc.setPosition(ss); while (tc.position() < se_) { tc.insertText("\t"); se_++; tc.movePosition(QTextCursor::StartOfLine); if (!tc.movePosition(QTextCursor::Down)) break; } tc.setPosition(ss_ + 1); tc.setPosition(se_, QTextCursor::KeepAnchor); textCode->setTextCursor(tc); } void QCodeEdit::deindent() { QTextCursor tc = textCode->textCursor(); int ss = tc.selectionStart(), ss_ = ss, se = tc.selectionEnd(), se_ = se; QString st_ = tc.selection().toPlainText(); if (st_.endsWith("\n")) { st_.chop(1); se--; se_--; } tc.setPosition(ss); tc.movePosition(QTextCursor::StartOfLine); ss = tc.position(); tc.setPosition(se); tc.movePosition(QTextCursor::EndOfLine); se = tc.position(); tc.setPosition(ss); bool first = true; while (tc.position() < se_) { tc.movePosition(QTextCursor::StartOfLine); tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); int rs = 0; if (tc.selectedText() == "\t") { tc.removeSelectedText(); rs = 1; } else { for (int i = 0; i < 4; ++i) { tc.movePosition(QTextCursor::StartOfLine); tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); if (tc.selectedText() == " ") { tc.removeSelectedText(); rs++; } } } if (first) { first = false; ss_ -= rs; } se_ -= rs; tc.movePosition(QTextCursor::StartOfLine); if (!tc.movePosition(QTextCursor::Down)) break; } tc.setPosition(ss_); tc.setPosition(se_, QTextCursor::KeepAnchor); textCode->setTextCursor(tc); } void QCodeEdit::autoIndent() { QTextCursor tc = textCode->textCursor(), stc = tc; tc.movePosition(QTextCursor::StartOfLine); if (!tc.movePosition(QTextCursor::Up)) return; tc.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor); QString line = tc.selectedText(), tabs; int i = 0; for (; i < line.size(); ++i) if (!line[i].isSpace()) { tabs = line.left(i); break; } if (i >= line.size()) tabs = line.left(line.size() - 1); int nt = qMax(0, line.count(QChar('{')) - line.count(QChar('}'))); tabs.append(QString("\t").repeated(nt)); if (tabs.isEmpty()) return; stc.insertText(tabs); textCode->setTextCursor(stc); } void QCodeEdit::updateLines() { if (timer > 0) killTimer(timer); timer = startTimer(500); textCode->setTabStopWidth(textCode->fontMetrics().width(" ")); int lc = textCode->document()->lineCount(); if (prev_lc == lc) return; prev_lc = lc; textLines->setFixedWidth(textLines->fontMetrics().width(QString(" %1").arg(lc))); textLines->clear(); for (int i = 1; i <= lc; ++i) textLines->appendPlainText(QString("%1").arg(i)); textLines->verticalScrollBar()->setValue(textCode->verticalScrollBar()->value()); } QCodeEdit::ACList QCodeEdit::wordsCompletitionList(const QString & written) const { QCodeEdit::ACList ret; if (!written.isEmpty()) { QTextCursor tc = QTextCursor(textCode->document()->begin()), stc; QStringList acwl; tc = QTextCursor(textCode->document()->begin()); while (true) { tc = textCode->document()->find(written, tc); if (tc.isNull()) break; stc = tc; stc.movePosition(QTextCursor::Left); stc.select(QTextCursor::WordUnderCursor); if (!stc.selectedText().isEmpty() && stc.selectedText().trimmed() != written) acwl << stc.selectedText(); } acwl.removeDuplicates(); ACPair acl; acl.first = -1; foreach (const QString & s, acwl) acl.second << StringsPair("", s); ret << acl; } return ret; } void QCodeEdit::invokeAutoCompletition(bool force) { QTextCursor tc = textCode->textCursor(), stc = tc; if (tc.isNull()) { completer.hide(); return; } int line = tc.block().firstLineNumber(); if (completer.isVisible()) { if (auto_comp_pl != line) { completer.hide(); auto_comp_pl = line; return; } } QString doc = textCode->toPlainText(); auto_comp_pl = line; completer.clear(); int spos = tc.position(), cpos = spos; tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor); QStringList scope; QString written = tc.selectedText().trimmed(); //qDebug() << "\n*** invokeAutoCompletition ***"; if (written != "_" && !written.leftJustified(1)[0].isLetterOrNumber()) { written.clear(); } else { cpos = skipCWord(doc, spos); if (cpos >= 0) written = doc.mid(cpos, spos - cpos).trimmed(); } while (cpos >= 0) { cpos--; //qDebug() << "char =" << doc.mid(cpos, 1); if (doc.mid(cpos, 1) != ".") break; QChar c = doc.mid(cpos - 1, 1).leftJustified(1)[0]; int ppos = cpos; if (c == '\"' || c == ')' || c == ']') { cpos = skipRange(doc, cpos, pairChar(c), c, '\\'); //qDebug() << "range" << cpos; if (cpos < 0) break; } int npos = skipCWord(doc, cpos); if (npos < 0) break; scope.push_front(doc.mid(npos, ppos - npos)); cpos = npos; } ACList acl(autoCompletitionList(scope, written)); //qDebug() << written << scope << acl.size(); if (scope.isEmpty() && written.isEmpty() && !force) { completer.hide(); return; } acl << wordsCompletitionList(written); QFont bf(font()); bf.setBold(true); foreach (const ACPair & ac, acl) { if (ac.second.isEmpty()) continue; ACClass acc = ac_classes.value(ac.first); QTreeWidgetItem * gi = new QTreeWidgetItem(); gi->setText(0, acc.name); gi->setTextAlignment(0, Qt::AlignCenter); gi->setTextAlignment(1, Qt::AlignCenter); gi->setFont(0, bf); gi->setBackgroundColor(0, Qt::lightGray); gi->setFlags(Qt::ItemIsEnabled); completer.addTopLevelItem(gi); gi->setFirstColumnSpanned(true); foreach (const StringsPair & s, ac.second) { QTreeWidgetItem * ni = new QTreeWidgetItem(); ni->setIcon(0, acc.icon); ni->setText(0, s.first); ni->setText(1, s.second); completer.addTopLevelItem(ni); } } if (completer.topLevelItemCount() > 1) completer.setCurrentItem(completer.topLevelItem(1)); if (completer.isHidden()) completer.move(textCode->mapToGlobal(textCode->cursorRect().bottomRight())); completer.setVisible(completer.topLevelItemCount() > 0); } void QCodeEdit::commitCompletition() { if (completer.currentItem() == 0) return; if (!completer.currentItem()->flags().testFlag(Qt::ItemIsSelectable)) return; QString ins = completer.currentItem()->text(1), ret = completer.currentItem()->text(0); QTextCursor tc = textCode->textCursor(), stc = tc; tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); bool ins_br = true, shifted = false; if (!tc.selectedText().isEmpty()) { if (!tc.selectedText()[0].isLetterOrNumber() && !tc.selectedText()[0].isSpace()) { stc.movePosition(QTextCursor::Left); shifted = true; } else { tc.movePosition(QTextCursor::Left); tc.movePosition(QTextCursor::EndOfWord); tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); } if (!tc.selectedText().isEmpty()) if (tc.selectedText()[0].toLatin1() == '(') ins_br = false; } if (ins.contains("(")) ins = ins.left(ins.indexOf("(")) + "()"; if (!ins_br && ins.endsWith("()")) ins.chop(2); tc = stc; tc.select(QTextCursor::WordUnderCursor); if (!tc.selectedText().leftJustified(1)[0].isLetterOrNumber()) { tc = stc; if (shifted) tc.movePosition(QTextCursor::Right); } textCode->setTextCursor(tc); textCode->textCursor().insertText(ins); tc = textCode->textCursor(); if (ins_br) { if (ret == "void") { tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); if (tc.selectedText() != ";") { textCode->textCursor().insertText(";"); tc.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 2); } } if (ins.endsWith(")") && !completer.currentItem()->text(1).endsWith("()")) { tc.movePosition(QTextCursor::Left); textCode->setTextCursor(tc); } } else { if (completer.currentItem()->text(1).endsWith(")")) { tc.movePosition(QTextCursor::Right); textCode->setTextCursor(tc); } if (completer.currentItem()->text(1).endsWith("()")) { tc.movePosition(QTextCursor::Right); textCode->setTextCursor(tc); } } completer.hide(); } void QCodeEdit::textEdit_cursorPositionChanged() { es_line.cursor = textCode->textCursor(); es_line.cursor.select(QTextCursor::LineUnderCursor); es_line.cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); applyExtraSelection(); } void QCodeEdit::textEdit_textChanged() { updateLines(); } void QCodeEdit::textEdit_selectionChanged() { es_selected.clear(); QString sf = textCode->textCursor().selectedText(); if (sf.trimmed().isEmpty() || sf.contains("\n")) { applyExtraSelection(); return; } QTextCursor tc(textCode->document()->begin()); QTextEdit::ExtraSelection es; es.format.setBackground(QColor(251, 250, 150)); while (true) { tc = textCode->document()->find(sf, tc, QTextDocument::FindCaseSensitively | QTextDocument::FindWholeWords); if (tc.isNull()) break; es.cursor = tc; es_selected << es; } applyExtraSelection(); } void QCodeEdit::setShowSpaces(bool yes) { spaces_ = yes; QTextOption to = textCode->document()->defaultTextOption(); to.setFlags(yes ? QTextOption::ShowTabsAndSpaces : (QTextOption::Flags)0); textCode->document()->setDefaultTextOption(to); }