void qceEqual(const QDocumentCursor& c, const QDocumentCursor& expected, const QString& message){ QEQUAL2(c.hasSelection(),expected.hasSelection(), " got-total: "+cur2str(c)+" expected-total: "+cur2str(expected)+" more: "+message); QEQUAL2(c.anchorLineNumber(),expected.anchorLineNumber(), " got-total: "+cur2str(c)+" expected-total: "+cur2str(expected)+" more: "+message); QEQUAL2(c.anchorColumnNumber(),expected.anchorColumnNumber(), " got-total: "+cur2str(c)+" expected-total: "+cur2str(expected)+" more: "+message); QEQUAL2(c.lineNumber(),expected.lineNumber(), " got-total: "+cur2str(c)+" expected-total: "+cur2str(expected)+" more: "+message); QEQUAL2(c.columnNumber(),expected.columnNumber(), " got-total: "+cur2str(c)+" expected-total: "+cur2str(expected)+" more: "+message); }
/*! \brief Completion callback */ void QCodeCompletionEngine::complete(const QDocumentCursor& c, const QString& trigger) { #ifdef _QCODE_MODEL_ // TODO : // * use a more efficient design by avoiding deep copy of the data // * only lex the requested part (stop at cursor or topmost frame required for proper class hierarchy) QDocumentCursor cc = c; cc.movePosition(1, QDocumentCursor::Start, QDocumentCursor::KeepAnchor); //qDebug("%s", qPrintable(cc.selectedText())); QCodeBuffer buffer(cc.selectedText()); //QCodeBuffer buffer(c.document()->text()); complete(&buffer, trigger); #else // remove unused argument warnings (void) c; (void) trigger; qWarning("From complete(QDocumentCursor, QString)"); qWarning("QCodeCompletionEngine is not self-sufficient : subclasses should " "reimplement at least on of the complete() method..."); #endif }
//tests if folded text can be edited void QEditorTest::activeFolding(){ QFETCH(QString, editorText); QFETCH(QList<int>, foldAt); QFETCH(QList<int>, hiddenLines); QFETCH(int, cursorAL); QFETCH(int, cursorAC); QFETCH(int, cursorL); QFETCH(int, cursorC); QFETCH(QString, textToInsert); QFETCH(QString, newEditorText); QFETCH(QList<int>, newHiddenLines); editor->setText(editorText, false); foreach(const int &i, foldAt) editor->document()->collapse(i); for (int i=0;i<editor->document()->lines();i++) QVERIFY2(editor->document()->line(i).isHidden() == hiddenLines.contains(i),qPrintable(QString::number(i))); compareLists(editor->document()->impl()->testGetHiddenLines(), hiddenLines); QDocumentCursor editCursor = editor->document()->cursor(cursorAL,cursorAC,cursorL,cursorC); editCursor.insertText(textToInsert); QEQUAL(editor->document()->text(), newEditorText); for (int i=0;i<editor->document()->lines();i++) QVERIFY2(editor->document()->line(i).isHidden() == newHiddenLines.contains(i),qPrintable(QString::number(i))); compareLists(editor->document()->impl()->testGetHiddenLines(), newHiddenLines); }
/*! \internal */ bool QCodeCompletionEngine::eventFilter(QObject *o, QEvent *e) { if ( !e || !o || (e->type() != QEvent::KeyPress) || (o != pEdit) ) return false; //qDebug("should trigger completion?"); QDocumentCursor cur = editor()->cursor(); QKeyEvent *k = static_cast<QKeyEvent*>(e); QString s, txt = s = k->text(); int count = txt.count(); if ( txt.isEmpty() || m_triggers.isEmpty() ) return false; // QThread::eventFilter(o, e); //qDebug("should trigger completion? (bis)"); if ( count > m_max ) { txt = txt.right(m_max); } else if ( count < m_max ) { QDocumentCursor c(cur); c.movePosition(m_max - count, QDocumentCursor::Left, QDocumentCursor::KeepAnchor); //qDebug("prev text : %s", qPrintable(c.selectedText())); txt.prepend(c.selectedText()); } //qDebug("text : %s", qPrintable(txt)); foreach ( QString trig, m_triggers ) { if ( txt.endsWith(trig) ) { editor()->write(s); cur = editor()->cursor(); cur.movePosition(trig.count(), QDocumentCursor::PreviousCharacter); // notify completion trigger emit completionTriggered(trig); //get rid of previous calltips/completions editor()->setFocus(); // trigger completion complete(cur, trig); return true; } } return false; }
/*! */ bool QHexPanel::paint(QPainter *p, QEditor *e) { // qWarning("drawing Hex panel... [%i, %i, %i, %i]", // geometry().x(), // geometry().y(), // geometry().width(), // geometry().height()); #if 1 //hexeditor->resize(geometry().size()); #else static QPixmap _warn(":/warning.png"), _mod(":/save.png"); QString s; int xpos = 10; QDocumentCursor c = e->cursor(); const QFontMetrics fm(fontMetrics()); const int ls = fm.lineSpacing(); const int ascent = fm.ascent() + 3; s = tr("Line : %1 Visual column : %2 Text column : %3") .arg(c.lineNumber() + 1) .arg(c.visualColumnNumber()) .arg(c.columnNumber()); p->drawText(xpos, ascent, s); xpos += fm.width(s) + 10; int sz = qMin(height(), _mod.height()); //int lastMod = d->lastModified().secsTo(QDateTime::currentDateTime()); //QString timeDiff = tr("(%1 min %2 s ago)").arg(lastMod / 60).arg(lastMod % 60); //xpos += 10; if ( e->isContentModified() ) { p->drawPixmap(xpos, (height() - sz) / 2, sz, sz, _mod); //xpos += sz; //xpos += 10; //p->drawText(xpos, ascent, timeDiff); } xpos += sz + 10; //xpos += fm.width(timeDiff); //xpos += 20; // s = editor()->flag(QEditor::Overwrite) ? tr("OVERWRITE") : tr("INSERT"); // p->drawText(xpos, ascent, s); // xpos += fm.width(s) + 10; #endif return true; }
int LatexTables::findNextToken(QDocumentCursor &cur,QStringList tokens,bool keepAnchor,bool backwards){ int pos=-1; int nextToken=-1; int offset=0; QDocumentCursor::MoveOperation mvNextLine= backwards ? QDocumentCursor::PreviousLine : QDocumentCursor::NextLine; QDocumentCursor::MoveOperation mvNextChar= backwards ? QDocumentCursor::Left : QDocumentCursor::Right; QDocumentCursor::MoveOperation mvStartOfLine= backwards ? QDocumentCursor::EndOfLine : QDocumentCursor::StartOfLine; QDocumentCursor::MoveFlag mvFlag= keepAnchor ? QDocumentCursor::KeepAnchor : QDocumentCursor::MoveAnchor; do{ QString line=cur.line().text(); if(backwards){ offset=line.length(); } line=LatexParser::cutComment(line); if(backwards){ offset=offset-line.length(); QString help; foreach(const QChar& elem,line) help.prepend(elem); line=help; } if(line.contains("\\end{")&&!backwards) { nextToken=-2; break; } if(line.contains("{nigeb\\")&&backwards) { nextToken=-2; break; } pos=-1; for(int i=0;i<tokens.count();i++){ QString elem=tokens.at(i); int colNumber= cur.columnNumber(); if(backwards) colNumber=line.length()+offset-colNumber ; int zw=line.indexOf(elem,colNumber); if(zw>-1) { if(pos>zw || pos==-1){ pos=zw; nextToken=i; } } } if(pos<0){ if(!backwards&&cur.lineNumber()>=cur.document()->lineCount()-1) break; if(backwards&&cur.lineNumber()<=0) break; cur.movePosition(1,mvNextLine,mvFlag); cur.movePosition(1,mvStartOfLine,mvFlag); } }while(pos<0); if(pos>-1) { cur.movePosition(1,mvStartOfLine,mvFlag); cur.movePosition(pos+tokens.at(nextToken).length()+offset,mvNextChar,mvFlag); } return nextToken; }
/*! */ void QStatusPanel::paint(QPainter *p, QEditor *e) { //qDebug("drawing status panel... [%i, %i, %i, %i]", // geometry().x(), // geometry().y(), // geometry().width(), // geometry().height()); static QPixmap _warn(":/warning.png"); QString s; int xpos = 10; QDocumentCursor c = e->cursor(); const QFontMetrics fm(fontMetrics()); const int ls = fm.lineSpacing(); const int ascent = fm.ascent() + 3; s = tr("Line : %1 Visual column : %2 Text column : %3") .arg(c.lineNumber() + 1) .arg(c.visualColumnNumber()) .arg(c.columnNumber()); p->drawText(xpos, ascent, s); xpos += fm.width(s) + 10; // TODO : draw icon to show mod status s = editor()->flag(QEditor::Overwrite) ? tr("OVERWRITE") : tr("INSERT"); p->drawText(xpos, ascent, s); xpos += fm.width(s) + 10; m_conflictSpot = 0; if ( editor()->isInConflict() ) { s = tr("Conflict"); int w = fm.width(s) + 30; if ( xpos + w + _warn.width() < width() ) { m_conflictSpot = width() - (w + _warn.width()); p->drawText(width() - w + 15, ascent, s); p->drawPixmap(m_conflictSpot, (ls - _warn.height()) / 2 + 2, _warn); } else if ( xpos + _warn.width() < width() ) { m_conflictSpot = width() - _warn.width(); p->drawPixmap(m_conflictSpot, (ls - _warn.height()) / 2 + 2, _warn); } } setFixedHeight(ls + 4); }
void simpleRestoreAutoOverride(const QString& written="????"){ //simple means without protecting the change from undo/redo if (!autoOverridenText.isEmpty() && !editor->isAutoOverrideText(written)) { int curpos = editor->cursor().columnNumber(); if (curpos < maxWritten) { QDocumentCursor c = editor->cursor(); c.movePosition(maxWritten-curpos, QDocumentCursor::Right); editor->setCursor(c); } editor->insertText(autoOverridenText); QDocumentCursor c = editor->cursor(); c.movePosition(autoOverridenText.length() + (curpos<maxWritten?maxWritten-curpos:0), QDocumentCursor::Left); editor->setCursor(c); editor->resizeAutoOverridenPlaceholder(c, autoOverridenText.size()); } }
void LatexTables::removeRow(QDocumentCursor &c){ QDocumentCursor cur(c); const QStringList tokens("\\\\"); if(cur.hasSelection()){ if(cur.lineNumber()>cur.anchorLineNumber()||(cur.lineNumber()==cur.anchorLineNumber() && cur.columnNumber()>cur.anchorColumnNumber())){ cur.moveTo(cur.anchorLineNumber(),cur.anchorColumnNumber()); } } int result=findNextToken(cur,tokens,false,true); if(result==0) cur.movePosition(2,QDocumentCursor::Right); if(result==-2) cur.movePosition(1,QDocumentCursor::EndOfLine); bool breakLoop=false; while(!(breakLoop=(findNextToken(cur,tokens,true)==-1)) && c.isWithinSelection(cur) ){ } if(!breakLoop) { // check if end of cursor is at line end QDocumentCursor c2(cur.document(),cur.anchorLineNumber(),cur.anchorColumnNumber()); if(c2.atLineEnd()) { c2.movePosition(1,QDocumentCursor::Right); cur.moveTo(c2,QDocumentCursor::KeepAnchor); } // remove text cur.beginEditBlock(); cur.removeSelectedText(); if(cur.line().text().isEmpty()) cur.deleteChar(); // don't leave empty lines cur.endEditBlock(); } }
/*! \brief \fn CCompletion::getLastToken \param c \return QString */ QString CCompletion::getLastToken(const QDocumentCursor &c) { QString line = c.line().text(); QString Token = c.selectedText(); if (Token.isEmpty()) { if (line.size()>1) { int i = c.columnNumber()-1; while (QString("_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").contains(line.at(i).toUpper())) { Token = line.at(i)+Token; i--; if (i<0) break; } } } return Token; }
QString LatexTables::getTableText(QDocumentCursor &cur){ int result=findNextToken(cur,QStringList(),false,true); if(result!=-2) return QString(); QString line=cur.line().text(); int i=line.indexOf("\\begin"); if(i>=0) cur.setColumnNumber(i); result=findNextToken(cur,QStringList(),true,false); if(result!=-2) return QString(); line=cur.line().text(); QRegExp rx("\\\\end\\{.*\\}"); i=rx.indexIn(line); if(i>=0) cur.setColumnNumber(i+rx.cap(0).length(),QDocumentCursor::KeepAnchor); QString res=cur.selectedText(); return res; }
/*! \brief Standard completion entry point for QEditor \param e QKeyEvent that caused a modification of the text \note This slot is only called when editing happens without any cursor mirrors */ void QCodeCompletionEngine::textEdited(QKeyEvent *k) { QString s, txt = s = k->text(); QDocumentCursor cur = editor()->cursor(); int count = txt.count(); if ( txt.isEmpty() || m_triggers.isEmpty() ) return; //qDebug("should trigger completion? (bis)"); if ( count > m_max ) { txt = txt.right(m_max); } else if ( count < m_max ) { QDocumentCursor c(cur); c.movePosition(m_max, QDocumentCursor::Left, QDocumentCursor::KeepAnchor); //qDebug("prev text : %s", qPrintable(c.selectedText())); txt = c.selectedText(); } //qDebug("text : %s", qPrintable(txt)); foreach ( QString trig, m_triggers ) { if ( txt.endsWith(trig) ) { cur = editor()->cursor(); cur.movePosition(trig.count(), QDocumentCursor::PreviousCharacter); // notify completion trigger emit completionTriggered(trig); //get rid of previous calltips/completions editor()->setFocus(); // trigger completion complete(cur, trig); } } }
bool QSnippetBinding::keyPressEvent(QKeyEvent *event, QEditor *editor) { /* if ( event->modifiers() & Qt::ControlModifier ) { for ( int i = 0; i < qMin(10, m->snippetCount()); ++i ) { if ( event->key() == (Qt::Key_F1 + i) ) { m->snippet(i)->insert(editor); return true; } } } */ if ( (event->modifiers() & Qt::AltModifier) && (event->key() == Qt::Key_Space || event->text() == " ") ) { QDocumentCursor c = editor->cursor(); //c.select(QDocumentCursor::SelectWord); if ( !c.hasSelection() ) { c.movePosition(1, QDocumentCursor::PreviousWord, QDocumentCursor::KeepAnchor); editor->setCursor(c); } QString s = c.selectedText(); for ( int i = 0; i < m_manager->snippetCount(); ++i ) { QSnippet *snip = m_manager->snippet(i); if ( snip->name() == s ) { snip->insert(editor); return true; } } } return QEditorInputBinding::keyPressEvent(event, editor); }
void LatexTables::alignTableCols(QDocumentCursor &cur){ QString text = getTableText(cur); if (!cur.hasSelection()) return; QString indentation = cur.selectionStart().line().indentation(); // split off \begin and \end parts int index = text.indexOf("\\begin{")+6; int cellsStart; QList<CommandArgument> args = getCommandOptions(text, index, &cellsStart); if (args.count() < 2) return; QString tableType = args.at(0).value; // assume alignment in second arg except for the following environments (which have it in the third one) QString alignment; if (tabularNames.contains(tableType)) { alignment = args.at(1).value; } else if (tabularNamesWithOneOption.contains(tableType)) { if (args.count()<3) alignment = ""; // incomplete definition -> fall back to defaults else alignment = args.at(2).value; } else return; // not a registered table environment int cellsEnd = text.indexOf("\\end{"+tableType); if (cellsEnd<0) return; QString beginPart = text.left(cellsStart); QString endPart = text.mid(cellsEnd); LatexTableModel ltm; ltm.setContent(text.mid(cellsStart, cellsEnd-cellsStart)); QStringList l_defs=splitColDef(alignment); simplifyColDefs(l_defs); QStringList content(ltm.getAlignedLines(l_defs)); QString result = beginPart + '\n'; for (int i=0; i<content.count(); i++) { result.append(indentation + content.at(i)); } result.append(indentation + endPart); cur.replaceSelectedText(result); }
bool LatexTables::inTableEnv(QDocumentCursor &cur){ QDocumentCursor c(cur); int result=findNextToken(c,QStringList(),false,true); if(result!=-2) return false; if(c.lineNumber()==cur.lineNumber()) return false; QString line=c.line().text(); int pos=line.indexOf("\\begin"); if(pos>-1){ QStringList values; LatexParser::resolveCommandOptions(line,pos,values); QString env=values.takeFirst(); if(!env.startsWith("{")||!env.endsWith("}")) return -1; env=env.mid(1); env.chop(1); if(tabularNames.contains(env,Qt::CaseSensitive)||tabularNamesWithOneOption.contains(env,Qt::CaseSensitive)){ int result=findNextToken(c,QStringList()); if(result!=-2) return false; if(c.lineNumber()>cur.lineNumber()) return true; } } return false; }
QString LatexTables::getDef(QDocumentCursor &cur){ QDocumentCursor c(cur); int result=findNextToken(c,QStringList(),false,true); if(result!=-2) return QString(); QString line=c.line().text(); QString opt; int pos=line.indexOf("\\begin"); if(pos>-1){ QStringList values; QList<int> starts; LatexParser::resolveCommandOptions(line,pos,values,&starts); QString env=values.takeFirst(); pos=starts.takeFirst(); if(!env.startsWith("{")||!env.endsWith("}")) return QString(); env=env.mid(1); env.chop(1); int numberOfOptions=-1; if(tabularNames.contains(env)) numberOfOptions=0; if(tabularNamesWithOneOption.contains(env)) numberOfOptions=1; if(numberOfOptions>=0){ while(!values.isEmpty()){ opt=values.takeFirst(); pos=starts.takeFirst(); if(opt.startsWith("[")&&opt.endsWith("]")) continue; if(numberOfOptions>0) { numberOfOptions--; continue; } if(!opt.startsWith("{")||!opt.endsWith("}")) return QString(); opt=opt.mid(1); opt.chop(1); cur.moveTo(c.line(),pos+1); cur.movePosition(opt.length(),QDocumentCursor::NextCharacter,QDocumentCursor::KeepAnchor); } } } return opt; }
int LatexTables::getColumn(QDocumentCursor &cur){ QDocumentCursor c(cur); QStringList tokens("\\\\"); int result=findNextToken(c,tokens,true,true); if(result==0) c.movePosition(2,QDocumentCursor::Right,QDocumentCursor::KeepAnchor); if(c.lineNumber()==cur.lineNumber() && c.selectedText().contains(QRegExp("^\\s*$"))){ c.movePosition(1,QDocumentCursor::EndOfLine,QDocumentCursor::KeepAnchor); QString zw=c.selectedText(); if(zw.contains(QRegExp("^\\s*$"))) return -1; } c.clearSelection(); tokens << "\\&" << "&"; int col=0; do{ result=findNextToken(c,tokens); if(c.lineNumber()>cur.lineNumber()|| (c.lineNumber()==cur.lineNumber() && c.columnNumber()>cur.columnNumber())) break; if(result==2) col++; }while(result>0); return col; }
QDocumentCursor CursorHistory::back(const QDocumentCursor ¤tCursor) { if (currentEntry == history.begin()) { updateNavActions(); return QDocumentCursor(); } // insert currentCursor to be able to go back if (currentCursor.isValid() && insertPos(currentCursor, false)) { currentEntry--; } CursorPosition pos(currentCursor); if (pos.isValid() && !pos.equals(*currentEntry)) { updateNavActions(); return currentPos(); } currentEntry = prevValidEntry(currentEntry); updateNavActions(); return currentPos(); }
/*! Inserts the cursor behind the current entry */ bool CursorHistory::insertPos(QDocumentCursor cur, bool deleteBehindCurrent) { if (!m_insertionEnabled) return false; if (!cur.isValid()) return false; CursorPosition pos(cur); connectUnique(pos.doc(), SIGNAL(destroyed(QObject*)), this, SLOT(documentClosed(QObject*))); // TODO destroyed() may be duplicate to aboutToDeleteDocument() - needs more testing. anyway it does not harm connectUnique(pos.doc(), SIGNAL(lineDeleted(QDocumentLineHandle*)), this, SLOT(lineDeleted(QDocumentLineHandle*))); connectUnique(pos.doc(), SIGNAL(lineRemoved(QDocumentLineHandle*)), this, SLOT(lineDeleted(QDocumentLineHandle*))); if (deleteBehindCurrent && currentEntry != history.end()) { currentEntry++; currentEntry = history.erase(currentEntry, history.end()); } if (currentEntry == history.end() && currentEntry != history.begin()) currentEntry--; // do not insert neighboring duplicates if (currentEntryValid() && (*currentEntry).equals(pos)) { updateNavActions(); return false; } CursorPosList::iterator it = prevValidEntry(currentEntry); if (it != history.end() && (*it).isValid() && (*it).equals(pos)) { updateNavActions(); return false; } if (history.count() >= m_maxLength) { if (currentEntry == history.begin()) { history.removeLast(); } else { history.removeFirst(); } } currentEntry++; history.insert(currentEntry, pos); updateNavActions(); return true; }
/*! \brief \fn CCompletion::complete \param c \param trigger */ void CCompletion::complete(const QDocumentCursor &c, const QString &trigger) { // test if there is selected text // etendre le texte selectionner au mot complet // si il a pour next char une ( alors afficher un calltips if ( (trigger == "(" ) || !c.selectedText().isEmpty()) { QStringList tips; //qDebug("fn %s", fn.constData()); QList<QCodeNode*> nodes = mainwindow->windowide->completionScan(editor()); tips = mainwindow->windowide->getProc(getLastToken(c)); if ( tips.count() ) { CDOxyItem * di = mainwindow->windowide->getDOxygenInfo(getLastToken(c).trimmed()); if (di) { tips[0] += QString("\n")+di->brief; if (di->params.count()) { for (int j=0;j<di->params.size();j++) { tips[0] += QString("\n")+di->params.at(j); } } if (!(di->returnTyp.isEmpty())) tips[0]+=QString("\nReturn value : ")+di->returnTyp; if (tips[0].right(1)=="\n") tips[0].chop(1); } QRect r = editor()->cursorRect(); QDocumentCursor cursor = editor()->cursor(); QDocumentLine line = cursor.line(); int hx = editor()->horizontalOffset(), cx = line.cursorToX(cursor.columnNumber()); QCallTip *ct = new QCallTip(editor()->viewport()); ct->move(cx - hx, r.y() + r.height()); ct->setTips(tips); ct->show(); ct->setFocus(); #ifdef TRACE_COMPLETION qDebug("parsing + scoping + search + pre-display : elapsed %i ms", time.elapsed()); #endif } } else { if ( pPopup && pPopup->editor() != editor() ) { delete pPopup; pPopup = 0; } if ( !pPopup ) { pPopup = new QCodeCompletionWidget(editor()); } pPopup->clear(); pPopup->setCursor(editor()->cursor()); QTime time; time.start(); QList<QCodeNode*> nodes = mainwindow->windowide->completionScan(editor()); pPopup->setPrefix(getLastToken(c)); pPopup->setCompletions(nodes); pPopup->update(); pPopup->popup(); } #if 1 #endif }
void QEditorInputBinding::MotionCommand::exec(QEditor *e) { QDocumentCursor c = e->cursor(); c.movePosition(count, operation, mode); e->setCursor(c); }
void QEditorInputBinding::EditCommand::exec(QEditor *e) { QDocumentCursor c = e->cursor(); switch ( operation ) { case ClearSelection : c.clearSelection(); break; case SelectWord : c.select(QDocumentCursor::WordUnderCursor); break; case SelectLine : c.select(QDocumentCursor::LineUnderCursor); break; case SelectDocument : c.movePosition(1, QDocumentCursor::Start, QDocumentCursor::MoveAnchor); c.movePosition(1, QDocumentCursor::End, QDocumentCursor::KeepAnchor); break; case DeleteChar : c.deleteChar(); break; case DeletePreviousChar : c.deletePreviousChar(); break; case DeleteLine : c.eraseLine(); break; case DeleteSelection : c.removeSelectedText(); break; case InsertLine : c.insertLine(); break; case InsertClipBoard : e->paste(); return; default: break; } e->setCursor(c); }
QScriptValue searchReplaceFunction(QScriptContext *context, QScriptEngine *engine, bool replace){ QEditor *editor = qobject_cast<QEditor*>(context->thisObject().toQObject()); //read arguments SCRIPT_REQUIRE(editor, "invalid object"); SCRIPT_REQUIRE(!replace || context->argumentCount()>=2, "at least two arguments are required"); SCRIPT_REQUIRE(context->argumentCount()>=1, "at least one argument is required"); SCRIPT_REQUIRE(context->argumentCount()<=4, "too many arguments"); SCRIPT_REQUIRE(context->argument(0).isString()||context->argument(0).isRegExp(), "first argument must be a string or regexp"); QDocumentSearch::Options flags = QDocumentSearch::Silent; bool global = false, caseInsensitive = false; QString searchFor; if (context->argument(0).isRegExp()) { flags |= QDocumentSearch::RegExp; QRegExp r = context->argument(0).toRegExp(); searchFor = r.pattern(); caseInsensitive = r.caseSensitivity() == Qt::CaseInsensitive; Q_ASSERT(caseInsensitive == context->argument(0).property("ignoreCase").toBool()); //check assumption about javascript core global = context->argument(0).property("global").toBool(); } else searchFor = context->argument(0).toString(); QScriptValue handler; QDocumentCursor scope = editor->document()->cursor(0,0,editor->document()->lineCount(),0); int handlerCount = 0; for (int i=1; i<context->argumentCount();i++) if (context->argument(i).isString() || context->argument(i).isFunction()) handlerCount++; SCRIPT_REQUIRE(handlerCount <= (replace?2:1), "too many string or function arguments"); for (int i=1; i<context->argumentCount();i++) { QScriptValue a = context->argument(i); if (a.isFunction()) { SCRIPT_REQUIRE(!handler.isValid(), "Multiple callbacks"); handler = a; } else if (a.isString()) { if (!replace || handlerCount > 1) { QString s = a.toString().toLower(); global = s.contains("g"); caseInsensitive = s.contains("i"); if (s.contains("w")) flags |= QDocumentSearch::WholeWords; } else { SCRIPT_REQUIRE(!handler.isValid(), "Multiple callbacks"); handler = a; } handlerCount--; } else if (a.isNumber()) flags |= QDocumentSearch::Options((int)a.toNumber()); else if (a.isObject()) scope = cursorFromValue(a); else SCRIPT_REQUIRE(false, "Invalid argument"); } SCRIPT_REQUIRE(handler.isValid() || !replace, "No callback given"); if (!caseInsensitive) flags |= QDocumentSearch::CaseSensitive; //search/replace QDocumentSearch search(editor, searchFor, flags); search.setScope(scope); if (replace && handler.isString()) { search.setReplaceText(handler.toString()); search.setOption(QDocumentSearch::Replace,true); return search.next(false, global, false, false); } if (!handler.isValid()) return search.next(false,global,true,false); int count=0; while (search.next(false, false, true, false) && search.cursor().isValid()) { count++; QDocumentCursor temp = search.cursor(); QScriptValue cb = handler.call(QScriptValue(), QScriptValueList() << engine->newQObject(&temp)); if (replace && cb.isValid()){ QDocumentCursor tmp = search.cursor(); tmp.replaceSelectedText(cb.toString()); search.setCursor(tmp.selectionEnd()); } if (!global) break; } return count; }
void scriptengine::run(){ if (globalObject) delete globalObject; globalObject = new ScriptObject(m_script,buildManager,app); if(m_allowWrite){ globalObject->registerAllowedWrite(); } QScriptValue globalValue = engine->newQObject(globalObject); globalValue.setPrototype(engine->globalObject()); engine->setGlobalObject(globalValue); QDocumentCursor c; QScriptValue cursorValue; if (m_editorView) engine->globalObject().setProperty("editorView", engine->newQObject(m_editorView)); if (m_editor) { engine->globalObject().setProperty("editor", engine->newQObject(m_editor)); c=m_editor->cursor(); c.setAutoUpdated(true); //auto updated so the editor text insert functions actually move the cursor cursorValue = engine->newQObject(&c); engine->globalObject().setProperty("cursor", cursorValue); QScriptValue matches = engine->newArray(triggerMatches.size()); for (int i=0;i<triggerMatches.size();i++) matches.setProperty(i, triggerMatches[i]); engine->globalObject().setProperty("triggerMatches", matches); } engine->globalObject().setProperty("triggerId", engine->newVariant(triggerId)); engine->globalObject().setProperty("include", engine->newFunction(include)); engine->globalObject().setProperty("setTimeout", engine->newFunction(setTimeout)); QScriptValue qsMetaObject = engine->newQMetaObject(&QDocumentCursor::staticMetaObject); engine->globalObject().setProperty("cursorEnums", qsMetaObject); QScriptValue uidClass = engine->scriptValueFromQMetaObject<UniversalInputDialogScript>(); engine->globalObject().setProperty("UniversalInputDialog", uidClass); FileChooser flchooser(0,scriptengine::tr("File Chooser")); engine->globalObject().setProperty("fileChooser", engine->newQObject(&flchooser)); engine->globalObject().setProperty("documentManager", engine->newQObject(&app->documents)); engine->globalObject().setProperty("documents", qScriptValueFromQList(engine, app->documents.documents)); #ifndef NO_POPPLER_PREVIEW engine->globalObject().setProperty("pdfs", qScriptValueFromQList(engine, PDFDocument::documentList())); #endif QScriptValue bm = engine->newQObject(&app->buildManager); bm.setProperty("runCommand", engine->newFunction(buildManagerRunCommandWrapper)); //bm.setProperty("commandLineRequested", engine->globalObject().property("buildManagerCommandLineRequestedWrapper")); engine->globalObject().setProperty("buildManager", bm); //connect(buildManager, SIGNAL(commandLineRequested(QString,QString*)), SLOT(buildManagerCommandLineRequestedWrapperSlot(const QString&, QString*))); engine->evaluate(m_script); if(engine->hasUncaughtException()){ QString error = QString(tr("Uncaught exception at line %1: %2\n")).arg(engine->uncaughtExceptionLineNumber()).arg(engine->uncaughtException().toString()); error += "\n"+QString(tr("Backtrace %1")).arg(engine->uncaughtExceptionBacktrace().join(", ")); qDebug() << error; QMessageBox::critical(0, tr("Script-Error"), error); } if (m_editor) { if (engine->globalObject().property("cursor").strictlyEquals(cursorValue)) m_editor->setCursor(c); else m_editor->setCursor(cursorFromValue(engine->globalObject().property("cursor"))); } if (!globalObject->backgroundScript) { delete globalObject; globalObject = 0; } }
/*! */ bool QStatusPanel::paint(QPainter *p, QEditor *e) { //qDebug("drawing status panel... [%i, %i, %i, %i]", // geometry().x(), // geometry().y(), // geometry().width(), // geometry().height()); static QPixmap _warn(":/warning.png"), _mod(":/save.png"); QString s; int xpos = 10; QDocumentCursor c = e->cursor(); const QFontMetrics fm(fontMetrics()); const int ls = fm.lineSpacing(); const int ascent = fm.ascent() + 3; s = tr("Line : %1 Visual column : %2 Text column : %3") .arg(c.lineNumber() + 1) .arg(c.visualColumnNumber()) .arg(c.columnNumber()); p->drawText(xpos, ascent, s); xpos += fm.width(s) + 10; int sz = qMin(height(), _mod.height()); //int lastMod = d->lastModified().secsTo(QDateTime::currentDateTime()); //QString timeDiff = tr("(%1 min %2 s ago)").arg(lastMod / 60).arg(lastMod % 60); //xpos += 10; if ( e->isContentModified() ) { p->drawPixmap(xpos, (height() - sz) / 2, sz, sz, _mod); //xpos += sz; //xpos += 10; //p->drawText(xpos, ascent, timeDiff); } xpos += sz + 10; //xpos += fm.width(timeDiff); //xpos += 20; s = editor()->flag(QEditor::Overwrite) ? tr("OVERWRITE") : tr("INSERT"); p->drawText(xpos, ascent, s); xpos += fm.width(s) + 10; m_conflictSpot = 0; if ( editor()->isInConflict() ) { s = tr("Conflict"); int w = fm.width(s) + 30; if ( xpos + w + _warn.width() < width() ) { m_conflictSpot = width() - (w + _warn.width()); p->drawText(width() - w + 15, ascent, s); p->drawPixmap(m_conflictSpot, (ls - _warn.height()) / 2 + 2, _warn); } else if ( xpos + _warn.width() < width() ) { m_conflictSpot = width() - _warn.width(); p->drawPixmap(m_conflictSpot, (ls - _warn.height()) / 2 + 2, _warn); } } setFixedHeight(ls + 4); QTimer::singleShot(1000, this, SLOT( update() ) ); return true; }
QString cur2str(const QDocumentCursor &c){ if (c.hasSelection()) return QString("%1|%2|%3|%4").arg(c.anchorLineNumber()).arg(c.anchorColumnNumber()).arg(c.lineNumber()).arg(c.columnNumber()); return QString("%1|%2").arg(c.lineNumber()).arg(c.columnNumber()); }
void CodeSnippet::insertAt(QEditor* editor, QDocumentCursor* cursor, bool usePlaceholders, bool byCompleter) const{ if (lines.empty()||!editor||!cursor) return; //find filechooser escape %( %) QString line=lines.join("\n"); QRegExp rx("%\\((.+)%\\)"); int pos=rx.indexIn(line,0); if(pos>-1){ FileChooser sfDlg(0,QApplication::tr("Select a File")); sfDlg.setFilter(rx.cap(1)); LatexDocument *doc=qobject_cast<LatexDocument*>(cursor->document()); QString path=doc->parent->getCompileFileName(); path=getPathfromFilename(path); QString directory; if(path.isEmpty()) directory=QDir::homePath(); else directory=path; sfDlg.setDir(directory); if (sfDlg.exec()) { QString fn=sfDlg.fileName(); line.replace(rx,getRelativeBaseNameToPath(fn,path)); } else return; } QString savedSelection; bool alwaysSelect = false; bool editBlockOpened = false; if (cursor->hasSelection()) { savedSelection=cursor->selectedText(); editBlockOpened = true; cursor->beginEditBlock(); cursor->removeSelectedText(); }else if(!editor->cutBuffer.isEmpty()){ savedSelection=editor->cutBuffer; editor->cutBuffer.clear(); alwaysSelect = true; } bool multiLineSavedSelection = savedSelection.contains("\n"); QDocumentCursor selector=*cursor; QDocumentLine curLine=cursor->line(); // on multi line commands, replace environments only if(autoReplaceCommands && lines.size()>1 && line.contains("\\begin{")){ QString curLine=cursor->line().text(); int wordBreak=curLine.indexOf(QRegExp("\\W"),cursor->columnNumber()); int closeCurl=curLine.indexOf("}",cursor->columnNumber()); int openCurl=curLine.indexOf("{",cursor->columnNumber()); int openBracket=curLine.indexOf("[",cursor->columnNumber()); if(closeCurl>0){ if(openBracket<0) openBracket=1e9; if(openCurl<0) openCurl=1e9; if(wordBreak<0) wordBreak=1e9; if(closeCurl<openBracket && (closeCurl<=wordBreak || openCurl<=wordBreak)){ QString oldEnv; if(closeCurl<openCurl) oldEnv=curLine.mid(cursor->columnNumber(),closeCurl-cursor->columnNumber()); else oldEnv=curLine.mid(openCurl+1,closeCurl-openCurl-1); QRegExp rx("\\\\begin\\{(.+)\\}"); rx.setMinimal(true); rx.indexIn(line); QString newEnv=rx.cap(1); // remove curly brakets as well QDocument* doc=cursor->document(); QString searchWord="\\end{"+oldEnv+"}"; QString inhibitor="\\begin{"+oldEnv+"}"; bool backward=false; int step=1; int startLine=cursor->lineNumber(); //int startCol=cursor.columnNumber(); int endLine=doc->findLineContaining(searchWord,startLine+step,Qt::CaseSensitive,backward); int inhibitLine=doc->findLineContaining(inhibitor,startLine+step,Qt::CaseSensitive,backward); // not perfect (same line end/start ...) while (inhibitLine>0 && endLine>0 && inhibitLine*step<endLine*step) { endLine=doc->findLineContaining(searchWord,endLine+step,Qt::CaseSensitive,backward); // not perfect (same line end/start ...) inhibitLine=doc->findLineContaining(inhibitor,inhibitLine+step,Qt::CaseSensitive,backward); } QString endText=doc->line(endLine).text(); int start=endText.indexOf(searchWord); int offset=searchWord.indexOf("{"); int length=searchWord.length()-offset-1; selector.moveTo(endLine,start+1+offset); selector.movePosition(length-1,QDocumentCursor::Right,QDocumentCursor::KeepAnchor); selector.replaceSelectedText(newEnv); cursor->movePosition(closeCurl-cursor->columnNumber()+1,QDocumentCursor::Right,QDocumentCursor::KeepAnchor); QString first=lines.first(); int pos=first.indexOf('{'); pos=first.indexOf('{',pos+1); //pos of second { if(pos>-1) first.remove(pos,first.length()-pos); editor->insertText(*cursor,first); if (editBlockOpened) cursor->endEditBlock(); return; } } } int baseLine=cursor->lineNumber(); int baseLineIndent = cursor->columnNumber(); //text before inserted word moves placeholders to the right int lastLineRemainingLength = curLine.text().length()-baseLineIndent; //last line will has length: indentation + codesnippet + lastLineRemainingLength editor->insertText(*cursor,line); //don't use cursor->insertText to keep autoindentation working if (editBlockOpened) cursor->endEditBlock(); // on single line commands only: replace command if(byCompleter && autoReplaceCommands && lines.size()==1 && line.startsWith('\\')){ if(cursor->nextChar().isLetterOrNumber()||cursor->nextChar()==QChar('{')){ QString curLine=cursor->line().text(); int wordBreak=curLine.indexOf(QRegExp("\\W"),cursor->columnNumber()); int closeCurl=curLine.indexOf("}",cursor->columnNumber()); int openCurl=curLine.indexOf("{",cursor->columnNumber()); int openBracket=curLine.indexOf("[",cursor->columnNumber()); if(!line.contains("{")){ if(openBracket<0) openBracket=1e9; if(closeCurl<0) closeCurl=1e9; if(openCurl<0) openCurl=1e9; if(wordBreak<openBracket && wordBreak<closeCurl &&wordBreak<openCurl){ if(wordBreak<0) cursor->movePosition(wordBreak-cursor->columnNumber(),QDocumentCursor::EndOfLine,QDocumentCursor::KeepAnchor); else cursor->movePosition(wordBreak-cursor->columnNumber(),QDocumentCursor::Right,QDocumentCursor::KeepAnchor); cursor->removeSelectedText(); return; } }else{ if(openCurl>-1){ if(openBracket<0) openBracket=1e9; if(closeCurl<0) closeCurl=1e9; if(openCurl<openBracket && openCurl<closeCurl &&openCurl<=wordBreak){ cursor->movePosition(openCurl-cursor->columnNumber(),QDocumentCursor::Right,QDocumentCursor::KeepAnchor); cursor->removeSelectedText(); int curl=line.length()-line.indexOf("{"); cursor->movePosition(curl,QDocumentCursor::Left,QDocumentCursor::KeepAnchor); cursor->removeSelectedText(); return; } } } } } Q_ASSERT(placeHolders.size()==lines.count()); if (usePlaceholders) { //check if there actually are placeholders to insert usePlaceholders=false; for (int l=0;l< lines.count();l++) usePlaceholders|=placeHolders[l].size(); } int autoSelectPlaceholder = -1; if (usePlaceholders) { if (editor->currentPlaceHolder()!=-1 && editor->getPlaceHolder(editor->currentPlaceHolder()).cursor.isWithinSelection(*cursor)) editor->removePlaceHolder(editor->currentPlaceHolder()); //remove currentplaceholder to prevent nesting for (int l=0;l< lines.count();l++){ //if (l<mLines.count()-1) cursor->insertLine(); for (int i=0; i<placeHolders[l].size(); i++) { if (placeHolders[l][i].flags & CodeSnippetPlaceHolder::Mirror) continue; PlaceHolder ph; ph.length=placeHolders[l][i].length; ph.cursor = getCursor(editor, placeHolders[l][i], l, baseLine, baseLineIndent, lastLineRemainingLength); ph.autoRemove = !(placeHolders[l][i].flags & CodeSnippetPlaceHolder::Persistent); if (!ph.cursor.isValid()) continue; editor->addPlaceHolder(ph); if (placeHolders[l][i].flags & CodeSnippetPlaceHolder::Mirrored) { int phId = editor->placeHolderCount()-1; for (int lm=0; lm<placeHolders.size(); lm++) for (int im=0; im < placeHolders[lm].size(); im++) if (placeHolders[lm][im].flags & CodeSnippetPlaceHolder::Mirror && placeHolders[lm][im].id == placeHolders[l][i].id) editor->addPlaceHolderMirror(phId, getCursor(editor, placeHolders[lm][im], lm, baseLine, baseLineIndent, lastLineRemainingLength)); } if ((placeHolders[l][i].flags & CodeSnippetPlaceHolder::AutoSelect) && ((autoSelectPlaceholder == -1) || (multiLineSavedSelection && (placeHolders[l][i].flags & CodeSnippetPlaceHolder::PreferredMultilineAutoSelect)))) autoSelectPlaceholder = editor->placeHolderCount()-1; } } } //place cursor/add \end if (cursorOffset!=-1) { int realAnchorOffset=anchorOffset; //will be moved to the right if text is already inserted on this line if (cursorLine>0) { if (cursorLine>=lines.size()) return; if (!selector.movePosition(cursorLine,QDocumentCursor::Down,QDocumentCursor::MoveAnchor)) return; //if (editor->flag(QEditor::AutoIndent)) realAnchorOffset += selector.line().length()-lines[cursorLine].length(); if (cursorLine + 1 == lines.size()) realAnchorOffset-=lastLineRemainingLength; } else realAnchorOffset += baseLineIndent; selector.setColumnNumber(realAnchorOffset); bool ok=true; if (cursorOffset>anchorOffset) ok=selector.movePosition(cursorOffset-anchorOffset,QDocumentCursor::Right,QDocumentCursor::KeepAnchor); else if (cursorOffset<anchorOffset) ok=selector.movePosition(anchorOffset-cursorOffset,QDocumentCursor::Left,QDocumentCursor::KeepAnchor); if (!ok) return; editor->setCursor(selector); } else if (autoSelectPlaceholder!=-1) editor->setPlaceHolder(autoSelectPlaceholder, true); //this moves the cursor to that placeholder else { editor->setCursor(*cursor); //place after insertion return; } if (!savedSelection.isEmpty()) { QDocumentCursor oldCursor = editor->cursor(); editor->cursor().insertText(savedSelection,true); if (!editor->cursor().hasSelection() && alwaysSelect) { oldCursor.movePosition(savedSelection.length(), QDocumentCursor::Right, QDocumentCursor::KeepAnchor); editor->setCursor(oldCursor); } if (autoSelectPlaceholder!=-1) editor->setPlaceHolder(autoSelectPlaceholder, true); //this synchronizes the placeholder mirrors with the current placeholder text } }
void CompletionWord::insertAt(QEditor* editor, QDocumentCursor cursor){ QString savedSelection; int multilines=shownWord.count('\n'); QVector<QDocumentLine> documentlines; if (cursor.hasSelection()) { savedSelection=cursor.selectedText(); cursor.removeSelectedText(); } QDocumentCursor selector=cursor; int curStart=cursor.columnNumber(); QDocumentLine curLine=cursor.line(); cursor.insertText(shownWord); if (multilines) { documentlines.resize(multilines+1); documentlines[0]=curLine; for (int i=1;i<documentlines.count()-1;i++) documentlines[i]=documentlines[i-1].next(); //todo: optimize } if (QDocument::formatFactory()) for (int i=0;i<descriptiveParts.size();i++) { QFormatRange fr(descriptiveParts[i].first+curStart,descriptiveParts[i].second,QDocument::formatFactory()->id("temporaryCodeCompletion")); if (multilines) { QString temp= shownWord; temp.truncate(descriptiveParts[i].first); int linetoadd=temp.count('\n'); if (linetoadd==0) curLine.addOverlay(fr); else if (linetoadd<documentlines.size()) { fr.offset=temp.size()-temp.lastIndexOf('\n')-1; documentlines[linetoadd].addOverlay(fr); } } else curLine.addOverlay(fr); } //place cursor/add \end int selectFrom=-1; int selectTo=-1; int deltaLine=0; if (shownWord.startsWith("\\begin")&&!multilines) { //int curColumnNumber=cursor.columnNumber(); QString indent=curLine.indentation(); int p=shownWord.indexOf("{"); QString content="content..."; if (editor->flag(QEditor::AutoIndent)){ cursor.insertText( "\n"+indent+"\t"+content+"\n"+indent+"\\end"+shownWord.mid(p,shownWord.indexOf("}")-p+1)); indent+="\t"; } else cursor.insertText( "\n"+indent+content+"\n"+indent+"\\end"+shownWord.mid(p,shownWord.indexOf("}")-p+1)); if (QDocument::formatFactory()) for (int i=0;i<descriptiveParts.size();i++) curLine.next().addOverlay(QFormatRange(indent.size(),content.size(),QDocument::formatFactory()->id("temporaryCodeCompletion"))); if (cursorPos==-1) { deltaLine=1; selectFrom=indent.length(); selectTo=indent.length()+content.size(); } else { selectFrom=anchorPos+curStart; selectTo=cursorPos+curStart; } } else if (cursorPos>-1) { if (multilines) { //todo: add support for selected multilines QString temp= shownWord; temp.truncate(cursorPos); deltaLine=temp.count('\n'); if (!deltaLine) { selectFrom=anchorPos+curStart; selectTo=cursorPos+curStart; } else { selectTo=temp.size()-temp.lastIndexOf('\n')-1; selectFrom=anchorPos-cursorPos+selectTo; } } else { selectFrom=anchorPos+curStart; selectTo=cursorPos+curStart; } } else editor->setCursor(cursor); //place after insertion if (selectFrom!=-1){ if (deltaLine>0) selector.movePosition(deltaLine,QDocumentCursor::Down,QDocumentCursor::MoveAnchor); selector.setColumnNumber(selectFrom); if (selectTo>selectFrom) selector.movePosition(selectTo-selectFrom,QDocumentCursor::Right,QDocumentCursor::KeepAnchor); else if (selectTo<selectFrom) selector.movePosition(selectFrom-selectTo,QDocumentCursor::Left,QDocumentCursor::KeepAnchor); editor->setCursor(selector); } if (!savedSelection.isEmpty() && cursorPos>0) editor->cursor().insertText(savedSelection); }
void QSearchReplacePanel::on_leFind_textEdited(const QString& text) { bool hadSearch = m_search; QDocumentCursor cur = editor()->cursor(); if ( m_search ) { cur = m_search->cursor(); m_search->setSearchText(text); if ( cbCursor->isChecked() ) { QDocumentCursor c = cur; c.setColumnNumber(qMin(c.anchorColumnNumber(), c.columnNumber())); m_search->setCursor(c); } } else { // TODO : make incremental search optional init(); } if ( text.isEmpty() ) { leFind->setStyleSheet(QString()); return; } m_search->setOption(QDocumentSearch::Silent, true); find(0); m_search->setOption(QDocumentSearch::Silent, false); if ( m_search->cursor().isNull() ) { leFind->setStyleSheet("QLineEdit { background: red; color : white; }"); if ( hadSearch ) { m_search->setCursor(cur); // figure out whether other matches are availables QDocumentSearch::Options opts = m_search->options(); opts &= ~QDocumentSearch::HighlightAll; opts |= QDocumentSearch::Silent; QDocumentSearch temp(editor(), text, opts); temp.setOrigin(QDocumentCursor()); temp.setScope(m_search->scope()); temp.next(true); if ( temp.cursor().isValid() ) { // other match found from doc start leFind->setStyleSheet("QLineEdit { background: yellow; color : black; }"); m_search->setCursor(cur.document()->cursor(0,0)); find(0); } } } else { leFind->setStyleSheet(QString()); editor()->setCursor(m_search->cursor()); } }