Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Utilities
Kate
Commits
7d8a1c3d
Commit
7d8a1c3d
authored
Sep 01, 2022
by
Waqar Ahmed
Committed by
Christoph Cullmann
Sep 03, 2022
Browse files
Add basic inline diffing
parent
ae505e22
Changes
1
Hide whitespace changes
Inline
Side-by-side
apps/lib/diffwidget.cpp
View file @
7d8a1c3d
...
...
@@ -10,6 +10,7 @@
#include
<QApplication>
#include
<QHBoxLayout>
#include
<QMimeDatabase>
#include
<QPainter>
#include
<QPainterPath>
#include
<QRegularExpression>
...
...
@@ -112,12 +113,102 @@ static void balanceHunkLines(QStringList &left, QStringList &right, int &lineA,
}
}
static
std
::
pair
<
Change
,
Change
>
inlineDiff
(
QStringView
l
,
QStringView
r
)
{
auto
sitl
=
l
.
begin
();
auto
sitr
=
r
.
begin
();
while
(
sitl
!=
l
.
end
()
||
sitr
!=
r
.
end
())
{
if
(
*
sitl
!=
*
sitr
)
{
break
;
}
++
sitl
;
++
sitr
;
}
int
lStart
=
std
::
distance
(
l
.
begin
(),
sitl
);
int
rStart
=
std
::
distance
(
r
.
begin
(),
sitr
);
auto
eitl
=
l
.
rbegin
();
auto
eitr
=
r
.
rbegin
();
int
lcount
=
l
.
size
();
int
rcount
=
r
.
size
();
while
(
eitl
!=
l
.
rend
()
||
eitr
!=
r
.
rend
())
{
if
(
*
eitl
!=
*
eitr
)
{
break
;
}
// do not allow overlap
if
(
lcount
==
lStart
||
rcount
==
rStart
)
{
break
;
}
--
lcount
;
--
rcount
;
++
eitl
;
++
eitr
;
}
int
lEnd
=
l
.
size
()
-
std
::
distance
(
l
.
rbegin
(),
eitl
);
int
rEnd
=
r
.
size
()
-
std
::
distance
(
r
.
rbegin
(),
eitr
);
Change
cl
;
cl
.
pos
=
lStart
;
cl
.
len
=
lEnd
-
lStart
;
Change
cr
;
cr
.
pos
=
rStart
;
cr
.
len
=
rEnd
-
rStart
;
return
{
cl
,
cr
};
}
struct
HunkChangedLine
{
const
QString
line
;
bool
added
;
int
lineNo
;
Change
c
=
{
-
1
,
-
1
};
};
static
void
markInlineDiffs
(
QVector
<
HunkChangedLine
>
&
hunkChangedLinesA
,
QVector
<
HunkChangedLine
>
&
hunkChangedLinesB
,
QVector
<
LineHighlight
>
&
leftHlts
,
QVector
<
LineHighlight
>
&
rightHlts
)
{
if
(
hunkChangedLinesA
.
size
()
!=
hunkChangedLinesB
.
size
())
{
hunkChangedLinesA
.
clear
();
hunkChangedLinesB
.
clear
();
return
;
}
const
int
size
=
hunkChangedLinesA
.
size
();
for
(
int
i
=
0
;
i
<
size
;
++
i
)
{
const
auto
[
leftChange
,
rightChange
]
=
inlineDiff
(
hunkChangedLinesA
.
at
(
i
).
line
,
hunkChangedLinesB
.
at
(
i
).
line
);
hunkChangedLinesA
[
i
].
c
=
leftChange
;
hunkChangedLinesB
[
i
].
c
=
rightChange
;
}
auto
addHighlights
=
[](
QVector
<
HunkChangedLine
>
&
hunkChangedLines
,
QVector
<
LineHighlight
>
&
hlts
)
{
for
(
int
i
=
0
;
i
<
hunkChangedLines
.
size
();
++
i
)
{
auto
&
change
=
hunkChangedLines
[
i
];
for
(
int
j
=
hlts
.
size
()
-
1
;
j
>=
0
;
--
j
)
{
if
(
hlts
.
at
(
j
).
line
==
change
.
lineNo
)
{
hlts
[
j
].
changes
.
push_back
(
change
.
c
);
break
;
}
else
if
(
hlts
.
at
(
j
).
line
<
change
.
lineNo
)
{
break
;
}
}
}
};
addHighlights
(
hunkChangedLinesA
,
leftHlts
);
addHighlights
(
hunkChangedLinesB
,
rightHlts
);
hunkChangedLinesA
.
clear
();
hunkChangedLinesB
.
clear
();
}
void
DiffWidget
::
openDiff
(
const
QByteArray
&
raw
)
{
// printf("show diff:\n%s\n================================", raw.constData());
const
QStringList
text
=
QString
::
fromUtf8
(
raw
).
replace
(
QStringLiteral
(
"
\r\n
"
),
QStringLiteral
(
"
\n
"
)).
split
(
QLatin1Char
(
'\n'
),
Qt
::
SkipEmptyParts
);
static
const
QRegularExpression
HUNK_HEADER_RE
(
QStringLiteral
(
"^@@ -([0-9,]+)
\\
+([0-9,]+) @@(.*)"
));
static
const
QRegularExpression
DIFF_FILENAME_RE
(
QStringLiteral
(
"^[-+]{3} [ab]/(.*)"
));
QStringList
left
;
QStringList
right
;
...
...
@@ -129,20 +220,39 @@ void DiffWidget::openDiff(const QByteArray &raw)
QVector
<
int
>
lineToLineNumLeft
;
QVector
<
int
>
lineToLineNumRight
;
QVector
<
HunkChangedLine
>
hunkChangedLinesA
;
QVector
<
HunkChangedLine
>
hunkChangedLinesB
;
QSet
<
QString
>
mimeTypes
;
QString
srcFile
;
QString
tgtFile
;
int
maxLineNoFound
=
0
;
// int lineNo = 0;
int
lineA
=
0
;
int
lineB
=
0
;
for
(
int
i
=
0
;
i
<
text
.
size
();
++
i
)
{
const
QString
&
line
=
text
.
at
(
i
);
const
auto
match
=
HUNK_HEADER_RE
.
match
(
line
);
auto
match
=
DIFF_FILENAME_RE
.
match
(
line
);
if
(
match
.
hasMatch
())
{
if
(
line
.
startsWith
(
QLatin1Char
(
'-'
)))
{
srcFile
=
match
.
captured
(
1
);
}
else
if
(
line
.
startsWith
(
QLatin1Char
(
'+'
)))
{
tgtFile
=
match
.
captured
(
1
);
}
if
(
!
match
.
captured
(
1
).
isEmpty
())
{
mimeTypes
.
insert
(
QMimeDatabase
().
mimeTypeForFile
(
match
.
captured
(
1
),
QMimeDatabase
::
MatchExtension
).
name
());
}
continue
;
}
match
=
HUNK_HEADER_RE
.
match
(
line
);
if
(
!
match
.
hasMatch
())
continue
;
const
auto
oldRange
=
parseRange
(
match
.
captured
(
1
));
const
auto
newRange
=
parseRange
(
match
.
captured
(
2
));
const
QString
headingLeft
=
QStringLiteral
(
"@@ "
)
+
match
.
captured
(
1
)
+
match
.
captured
(
3
);
const
QString
headingRight
=
QStringLiteral
(
"@@ "
)
+
match
.
captured
(
2
)
+
match
.
captured
(
3
);
const
QString
headingLeft
=
QStringLiteral
(
"@@ "
)
+
match
.
captured
(
1
)
+
match
.
captured
(
3
)
/* + QStringLiteral(" ") + srcFile*/
;
const
QString
headingRight
=
QStringLiteral
(
"@@ "
)
+
match
.
captured
(
2
)
+
match
.
captured
(
3
)
/* + QStringLiteral(" ") + tgtFile*/
;
lineToLineNumLeft
.
append
(
-
1
);
lineToLineNumRight
.
append
(
-
1
);
...
...
@@ -151,6 +261,9 @@ void DiffWidget::openDiff(const QByteArray &raw)
lineA
++
;
lineB
++
;
hunkChangedLinesA
.
clear
();
hunkChangedLinesB
.
clear
();
int
srcLine
=
oldRange
.
first
;
const
int
oldCount
=
oldRange
.
second
;
...
...
@@ -163,6 +276,7 @@ void DiffWidget::openDiff(const QByteArray &raw)
if
(
l
.
startsWith
(
QLatin1Char
(
' '
)))
{
// Insert dummy lines when left/right are unequal
balanceHunkLines
(
left
,
right
,
lineA
,
lineB
,
lineToLineNumLeft
,
lineToLineNumRight
);
markInlineDiffs
(
hunkChangedLinesA
,
hunkChangedLinesB
,
leftHlts
,
rightHlts
);
l
=
l
.
mid
(
1
);
left
.
append
(
l
);
...
...
@@ -183,6 +297,8 @@ void DiffWidget::openDiff(const QByteArray &raw)
lineToLineNumRight
.
append
(
tgtLine
++
);
right
.
append
(
l
);
hunkChangedLinesB
.
append
({
l
,
true
,
lineB
});
// lineNo++;
lineB
++
;
}
else
if
(
l
.
startsWith
(
QLatin1Char
(
'-'
)))
{
...
...
@@ -196,10 +312,14 @@ void DiffWidget::openDiff(const QByteArray &raw)
leftHlts
.
push_back
(
h
);
lineToLineNumLeft
.
append
(
srcLine
++
);
left
.
append
(
l
);
hunkChangedLinesA
.
append
({
l
,
false
,
lineA
});
lineA
++
;
}
else
if
(
l
.
startsWith
(
QStringLiteral
(
"@@ "
))
&&
HUNK_HEADER_RE
.
match
(
l
).
hasMatch
())
{
i
=
j
-
1
;
markInlineDiffs
(
hunkChangedLinesA
,
hunkChangedLinesB
,
leftHlts
,
rightHlts
);
// add line number for current line
lineToLineNumLeft
.
append
(
-
1
);
lineToLineNumRight
.
append
(
-
1
);
...
...
@@ -212,6 +332,7 @@ void DiffWidget::openDiff(const QByteArray &raw)
break
;
}
if
(
j
+
1
>=
text
.
size
())
{
markInlineDiffs
(
hunkChangedLinesA
,
hunkChangedLinesB
,
leftHlts
,
rightHlts
);
i
=
j
;
// ensure outer loop also exits after this
}
}
...
...
@@ -222,13 +343,22 @@ void DiffWidget::openDiff(const QByteArray &raw)
QString
leftText
=
left
.
join
(
QLatin1Char
(
'\n'
));
QString
rightText
=
right
.
join
(
QLatin1Char
(
'\n'
));
// printf("(%d), lt %d ln %d -- rt %d rn %d\n", lineNo, left.size(), lineToLineNumLeft.size(), right.size(), lineToLineNumRight.size());
m_left
->
appendData
(
leftHlts
);
m_right
->
appendData
(
rightHlts
);
m_left
->
appendPlainText
(
leftText
);
m_right
->
appendPlainText
(
rightText
);
m_left
->
setLineNumberData
(
lineToLineNumLeft
,
maxLineNoFound
);
m_right
->
setLineNumberData
(
lineToLineNumRight
,
maxLineNoFound
);
// Only do highlighting if there is one mimetype found, multiple different files not supported
if
(
mimeTypes
.
size
()
==
1
)
{
const
auto
def
=
KTextEditor
::
Editor
::
instance
()
->
repository
().
definitionForMimeType
(
*
mimeTypes
.
begin
());
leftHl
->
setDefinition
(
def
);
rightHl
->
setDefinition
(
def
);
}
else
{
const
auto
def
=
KTextEditor
::
Editor
::
instance
()
->
repository
().
definitionForMimeType
(
QStringLiteral
(
"None"
));
leftHl
->
setDefinition
(
def
);
rightHl
->
setDefinition
(
def
);
}
}
void
DiffWidget
::
openWordDiff
(
const
QByteArray
&
raw
)
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment