Ai
1 Star 1 Fork 1

HuanZeng/texstudio

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
diffoperations.cpp 18.03 KB
一键复制 编辑 原始数据 按行查看 历史
Transporter 提交于 2018-12-10 23:37 +08:00 . Fixes for MS Visual Studio 2017
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
#include "diffoperations.h"
#include "latexdocument.h"
#include "latexeditorview.h"
#include "smallUsefulFunctions.h"
DiffOp::DiffOp(): start(0), length(0), type(Insert), lineWasModified(false), dlh(nullptr) {}
void diffDocs(LatexDocument *doc, LatexDocument *doc2, bool dontAddLines)
{
QString text = doc->text();
QString text2 = doc2->text();
diff_match_patch dmp;
QString error;
QList<Diff> diffList;
try {
diffList = dmp.diff_main(text, text2, true);
dmp.diff_cleanupSemantic(diffList);
} catch (const char *c) {
if (c) error = QString(c);
#ifndef _MSC_VER
} catch (char *c) {
if (c) error = QString(c);
#endif
} catch (const QString &s) {
error = s;
} catch (...) {
error = LatexDocument::tr("Unknown error. Potential crash. You are advised to restart TeXstudio");
}
if (!error.isEmpty()) {
UtilsUi::txsWarning("Diff: " + error);
return;
}
int lineNr = 0;
int lineNr2 = 0;
int col = 0;
for (int i = 0; i < diffList.size(); ++i) {
const Diff elem = diffList.at(i);
if (elem.operation == EQUAL) {
lineNr += elem.text.count("\n");
lineNr2 += elem.text.count("\n");
if (elem.text.count("\n") > 0)
col = 0;
col += elem.text.length();
if (elem.text.lastIndexOf("\n") >= 0)
col -= elem.text.lastIndexOf("\n") + 1;
}
if (elem.operation == DELETE) {
QStringList splitList = elem.text.split("\n");
QStringList splitListInsert;
if (splitList.isEmpty())
continue;
QString lineDelete = splitList.takeFirst();
int diff = lineDelete.length();
bool toBeReplaced = false;
if (i + 1 < diffList.size() && diffList[i + 1].operation == INSERT) {
splitListInsert = diffList[i + 1].text.split("\n");
}
if ( splitListInsert.size() > 0 && (splitList.size() > 1 || splitListInsert.size() > 1) ) {
toBeReplaced = true;
}
QVariant var = doc->line(lineNr).getCookie(QDocumentLine::DIFF_LIST_COOCKIE);
DiffList lineData;
bool lineModified;
if (var.isValid()) {
lineData = var.value<DiffList>();
if (lineData.isEmpty())
lineModified = doc->isLineModified(doc->line(lineNr));
else
lineModified = lineData.first().lineWasModified;
} else {
lineModified = doc->isLineModified(doc->line(lineNr));
}
//doc->line(lineNr).addOverlay(QFormatRange(col,diff,fid));
DiffOp diffOperation;
diffOperation.start = col;
diffOperation.length = diff;
diffOperation.lineWasModified = lineModified;
if (toBeReplaced) {
diffOperation.type = DiffOp::Replace;
diffOperation.text = splitListInsert.takeFirst();
diffOperation.dlh = doc2->line(lineNr2).handle();
//qDebug()<<doc->line(lineNr).text()<<" <-> "<< diffOperation.dlh->text();
if (splitList.isEmpty()) {
diffOperation.text += "\n" + splitListInsert.join("\n");
lineNr2 += splitListInsert.size();
}
} else {
diffOperation.type = DiffOp::Delete;
}
lineData.append(diffOperation);
doc->line(lineNr).setCookie(QDocumentLine::DIFF_LIST_COOCKIE, QVariant::fromValue<DiffList>(lineData));
col += diff;
int sz = splitList.size();
for (int j = 0; j < sz; j++) {
col = 0;
QString ln = splitList.takeFirst();
DiffOp diffOperation;
diffOperation.start = col;
diffOperation.length = ln.length();
if (toBeReplaced) {
lineNr2++;
diffOperation.type = DiffOp::Replace;
if (splitListInsert.isEmpty()) {
diffOperation.text = "";
} else {
diffOperation.text = splitListInsert.takeFirst();
diffOperation.dlh = doc2->line(lineNr2).handle();
//qDebug()<<doc->line(lineNr+j+1).text()<<" <-> "<< diffOperation.dlh->text();
if (splitList.isEmpty() && !splitListInsert.isEmpty()) {
diffOperation.text += "\n" + splitListInsert.join("\n");
lineNr2 += splitListInsert.size();
}
}
} else {
diffOperation.type = DiffOp::Delete;
}
var = doc->line(lineNr + j + 1).getCookie(QDocumentLine::DIFF_LIST_COOCKIE);
DiffList lineData;
if (var.isValid()) {
lineData = var.value<DiffList>();
if (lineData.isEmpty())
lineModified = doc->isLineModified(doc->line(lineNr + j + 1));
else
lineModified = lineData.first().lineWasModified;
} else {
lineModified = doc->isLineModified(doc->line(lineNr + j + 1));
}
diffOperation.lineWasModified = lineModified;
lineData.append(diffOperation);
doc->line(lineNr + j + 1).setCookie(QDocumentLine::DIFF_LIST_COOCKIE, QVariant::fromValue<DiffList>(lineData));
col = ln.length();
}
lineNr += elem.text.count("\n");
if (toBeReplaced)
i++;
}
if (elem.operation == INSERT) {
QStringList splitList = elem.text.split("\n");
if (splitList.isEmpty())
continue;
QDocumentCursor cur(doc);
if (lineNr + 1 > doc->lines()) {
if (dontAddLines)
continue;
cur.moveTo(lineNr - 1, 0);
cur.movePosition(1, QDocumentCursor::EndOfLine);
cur.insertText("\n");
} else {
cur.moveTo(lineNr, col);
}
int diff = splitList.first().length();
cur.insertText(splitList.first());
int lnNr = cur.lineNumber();
if (splitList.size() > 1 && !dontAddLines)
cur.insertText("\n");
QVariant var = doc->line(lnNr).getCookie(QDocumentLine::DIFF_LIST_COOCKIE);
DiffList lineData;
bool lineModified;
if (var.isValid()) {
lineData = var.value<DiffList>();
if (lineData.isEmpty())
lineModified = doc->isLineModified(doc->line(lnNr));
else
lineModified = lineData.first().lineWasModified;
} else {
lineModified = doc->isLineModified(doc->line(lnNr));
}
DiffOp diffOperation;
diffOperation.start = col;
diffOperation.length = diff;
diffOperation.type = DiffOp::Insert;
diffOperation.text = "";
diffOperation.lineWasModified = lineModified;
diffOperation.dlh = doc2->line(lineNr2).handle();
//qDebug()<<doc->line(lnNr).text()<<" <-> "<< diffOperation.dlh->text();
lineData.append(diffOperation);
doc->line(lnNr).setCookie(QDocumentLine::DIFF_LIST_COOCKIE, QVariant::fromValue<DiffList>(lineData));
//doc->line(lnNr).addOverlay(QFormatRange(col,diff,fid_Insert));
col += diff;
splitList.removeFirst();
if (dontAddLines)
continue;
for (int i = 0; i < splitList.size(); i++) {
lineNr2++;
QString ln = splitList.at(i);
cur.insertText(ln);
lnNr = cur.lineNumber();
if (i + 1 < splitList.size())
cur.insertText("\n");
QVariant var = doc->line(lnNr).getCookie(QDocumentLine::DIFF_LIST_COOCKIE);
DiffList lineData;
if (var.isValid()) {
lineData = var.value<DiffList>();
if (lineData.isEmpty())
lineModified = doc->isLineModified(doc->line(lnNr));
else
lineModified = lineData.first().lineWasModified;
} else {
lineModified = doc->isLineModified(doc->line(lnNr));
}
DiffOp diffOperation;
diffOperation.start = 0;
diffOperation.length = ln.length();
diffOperation.type = DiffOp::Insert;
diffOperation.text = "";
diffOperation.lineWasModified = lineModified;
diffOperation.dlh = doc2->line(lineNr2).handle();
//qDebug()<<doc->line(lnNr).text()<<" <-> "<< diffOperation.dlh->text();
lineData.append(diffOperation);
doc->line(lnNr).setCookie(QDocumentLine::DIFF_LIST_COOCKIE, QVariant::fromValue<DiffList>(lineData));
//doc->line(lnNr).addOverlay(QFormatRange(0,ln.length(),fid_Insert));
col = ln.length();
}
lineNr += elem.text.count("\n");
}
}
doc->mayHaveDiffMarkers = true;
}
void diffRemoveMarkers(LatexDocument *doc, bool theirs)
{
if (!doc || !doc->mayHaveDiffMarkers)
return;
QDocumentCursor cur(doc);
for (int i = 0; i < doc->lineCount(); i++) {
QVariant var = doc->line(i).getCookie(QDocumentLine::DIFF_LIST_COOCKIE);
if (var.isValid()) {
DiffList lineData = var.value<DiffList>();
int offset = 0;
for (int j = 0; j < lineData.size(); j++) {
DiffOp op = lineData.at(j);
bool removeLine = false;
if (theirs) { //keep theirs
switch (op.type) {
case DiffOp::Delete:
cur.moveTo(i, op.start + offset);
cur.movePosition(op.length, QDocumentCursor::NextCharacter, QDocumentCursor::KeepAnchor);
cur.removeSelectedText();
break;
case DiffOp::Insert:
break;
case DiffOp::Replace:
cur.moveTo(i, op.start + offset);
cur.movePosition(op.length, QDocumentCursor::NextCharacter, QDocumentCursor::KeepAnchor);
cur.insertText(op.text);
if (op.text.isEmpty() && cur.line().text().isEmpty()) {
cur.deletePreviousChar();
i--;
}
break;
default:
;
}
} else { // keep mine
switch (op.type) {
case DiffOp::Delete:
break;
case DiffOp::Insert:
cur.moveTo(i, op.start + offset);
removeLine = op.length == doc->line(i).length();
cur.movePosition(op.length, QDocumentCursor::NextCharacter, QDocumentCursor::KeepAnchor);
cur.removeSelectedText();
offset = -op.length;
if (removeLine) {
cur.deletePreviousChar();
i--;
}
break;
case DiffOp::Replace:
break;
default:
;
}
}
}
doc->line(i).removeCookie(QDocumentLine::DIFF_LIST_COOCKIE);
}
}
doc->mayHaveDiffMarkers = false;
}
void diffChange(LatexDocument *doc, int ln, int col, bool theirs)
{
LatexEditorView *edView = doc->getEditorView();
QDocumentCursor cursor(doc);
cursor.moveTo(ln, col);
QList<int> fids;
fids << edView->deleteFormat << edView->insertFormat << edView->replaceFormat;
foreach (int fid, fids) {
QFormatRange fr;
if (cursor.hasSelection()) fr = cursor.line().getOverlayAt((cursor.columnNumber() + cursor.anchorColumnNumber()) / 2, fid);
else fr = cursor.line().getOverlayAt(cursor.columnNumber(), fid);
if (fr.length > 0 ) {
QDocumentCursor range = diffSearchBoundaries(doc, ln, col, fid);
cursor.moveTo(range.lineNumber(), range.columnNumber());
QVariant var = cursor.line().getCookie(QDocumentLine::DIFF_LIST_COOCKIE);
if (var.isValid()) {
DiffList diffList = var.value<DiffList>();
//QString word=cursor.line().text().mid(fr.offset,fr.length);
DiffOp op;
QList<DiffOp>::iterator i;
for (i = diffList.begin(); i != diffList.end(); ++i) {
op = *i;
if (op.start <= cursor.columnNumber() && op.start + op.length >= cursor.columnNumber()) {
break;
}
}
QStringList splitText;
if (i != diffList.end()) {
QString txt;
QString altText;
int ln2;
QDocumentCursor range2(doc);
if (theirs) {
switch (op.type) {
case DiffOp::Delete:
range.beginBoundary(ln2, col);
range.endBoundary(ln, col);
if (ln2 - ln == 0) {
range2 = diffSearchBoundaries(doc, ln, col, edView->insertFormat);
diffChangeOpType(range2, DiffOp::Inserted);
}
range.removeSelectedText();
diffList.erase(i);
cursor.line().setCookie(QDocumentLine::DIFF_LIST_COOCKIE, QVariant::fromValue<DiffList>(diffList));
break;
case DiffOp::Insert:
//op.type=DiffOp::Inserted;
//*i=op;
range.endBoundary(ln, col);
range.beginBoundary(ln2, col);
diffChangeOpType(range, DiffOp::Inserted);
if ((ln2 - ln == 0) && (col > 0)) {
range2 = diffSearchBoundaries(doc, ln2, col - 1, edView->deleteFormat);
range2.removeSelectedText();
diffChangeOpType(range2, DiffOp::Deleted);
}
break;
case DiffOp::Replace:
altText = diffCollectText(range);
txt = range.selectedText();
range.removeSelectedText();
range.insertText(altText);
op.type = DiffOp::Replaced;
op.text = txt;
splitText = txt.split("\n");
op.length = splitText.first().length();
*i = op;
cursor.line().setCookie(QDocumentLine::DIFF_LIST_COOCKIE, QVariant::fromValue<DiffList>(diffList));
break;
default:
;
} // end theirs
} else {
switch (op.type) {
case DiffOp::Delete:
//op.type=DiffOp::NotDeleted;
//*i=op;
range.beginBoundary(ln2, col);
range.endBoundary(ln, col);
if (ln2 - ln == 0) {
range2 = diffSearchBoundaries(doc, ln, col, edView->insertFormat);
range2.removeSelectedText();
}
diffChangeOpType(range, DiffOp::NotDeleted);
break;
case DiffOp::Insert:
range.endBoundary(ln, col);
range.beginBoundary(ln2, col);
if ((ln2 - ln == 0) && (col > 0)) {
range2 = diffSearchBoundaries(doc, ln2, col - 1, edView->deleteFormat);
diffChangeOpType(range2, DiffOp::NotDeleted);
}
range.removeSelectedText();
diffList.erase(i);
cursor.line().setCookie(QDocumentLine::DIFF_LIST_COOCKIE, QVariant::fromValue<DiffList>(diffList));
if (range.line().text().isEmpty())
range.eraseLine();
//if(removeLine)
// cursor.deletePreviousChar();
break;
case DiffOp::Replace:
//op.type=DiffOp::NotReplaced;
//*i=op;
diffChangeOpType(range, DiffOp::NotReplaced);
break;
default:
;
}
} // end mine
}
}
return;
} // if fr.length>0
}
}
QDocumentCursor diffSearchBoundaries(LatexDocument *doc, int ln, int col, int fid, int direction)
{
// direction 0 both, 1 forward, -1 backward
if (!doc)
return QDocumentCursor();
QDocumentCursor result(doc);
QDocumentCursor cursor(doc);
cursor.moveTo(ln, col);
QFormatRange fr = cursor.line().getOverlayAt(cursor.columnNumber(), fid);
if (fr.length == 0)
return QDocumentCursor();
QDocumentCursor beginCur(doc);
beginCur.moveTo(ln, fr.offset);
QDocumentCursor endCur(doc);
endCur.moveTo(ln, fr.offset + fr.length);
if (fr.length > 0 && fr.offset == 0 && direction < 1) {
//search backward
if (ln > 0) {
beginCur.movePosition(1, QDocumentCursor::PreviousCharacter);
QDocumentCursor zw = diffSearchBoundaries(doc, beginCur.lineNumber(), beginCur.columnNumber(), fid, -1);
if (zw.isValid())
beginCur = zw;
}
}
if (fr.length > 0 && fr.offset + fr.length == endCur.line().length() && direction > -1) {
//search backward
if (ln + 1 < doc->lineCount()) {
endCur.movePosition(1, QDocumentCursor::NextCharacter);
QDocumentCursor zw = diffSearchBoundaries(doc, endCur.lineNumber(), endCur.columnNumber(), fid, 1);
if (zw.isValid())
endCur = zw;
}
}
if (beginCur.isValid())
result.moveTo(beginCur.lineNumber(), beginCur.columnNumber());
if (endCur.isValid())
result.moveTo(endCur.anchorLineNumber(), endCur.anchorColumnNumber(), QDocumentCursor::KeepAnchor);
return result;
}
QString diffCollectText(QDocumentCursor range)
{
QDocumentCursor cursor(range);
QString result;
while (cursor.lineNumber() <= range.anchorLineNumber()) {
QVariant var = cursor.line().getCookie(QDocumentLine::DIFF_LIST_COOCKIE);
if (var.isValid()) {
DiffList diffList = var.value<DiffList>();
//QString word=cursor.line().text().mid(fr.offset,fr.length);
DiffOp op;
QList<DiffOp>::const_iterator i;
for (i = diffList.constBegin(); i != diffList.constEnd(); ++i) {
op = *i;
if (op.start <= cursor.columnNumber() && op.start + op.length >= cursor.columnNumber()) {
break;
}
}
if (i != diffList.constEnd()) {
if (!result.isEmpty())
result += "\n";
result += op.text;
}
}
if (cursor.lineNumber() + 1 == cursor.document()->lineCount())
break;
cursor.movePosition(1, QDocumentCursor::NextLine);
}
return result;
}
void diffChangeOpType(QDocumentCursor range, DiffOp::DiffType type)
{
QDocumentCursor cursor(range);
while (cursor.lineNumber() <= range.anchorLineNumber()) {
QVariant var = cursor.line().getCookie(QDocumentLine::DIFF_LIST_COOCKIE);
if (var.isValid()) {
DiffList diffList = var.value<DiffList>();
//QString word=cursor.line().text().mid(fr.offset,fr.length);
DiffOp op;
QList<DiffOp>::iterator i;
for (i = diffList.begin(); i != diffList.end(); ++i) {
op = *i;
if (op.start <= cursor.columnNumber() && op.start + op.length >= cursor.columnNumber()) {
break;
}
}
if (i != diffList.end()) {
op.type = type;
*i = op;
}
cursor.line().setCookie(QDocumentLine::DIFF_LIST_COOCKIE, QVariant::fromValue<DiffList>(diffList));
}
if (cursor.lineNumber() + 1 == cursor.document()->lineCount())
break;
cursor.movePosition(1, QDocumentCursor::NextLine);
}
}
void diffMerge(LatexDocument *doc)
{
if (!doc)
return;
//LatexDocument *doc2=doc->findChild("diffObejct");
enum Version {mine, their, conflict};
Version whose;
QDocumentCursor cur(doc);
for (int i = 0; i < doc->lineCount(); i++) {
QVariant var = doc->line(i).getCookie(QDocumentLine::DIFF_LIST_COOCKIE);
if (var.isValid()) {
DiffList lineData = var.value<DiffList>();
for (int j = 0; j < lineData.size(); j++) {
DiffOp op = lineData.at(j);
if (op.lineWasModified) {
whose = mine;
if (op.dlh != nullptr) {
QVariant var = op.dlh->getCookie(QDocumentLine::DIFF_LIST_COOCKIE);
if (var.isValid()) {
whose = conflict;
}
}
} else {
whose = their;
}
bool removeLine = false;
if (whose == their) { //keep theirs
switch (op.type) {
case DiffOp::Delete:
cur.moveTo(i, op.start);
cur.movePosition(op.length, QDocumentCursor::NextCharacter, QDocumentCursor::KeepAnchor);
cur.removeSelectedText();
if (cur.line().text().isEmpty()) {
cur.eraseLine();
i--;
}
break;
case DiffOp::Insert:
break;
case DiffOp::Replace:
cur.moveTo(i, op.start);
cur.movePosition(op.length, QDocumentCursor::NextCharacter, QDocumentCursor::KeepAnchor);
cur.insertText(op.text);
if (op.text.isEmpty() && cur.line().text().isEmpty()) {
cur.deletePreviousChar();
i--;
}
break;
default:
;
}
}
if (whose == mine) { // keep mine
switch (op.type) {
case DiffOp::Delete:
break;
case DiffOp::Insert:
cur.moveTo(i, op.start);
removeLine = op.length == doc->line(i).length();
cur.movePosition(op.length, QDocumentCursor::NextCharacter, QDocumentCursor::KeepAnchor);
cur.removeSelectedText();
if (removeLine) {
cur.deletePreviousChar();
i--;
}
break;
case DiffOp::Replace:
break;
default:
;
}
}
}
doc->line(i).removeCookie(QDocumentLine::DIFF_LIST_COOCKIE);
}
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/xmrzh/texstudio.git
git@gitee.com:xmrzh/texstudio.git
xmrzh
texstudio
texstudio
master

搜索帮助