Exemple #1
0
QString QueryPanel::getActiveStatement(int block, int col) {

    int from = 0, to = -1;
    State st;

    QTextBlock b = editor->document()->findBlockByNumber(block);
    int scol = col;
    while(b.isValid()) {
        st.opaque = b.userState();
        if(st.s.col != -1 && st.s.col < scol) {
            from = b.position() + st.s.col + 1;
            break;
        }
        scol = INT_MAX;
        b = b.previous();
    }

    b = editor->document()->findBlockByNumber(block);
    scol = col;
    while(b.isValid()) {
        st.opaque = b.userState();
        if(st.s.col != -1 && st.s.col >= scol) {
            to = b.position() + st.s.col;
            break;
        }
        scol = 0;
        b = b.next();
    }

    QString all = editor->document()->toPlainText();
    if(to < 0)
        to = all.length();
    return all.mid(from,to);;
}
void DevHighlighter::reformatBlocks(int from, int charsRemoved, int charsAdded)
{
	QTextBlock block = doc->findBlock(from);
	if (!block.isValid())
		return;

	QTextBlock endBlock;
	if (charsAdded > charsRemoved || charsAdded == charsRemoved)
		endBlock = doc->findBlock(from + charsAdded);
	else
		endBlock = block;

	bool forceHighlightOfNextBlock = false;

	while (block.isValid() && (!(endBlock < block) || forceHighlightOfNextBlock) )
	{
		const int stateBeforeHighlight = block.userState();

		reformatBlock(block);

		forceHighlightOfNextBlock = (block.userState() != stateBeforeHighlight);

		block = block.next();
	}

	formatChanges.clear();
}
Exemple #3
0
void QSyntaxHighlighterPrivate::_q_reformatBlocks(int from, int charsRemoved, int charsAdded)
{
    Q_UNUSED(charsRemoved);
    rehighlightPending = false;

    QTextBlock block = doc->findBlock(from);
    if (!block.isValid())
        return;

    int endPosition;
    QTextBlock lastBlock = doc->findBlock(from + charsAdded);
    if (lastBlock.isValid())
        endPosition = lastBlock.position() + lastBlock.length();
    else
        endPosition = doc->docHandle()->length();

    bool forceHighlightOfNextBlock = false;

    while (block.isValid() && (block.position() < endPosition || forceHighlightOfNextBlock)) {
        const int stateBeforeHighlight = block.userState();

        reformatBlock(block);

        forceHighlightOfNextBlock = (block.userState() != stateBeforeHighlight);

        block = block.next();
    }

    formatChanges.clear();
}
Exemple #4
0
void Indenter::indentBlock(const QTextBlock &block,
                           const QChar &,
                           const TextEditor::TabSettings &settings,
                           int)
{
    int indent;

    QTextBlock previous = block.previous();
    // Previous line ends on comma, ignore everything and follow the indent
    if (previous.text().endsWith(',')) {
        indent = previous.text().indexOf(QRegularExpression("\\S")) / settings.m_indentSize;
    } else {
        // Use the stored indent plus some bizarre heuristics that even myself remember how it works.
        indent = block.userState() >> 20;
        if (indent < 0) {
            while (indent == -1 && previous.isValid()) {
                indent = previous.userState() >> 20;
                previous = previous.previous();
            }
        }

        if (didBlockStart(block) && indent > 0)
            indent--;
    }

    settings.indentLine(block, indent  * settings.m_indentSize);
}
// Reset the header state of a here-doc to 7
// and the state of its body to 6.
void Highlighter::resetHereDocStates (QTextBlock block)
{
    if (block.userState() == hereDocTempState)
    {
        block.setUserState (hereDocHeaderState);
        block = block.next();
        while (block.isValid() && block.userState() != 0)
        {
            block.setUserState (hereDocBodyState);
            block = block.next();
        }
    }
}
Exemple #6
0
int BaseTextDocumentLayout::braceDepth(const QTextBlock &block)
{
    int state = block.userState();
    if (state == -1)
        return 0;
    return state >> 8;
}
void ScriptFormatter::enforceFormatting( QQuickTextDocument* document ) { //The script doesn't quite look right when loaded from a file, so we call this function.
	
	if( document != nullptr && document != NULL ) {
		for( QTextBlock block = document->textDocument()->firstBlock(); block != document->textDocument()->end(); block = block.next() ) {
			setParagraphType( document, ( ScriptFormatter::paragraphType ) block.userState(), block.position() );
		}
	}
}
Exemple #8
0
void BaseTextDocumentLayout::setBraceDepth(QTextBlock &block, int depth)
{
    int state = block.userState();
    if (state == -1)
        state = 0;
    state = state & 0xff;
    block.setUserState((depth << 8) | state);
}
int QTextCopyHelper::appendFragment(int pos, int endPos, int objectIndex)
{
    QTextDocumentPrivate::FragmentIterator fragIt = src->find(pos);
    const QTextFragmentData * const frag = fragIt.value();

    Q_ASSERT(objectIndex == -1
             || (frag->size_array[0] == 1 && src->formatCollection()->format(frag->format).objectIndex() != -1));

    int charFormatIndex;
    if (forceCharFormat)
       charFormatIndex = primaryCharFormatIndex;
    else
       charFormatIndex = convertFormatIndex(frag->format, objectIndex);

    const int inFragmentOffset = qMax(0, pos - fragIt.position());
    int charsToCopy = qMin(int(frag->size_array[0] - inFragmentOffset), endPos - pos);

    QTextBlock nextBlock = src->blocksFind(pos + 1);

    int blockIdx = -2;
    if (nextBlock.position() == pos + 1) {
        blockIdx = convertFormatIndex(nextBlock.blockFormat());
    } else if (pos == 0 && insertPos == 0) {
        dst->setBlockFormat(dst->blocksBegin(), dst->blocksBegin(), convertFormat(src->blocksBegin().blockFormat()).toBlockFormat());
        dst->setCharFormat(-1, 1, convertFormat(src->blocksBegin().charFormat()).toCharFormat());
    }

    QString txtToInsert(originalText.constData() + frag->stringPosition + inFragmentOffset, charsToCopy);
    if (txtToInsert.length() == 1
        && (txtToInsert.at(0) == QChar::ParagraphSeparator
            || txtToInsert.at(0) == QTextBeginningOfFrame
            || txtToInsert.at(0) == QTextEndOfFrame
           )
       ) {
        dst->insertBlock(txtToInsert.at(0), insertPos, blockIdx, charFormatIndex);
        ++insertPos;
    } else {
        if (nextBlock.textList()) {
            QTextBlock dstBlock = dst->blocksFind(insertPos);
            if (!dstBlock.textList()) {
                // insert a new text block with the block and char format from the
                // source block to make sure that the following text fragments
                // end up in a list as they should
                int listBlockFormatIndex = convertFormatIndex(nextBlock.blockFormat());
                int listCharFormatIndex = convertFormatIndex(nextBlock.charFormat());
                dst->insertBlock(insertPos, listBlockFormatIndex, listCharFormatIndex);
                ++insertPos;
            }
        }
        dst->insert(insertPos, txtToInsert, charFormatIndex);
        const int userState = nextBlock.userState();
        if (userState != -1)
            dst->blocksFind(insertPos).setUserState(userState);
        insertPos += txtToInsert.length();
    }

    return charsToCopy;
}
void AssistInterface::prepareForAsyncUse()
{
    m_text = m_textDocument->toPlainText();
    m_userStates.reserve(m_textDocument->blockCount());
    for (QTextBlock block = m_textDocument->firstBlock(); block.isValid(); block = block.next())
        m_userStates.append(block.userState());
    m_textDocument = 0;
    m_isAsync = true;
}
Exemple #11
0
void TextEditor::pcChanged(ParseNode *pc, bool justRolledBack) {
   ParseNode *old = m_pc;
//   cerr << "\tpcChanged id:" << QThread::currentThreadId() << "\n";
   
   if (old == pc)
      return;
   
   m_pc = pc;
//   if (m_program->getStatus() != PAUSED)
//      return;
   
   if (old != NULL) {
      QTextBlock *b = old->getTextBlock();
      int state = b->userState();
      if (state > 0)
         b->setUserState(state & ~B_CURRENT_PC);
   }

   if (m_pc != NULL) {
      QTextBlock *b = m_pc->getTextBlock();

//      cerr << "b: " << b->text().toStdString() << endl;
      int state = b->userState();
      if (state < 0)
         b->setUserState(B_CURRENT_PC);
      else b->setUserState(state | B_CURRENT_PC);
      
      if (!justRolledBack && b != NULL) {
         QTextCursor c = textCursor();

         c.setPosition(b->position());
         setTextCursor(c);
         ensureCursorVisible();
      }
   }
   
   m_parent->updateLineNumbers(0);
   // the 2 can be changed according to preferences later
   // just be sure to also change the fading factors in paintEvent.
   m_program->getLastXInstructions(Options::noPreviousXInstructions(), m_lastInstructions);
   viewport()->update();
}
int ExpressionUnderCursor::previousBlockState(const QTextBlock &block)
{
    const QTextBlock prevBlock = block.previous();
    if (prevBlock.isValid()) {
        int state = prevBlock.userState();

        if (state != -1)
            return state;
    }
    return 0;
}
/*
    Returns true if the start of the bottom line of yyProgram (and
    potentially the whole line) is part of a C-style comment;
    otherwise returns false.
*/
bool LineInfo::bottomLineStartsInMultilineComment()
{
    QTextBlock currentLine = yyProgram.lastBlock().previous();
    QTextBlock previousLine = currentLine.previous();

    int startState = qMax(0, previousLine.userState()) & 0xff;
    if (startState > 0)
        return true;

    return false;
}
/**
 * Parses a text document and builds the navigation tree for it
 */
void NavigationWidget::parse(QTextDocument *document) {
    const QSignalBlocker blocker(this);
    Q_UNUSED(blocker);

    setDocument(document);
    clear();
    _lastHeadingItemList.clear();

    for (int i = 0; i < document->blockCount(); i++) {
        QTextBlock block = document->findBlockByNumber(i);
        int elementType = block.userState();

        // ignore all non headline types
        if ((elementType < pmh_H1) || (elementType > pmh_H6)) {
            continue;
        }

        QString text = block.text();

        text.remove(QRegularExpression("^#+"))
                .remove(QRegularExpression("#+$"))
                .remove(QRegularExpression("^\\s+"))
                .remove(QRegularExpression("^=+$"))
                .remove(QRegularExpression("^-+$"));

        if (text.isEmpty()) {
            continue;
        }

        QTreeWidgetItem *item = new QTreeWidgetItem();
        item->setText(0, text);
        item->setData(0, Qt::UserRole, block.position());
        item->setToolTip(0, tr("headline %1").arg(elementType - pmh_H1 + 1));

        // attempt to find a suitable parent item for the element type
        QTreeWidgetItem *lastHigherItem = findSuitableParentItem(elementType);

        if (lastHigherItem == NULL) {
            // if there wasn't a last higher level item then add the current
            // item to the top level
            addTopLevelItem(item);
        } else {
            // if there was a last higher level item then add the current
            // item as child of that item
            lastHigherItem->addChild(item);
        }

        _lastHeadingItemList[elementType] = item;
    }

    expandAll();
}
int BackwardsScanner::previousBlockState(const QTextBlock &block)
{
    const QTextBlock prevBlock = block.previous();

    if (prevBlock.isValid()) {
        int state = prevBlock.userState();

        if (state != -1)
            return state;
    }

    return 0;
}
Exemple #16
0
void CodeEditor::foldUnfold(QTextBlock& block)
{
    int state = block.userState();

    if (state & Error || state & End || !(state & Begin) || // (state & End) для однострочного блока ()
        document()->lastBlock() == block)
        return;

    bool unfolding = state & Folded;

    if (unfolding)
        block.setUserState(block.userState() & ~Folded);
    else
        block.setUserState(block.userState() | Folded);

    int previousBlockState = block.previous().userState();
    int endBraceDepth = previousBlockState & Error ? 0 : previousBlockState >> StateShift;

    int braceDepth;
    int skipDepth = 0;

    while ((block = block.next()).isValid()) {
        int state = block.userState();
        braceDepth = state >> StateShift;

        if (unfolding) {

            if (state & Begin && !skipDepth && state & Folded) {
                skipDepth = block.previous().userState() >> StateShift;
            } else if (skipDepth) {

                if (braceDepth == skipDepth)
                    skipDepth = 0;

                continue;
            }
        }
Exemple #17
0
void CodeEditor::paintEvent(QPaintEvent* event)
{
    QPlainTextEdit::paintEvent(event);

    QPainter painter(viewport());
    painter.setPen(Qt::darkGray);

    QTextBlock block = firstVisibleBlock();

    QRectF rect;

    do {

        if (!block.isVisible())
            continue;

        rect = blockBoundingGeometry(block).translated(contentOffset());

        QTextLine line = block.layout()->lineAt(0);

        if (config->whitespaces) {
            QString txt = block.text();

            for (int i = 0; i < txt.length(); i++) {
                // rect.x() <- учитывая горизонтальный скролинг
                QPoint point(rect.x() + line.cursorToX(i), rect.y() + line.ascent());

                if (txt[i] == ' ')
                    painter.drawText(point, QChar(0x00b7));
                else if (txt[i] == '\t')
                    painter.drawText(point, QChar(0x21b9));
            }
        }

        int state = block.userState();

        if (!(state & Error) && state & Folded) {
            QRect collapseRect(rect.x() + line.rect().x() + line.naturalTextWidth() + FONTWIDTH * 2,
                               rect.y() + 2, FONTWIDTH * 6, line.height() - 4);

            painter.drawText(collapseRect, Qt::AlignCenter, state & Comment ? "...;" : "...)");
            painter.drawRoundedRect(collapseRect, 4, 6);
        }

    } while ((block = block.next()).isValid() && rect.y() < viewport()->height());
}
Exemple #18
0
void CodeEditor::mouseMoveEvent(QMouseEvent* event)
{
    QTextBlock block = findBlockByY(event->pos().y());

    QRect collapseRect;

    if (block.isValid()) {
        QRectF    rect = blockBoundingGeometry(block).translated(contentOffset());
        QTextLine line = block.layout()->lineAt(0);

        collapseRect = QRect(rect.x() + line.rect().x() + line.naturalTextWidth() + FONTWIDTH * 2,
                             rect.y() + 2, FONTWIDTH * 6, line.height() - 4);
    }

    int state = block.userState();

    if (!(state & Error) && state & Folded && collapseRect.contains(event->pos())) {
        pointedBlock = block;

        viewport()->setCursor(Qt::PointingHandCursor);

        QString str;

        while ((block = block.next()).isValid() && !block.isVisible()) {

            if (str.count() > 1)
                str += "\n";

            if (block.blockNumber() - pointedBlock.blockNumber() > 50) {
                str += "..."; // "\n...";
                break;
            }

            str += block.text();
        }

        QToolTip::showText(event->globalPos(), str, this);
    } else {
        pointedBlock = QTextBlock();
        viewport()->setCursor(Qt::IBeamCursor);
    }

    QPlainTextEdit::mouseMoveEvent(event);
}
bool QssCompletionAssistProcessor::isInComment() const
{
    QTextBlock block = m_interface->textDocument()->findBlock(m_interface->position());
    QTextBlock prevBlock = block.previous();
    QList<Token> tokenList;
    Lexer lexer;
    lexer.setScanComments(true);
    if (prevBlock.isValid())
        lexer.setState(qssLexerState(prevBlock.userState()));
    tokenList = lexer.scanMore(block.text());
    int index = m_interface->position() - block.position();
    Q_FOREACH (const Token &t, tokenList) {
        if (t.is(Token::Comment) && index >= t.begin() && index < t.end()) {
            qDebug() << "InComment";
            return true;
        }
    }
    if (index == block.length() && (lexer.state() & Lexer::MultiLineComment)) {
        qDebug() << "InComment";
        return true;
    }
    return false;
}
IAssistProposal *QssCompletionAssistProcessor::perform(const IAssistInterface *interface)
{
    m_interface.reset(interface);

    if (isInComment())
        return 0;

    if (interface->reason() == IdleEditor && !acceptsIdleEditor())
        return 0;

    if (m_startPosition == -1)
        m_startPosition = findStartOfName();

    QTextBlock block = interface->textDocument()->findBlock(interface->position());
    QTextBlock prevBlock = block.previous();
    Lexer lexer;
    Parser parser;
    if (prevBlock.isValid()) {
        lexer.setState(qssLexerState(prevBlock.userState()));
        parser.setState(qssParserState(prevBlock.userState()));
    }
    QList<Token> tokenList = lexer.scanMore(block.text());
    int index = m_startPosition - block.position();
    Q_FOREACH (const Token &t, tokenList) {
        if (index <= t.begin())
            break;
        parser.parseMore(t);
    }
    QStringList keywords;
    QIcon icon;
    switch (parser.state()) {
    case Parser::ObjectState:
        keywords << Lexer::objects();
        icon = QIcon(":/qsseditor/images/class.png");
        break;
    case Parser::PseudoStatesState:
        keywords << Lexer::pseudoStates();
        icon = QIcon(":/qsseditor/images/func.png");
        break;
    case Parser::SubControlState:
        keywords << Lexer::subControls();
        icon = QIcon(":/qsseditor/images/func.png");
        break;
    case Parser::AttributeNameState:
        keywords << Lexer::attributeNames();
        icon = QIcon(":/qsseditor/images/var.png");
        break;
    case Parser::AttributeBodyState:
        keywords << Lexer::attributeCtors() << Lexer::attributeKeywords();
        icon = QIcon(":/qsseditor/images/keyword.png");
        break;
    default:
        ;
    }
    keywords.removeDuplicates();
    QList<TextEditor::BasicProposalItem *> items;
    for (int i = 0; i < keywords.count(); i++) {
        BasicProposalItem *item = new QssAssistProposalItem;
        item->setText(keywords[i]);
        item->setIcon(icon);
        items.append(item);
    }
    return new GenericProposal(m_startPosition, new QssAssistProposalModel(items));
}
// Changing of the start delimiter of a "here documnet" doesn't invoke
// highlightBlock() for the rest of it, hence the need for this slot.
// I don't like its complex logic but it works.
void Highlighter::docChanged (int pos, int, int)
{
    QTextBlock block = qobject_cast< QTextDocument *>(parent())->findBlock (pos);
    TextBlockData *data = static_cast<TextBlockData *>(block.userData());
    /* at start or end (state = 7 or 0 or < 6),
       or inside but previously at end (state = 6),
       or outside but previously at start (state = 0 or < 6):
       these are all states that we need to check */
    if (data->isdelimiter())
    {
        /*******************************************************************
         * It's important to know that this method is always called after  *
         * highlightBlock. There are three possibilities: state = 0, 6, 7. *
         * Other values are, like 0, related to a block outside here-docs. *
         *******************************************************************/

        /* when we're inside a here-doc, go up to its header */
        if (block.userState() == hereDocBodyState)
        {
            while (block.isValid())
            {
                block = block.previous();
                if (block.userState() == hereDocHeaderState)
                    break;
            }
        }

        /* when we're before, after or at end of a here-doc... */
        if (block.userState() != hereDocHeaderState)
        {
            /* ... the header state of the next here-doc should be 7;
               so, go to it and then do as for state 7 below */
            block = block.next();
            while (block.isValid() && block.userState() != hereDocHeaderState)
                block = block.next();
        }

        /* when this is a header (state = 7)... */
        if (block.isValid())
        {
            /* ... change the header state to 9 for this
               here-doc to be rehighlighted completely
               (for the highlighting downward 'wave' to go through it) */
            delimState = hereDocTempState;
            rehighlightBlock (block);
            /* then reset its block states... */
            resetHereDocStates (block);
            /* ... and also reset the global header state */
            delimState = hereDocHeaderState;
        }
        /* now, the header states of some here-docs
           below this one may be 9; so, reset them */
        block = block.next();
        while (block.isValid())
        {
            while (block.isValid() && block.userState() != hereDocTempState)
                block = block.next();
            if (block.isValid())
            {
                resetHereDocStates (block);
                block = block.next();
            }
        }
    }
}
Exemple #22
0
void CodeEditor::contentsChange(int pos, int, int)
{
    QTextBlock block = textCursor().block();

    // сдвиг блока клавишей Return
    // состояние предыдущего блока может быть не верным
    if (block.userState() == Empty)
        block.setUserState(block.previous().userState() | Rehighligh);

    block = document()->findBlock(pos);

    int startBlockNum = block.blockNumber();

    bool forceUnfold = false;

    while (block.isValid()) {
        int previousState = block.userState();
        int state = setBlockState(block);

        if (!(previousState & Error) && !(state & Error) &&
            previousState & Comment  && state & Comment) {

            QTextBlock next = block.next();

            int nextBlockState = next.userState();
            setBlockState(next);
            next.setUserState(nextBlockState); // в начальное состояние

            // правильное состояние комментария известно
            // только после обработки последующей строки
            state = block.userState();
        }

        if (state != previousState) {

            if (!forceUnfold) { // разворачиваем предыдущие блоки
                QTextBlock previous = block.previous();

                while (previous.isValid()) {
                    int state = previous.userState();

                    if (!(state & Error) && state & Folded)
                        previous.setUserState(state & ~Folded);

                    if (state & Error || !(state & Nested) || previous.isVisible())
                        break;

                    previous.setVisible(true);
                    previous = previous.previous();
                }
            }

            forceUnfold = true;
        } else if (block.blockNumber() > startBlockNum && // не начальный блок
                   state & Begin && !(state & Nested)) {  // (state & Begin ...) пропускаем End главного блока
          break;                                          // без state & Error, иначе срабатывает между блоками
        }                                                 // при первом обновлении

        if (forceUnfold) { // разворачиваем последующие блоки

            if (!(state & Error) && state & Folded)
                state &= ~Folded;

            block.setVisible(true);
        }

        block.setUserState(state | Rehighligh);

        block = block.next();
    }
}
Exemple #23
0
int CodeEditor::setBlockState(QTextBlock& block)
{
    int previousBlockState = block.previous().userState();

    if (previousBlockState & Error)
        previousBlockState = 0;

    bool inString = previousBlockState & String;

    int previousBraceDepth = previousBlockState >> StateShift;

    int braceDepth = previousBraceDepth;

    QString txt = block.text();

    int state = 0;
    int i     = 0;

    while (txt[i].isSpace()) ++i;

    if (txt[i] == ';') {

        if (!previousBraceDepth || previousBlockState & Comment) {
            state |= Comment; // только за предалами блока кода

            if (previousBlockState & Comment) {

                if (braceDepth) {
                    braceDepth--;
                } else {
                    previousBraceDepth = 1;

                    previousBlockState = (previousBlockState & End ? Nested : Begin) |
                                         (previousBlockState & Folded) |
                                         (previousBlockState & Rehighligh);

                    previousBlockState |= (previousBraceDepth << StateShift) | Comment;

                    block.previous().setUserState(previousBlockState);
                }

                state |= End;
            }
        }

    } else {
        // коррекция блока после удаления строки комментария
        if (previousBlockState & Comment && previousBlockState & (Nested | Begin)) {
            previousBraceDepth = 0;
            braceDepth = 0;

            previousBlockState  = previousBlockState & Nested ? End : 0;
            previousBlockState |= (previousBraceDepth << StateShift) | Comment;

            block.previous().setUserState(previousBlockState);
        }

        if (txt[i].isNull() && !previousBraceDepth) {      // пустая строка
            //qDebug() << "*** Error #1 'empty string'";
            state = Empty;
        } else if (txt[i] != '(' && !previousBraceDepth) { // начальный символ вне блока не '(' или ';'
            //qDebug() << "*** Error #2 'bad begin'";
            braceDepth = i; // позиция начала ошибки
            state |= Error;
        } else {
            while (i < txt.length()) {

                if (txt[i] == '"' && !(i && txt[i - 1] == '\\')) {
                    inString = !inString;
                } else if (!inString) {

                    if (txt[i] == ';') // комментарий в блоке кода
                        break;

                    if (txt[i] == '(')
                        braceDepth++;
                    else if (txt[i] == ')')
                        braceDepth--;

                    if (braceDepth == -1) {
                        //qDebug() << "*** Error #3 ') mismatch'";
                        braceDepth = i;
                        state |= Error;
                        break;
                    }
                }

                i++;
            } // while
        }
    }

    if (!(state & (Error | Comment))) {

        if (inString)
            state |= String;

        if (braceDepth > previousBraceDepth || !previousBraceDepth)
            state |= Begin;

        if (braceDepth < previousBraceDepth || !braceDepth)
            state |= End;

        if (previousBraceDepth && braceDepth)
            state |= Nested;
    }

    state |= (braceDepth << StateShift);

    int previousState = block.userState();

    if (previousState != Empty)
        state |= (previousState & Folded) | (previousState & Rehighligh);

//    qDebug("Block[%d]\n"
//           "\tDepth %d/%d State %d/%d New %d",
//           block.blockNumber(),
//           braceDepth, previousBraceDepth,
//           state,      block.userState(),
//           (bool)(previousState != state));

//    if (state & Error)
//        qDebug("\tError position %d", braceDepth);
//    else
//        qDebug("\tEnd:%d Begin:%d String:%d Comment:%d Nested:%d Folded:%d",
//               (bool)(state & End),    (bool)(state & Begin),
//               (bool)(state & String), (bool)(state & Comment),
//               (bool)(state & Nested), (bool)(state & Folded));

//    if (previousState & Error)
//        qDebug("\t[P] Error position %d", braceDepth);
//    else
//        qDebug("\t[P] End:%d Begin:%d String:%d Comment:%d Nested:%d Folded:%d",
//               (bool)(previousState & End),    (bool)(previousState & Begin),
//               (bool)(previousState & String), (bool)(previousState & Comment),
//               (bool)(previousState & Nested), (bool)(previousState & Folded));

    block.setUserState(state);

    return state;
}
Exemple #24
0
void CodeEditor::extraAreaPaintEvent()
{
    QTextBlock block = firstVisibleBlock();

    QPainter painter(extraArea);
    QPen 	 pen  = painter.pen();
    QFont 	 font = painter.font();
    bool 	 bold = font.bold();

    int y  = 0;
    int cx = lineNumWidth + foldBoxIndent + foldBoxWidth / 2;  // центр маркера блока по x

    do {
        if (!block.isVisible())
            continue;

        QRectF rect = blockBoundingGeometry(block);

        y = rect.translated(contentOffset()).y();

        if (block == textCursor().block()) {
            painter.setPen(Qt::yellow);
            font.setBold(!bold);
        } else {
            font.setBold(bold);
        }

        painter.setFont(font);
        painter.drawText(0, y, lineNumWidth, fontMetrics().height(), Qt::AlignRight,
                         QString::number(block.blockNumber() + 1)); // номер строки

        painter.setPen(pen);

        int state = block.userState();

        int cy    = y + fontMetrics().height() / 2; // центр маркера по Y

        if (!(state & Error) && !(state & Begin && state & End && !(state & Nested))) {

            if (state & Begin) {

                if (state & Comment)
                    painter.drawEllipse(FOLDBOXRECT(cy));
                else
                    painter.drawRoundedRect(FOLDBOXRECT(cy), 7, 3);

                if (!(!(state & Nested) && state & Folded))
                    painter.drawLine(cx, cy + foldBoxWidth / 2, cx, y + rect.height());  // края маркера вниз

                if (state & Nested)
                    painter.drawLine(cx, y, cx, cy - foldBoxWidth / 2);                  // края маркера вверх

                painter.drawLine(cx - foldBoxLength, cy, cx + foldBoxLength, cy);        // горизонтальная линия внутри маркера

                if (state & Folded)
                    painter.drawLine(cx, cy - foldBoxLength, cx, cy + foldBoxLength);    // вертикальная линия внутри маркера

            } else if (state & End) {
                painter.drawLine(cx, cy, cx + foldBoxLength, cy);                        // от центра вправо

                if (state & Nested)
                    painter.drawLine(cx, y, cx, y + rect.height());                      // вертикальная линия
                else
                    painter.drawLine(cx, y, cx, cy);                                     // от центра вверх

            } else if (state & Nested) {
                painter.drawLine(cx, y, cx, y + rect.height());                          // вертикальная линия
            }
        }

        // в paintEvent не работает
        if (state != Empty && state & Rehighligh) {
            highlighter->rehighlightBlock(block);
            block.setUserState(state & ~Rehighligh);
        }

    } while ((block = block.next()).isValid() && y < viewport()->height());
}
Exemple #25
0
void VMdEditor::updateHeaders(const QVector<VElementRegion> &p_headerRegions)
{
    QTextDocument *doc = document();

    QVector<VTableOfContentItem> headers;
    QVector<int> headerBlockNumbers;
    QVector<QString> headerSequences;
    if (!p_headerRegions.isEmpty()) {
        headers.reserve(p_headerRegions.size());
        headerBlockNumbers.reserve(p_headerRegions.size());
        headerSequences.reserve(p_headerRegions.size());
    }

    // Assume that each block contains only one line
    // Only support # syntax for now
    QRegExp headerReg(VUtils::c_headerRegExp);
    int baseLevel = -1;
    for (auto const & reg : p_headerRegions) {
        QTextBlock block = doc->findBlock(reg.m_startPos);
        if (!block.isValid()) {
            continue;
        }

        if (!block.contains(reg.m_endPos - 1)) {
            qWarning() << "header accross multiple blocks, starting from block"
                       << block.blockNumber()
                       << block.text();
        }

        if ((block.userState() == HighlightBlockState::Normal)
            && headerReg.exactMatch(block.text())) {
            int level = headerReg.cap(1).length();
            VTableOfContentItem header(headerReg.cap(2).trimmed(),
                                       level,
                                       block.blockNumber(),
                                       headers.size());
            headers.append(header);
            headerBlockNumbers.append(block.blockNumber());
            headerSequences.append(headerReg.cap(3));

            if (baseLevel == -1) {
                baseLevel = level;
            } else if (baseLevel > level) {
                baseLevel = level;
            }
        }
    }

    m_headers.clear();

    bool autoSequence = m_config.m_enableHeadingSequence
                        && !isReadOnly()
                        && m_file->isModifiable();
    int headingSequenceBaseLevel = g_config->getHeadingSequenceBaseLevel();
    if (headingSequenceBaseLevel < 1 || headingSequenceBaseLevel > 6) {
        headingSequenceBaseLevel = 1;
    }

    QVector<int> seqs(7, 0);
    QRegExp preReg(VUtils::c_headerPrefixRegExp);
    int curLevel = baseLevel - 1;
    for (int i = 0; i < headers.size(); ++i) {
        VTableOfContentItem &item = headers[i];
        while (item.m_level > curLevel + 1) {
            curLevel += 1;

            // Insert empty level which is an invalid header.
            m_headers.append(VTableOfContentItem(c_emptyHeaderName,
                                                 curLevel,
                                                 -1,
                                                 m_headers.size()));
            if (autoSequence) {
                addHeaderSequence(seqs, curLevel, headingSequenceBaseLevel);
            }
        }

        item.m_index = m_headers.size();
        m_headers.append(item);
        curLevel = item.m_level;
        if (autoSequence) {
            addHeaderSequence(seqs, item.m_level, headingSequenceBaseLevel);

            QString seqStr = headerSequenceStr(seqs);
            if (headerSequences[i] != seqStr) {
                // Insert correct sequence.
                insertSequenceToHeader(doc->findBlockByNumber(headerBlockNumbers[i]),
                                       headerReg,
                                       preReg,
                                       seqStr);
            }
        }
    }

    emit headersChanged(m_headers);

    updateCurrentHeader();
}