1 // Scintilla source code edit control
3 ** Lexer for diff results.
5 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
16 #include "Scintilla.h"
20 #include "LexAccessor.h"
22 #include "StyleContext.h"
23 #include "CharacterSet.h"
24 #include "LexerModule.h"
27 using namespace Scintilla
;
30 static inline bool AtEOL(Accessor
&styler
, Sci_PositionU i
) {
31 return (styler
[i
] == '\n') ||
32 ((styler
[i
] == '\r') && (styler
.SafeGetCharAt(i
+ 1) != '\n'));
35 #define DIFF_BUFFER_START_SIZE 16
36 // Note that ColouriseDiffLine analyzes only the first DIFF_BUFFER_START_SIZE
37 // characters of each line to classify the line.
39 static void ColouriseDiffLine(char *lineBuffer
, Sci_Position endLine
, Accessor
&styler
) {
40 // It is needed to remember the current state to recognize starting
41 // comment lines before the first "diff " or "--- ". If a real
42 // difference starts then each line starting with ' ' is a whitespace
43 // otherwise it is considered a comment (Only in..., Binary file...)
44 if (0 == strncmp(lineBuffer
, "diff ", 5)) {
45 styler
.ColourTo(endLine
, SCE_DIFF_COMMAND
);
46 } else if (0 == strncmp(lineBuffer
, "Index: ", 7)) { // For subversion's diff
47 styler
.ColourTo(endLine
, SCE_DIFF_COMMAND
);
48 } else if (0 == strncmp(lineBuffer
, "---", 3) && lineBuffer
[3] != '-') {
49 // In a context diff, --- appears in both the header and the position markers
50 if (lineBuffer
[3] == ' ' && atoi(lineBuffer
+ 4) && !strchr(lineBuffer
, '/'))
51 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
52 else if (lineBuffer
[3] == '\r' || lineBuffer
[3] == '\n')
53 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
55 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
56 } else if (0 == strncmp(lineBuffer
, "+++ ", 4)) {
57 // I don't know of any diff where "+++ " is a position marker, but for
58 // consistency, do the same as with "--- " and "*** ".
59 if (atoi(lineBuffer
+4) && !strchr(lineBuffer
, '/'))
60 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
62 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
63 } else if (0 == strncmp(lineBuffer
, "====", 4)) { // For p4's diff
64 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
65 } else if (0 == strncmp(lineBuffer
, "***", 3)) {
66 // In a context diff, *** appears in both the header and the position markers.
67 // Also ******** is a chunk header, but here it's treated as part of the
68 // position marker since there is no separate style for a chunk header.
69 if (lineBuffer
[3] == ' ' && atoi(lineBuffer
+4) && !strchr(lineBuffer
, '/'))
70 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
71 else if (lineBuffer
[3] == '*')
72 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
74 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
75 } else if (0 == strncmp(lineBuffer
, "? ", 2)) { // For difflib
76 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
77 } else if (lineBuffer
[0] == '@') {
78 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
79 } else if (lineBuffer
[0] >= '0' && lineBuffer
[0] <= '9') {
80 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
81 } else if (lineBuffer
[0] == '-' || lineBuffer
[0] == '<') {
82 styler
.ColourTo(endLine
, SCE_DIFF_DELETED
);
83 } else if (lineBuffer
[0] == '+' || lineBuffer
[0] == '>') {
84 styler
.ColourTo(endLine
, SCE_DIFF_ADDED
);
85 } else if (lineBuffer
[0] == '!') {
86 styler
.ColourTo(endLine
, SCE_DIFF_CHANGED
);
87 } else if (lineBuffer
[0] != ' ') {
88 styler
.ColourTo(endLine
, SCE_DIFF_COMMENT
);
90 styler
.ColourTo(endLine
, SCE_DIFF_DEFAULT
);
94 static void ColouriseDiffDoc(Sci_PositionU startPos
, Sci_Position length
, int, WordList
*[], Accessor
&styler
) {
95 char lineBuffer
[DIFF_BUFFER_START_SIZE
] = "";
96 styler
.StartAt(startPos
);
97 styler
.StartSegment(startPos
);
98 Sci_PositionU linePos
= 0;
99 for (Sci_PositionU i
= startPos
; i
< startPos
+ length
; i
++) {
100 if (AtEOL(styler
, i
)) {
101 if (linePos
< DIFF_BUFFER_START_SIZE
) {
102 lineBuffer
[linePos
] = 0;
104 ColouriseDiffLine(lineBuffer
, i
, styler
);
106 } else if (linePos
< DIFF_BUFFER_START_SIZE
- 1) {
107 lineBuffer
[linePos
++] = styler
[i
];
108 } else if (linePos
== DIFF_BUFFER_START_SIZE
- 1) {
109 lineBuffer
[linePos
++] = 0;
112 if (linePos
> 0) { // Last line does not have ending characters
113 if (linePos
< DIFF_BUFFER_START_SIZE
) {
114 lineBuffer
[linePos
] = 0;
116 ColouriseDiffLine(lineBuffer
, startPos
+ length
- 1, styler
);
120 static void FoldDiffDoc(Sci_PositionU startPos
, Sci_Position length
, int, WordList
*[], Accessor
&styler
) {
121 Sci_Position curLine
= styler
.GetLine(startPos
);
122 Sci_Position curLineStart
= styler
.LineStart(curLine
);
123 int prevLevel
= curLine
> 0 ? styler
.LevelAt(curLine
- 1) : SC_FOLDLEVELBASE
;
127 int lineType
= styler
.StyleAt(curLineStart
);
128 if (lineType
== SCE_DIFF_COMMAND
)
129 nextLevel
= SC_FOLDLEVELBASE
| SC_FOLDLEVELHEADERFLAG
;
130 else if (lineType
== SCE_DIFF_HEADER
)
131 nextLevel
= (SC_FOLDLEVELBASE
+ 1) | SC_FOLDLEVELHEADERFLAG
;
132 else if (lineType
== SCE_DIFF_POSITION
&& styler
[curLineStart
] != '-')
133 nextLevel
= (SC_FOLDLEVELBASE
+ 2) | SC_FOLDLEVELHEADERFLAG
;
134 else if (prevLevel
& SC_FOLDLEVELHEADERFLAG
)
135 nextLevel
= (prevLevel
& SC_FOLDLEVELNUMBERMASK
) + 1;
137 nextLevel
= prevLevel
;
139 if ((nextLevel
& SC_FOLDLEVELHEADERFLAG
) && (nextLevel
== prevLevel
))
140 styler
.SetLevel(curLine
-1, prevLevel
& ~SC_FOLDLEVELHEADERFLAG
);
142 styler
.SetLevel(curLine
, nextLevel
);
143 prevLevel
= nextLevel
;
145 curLineStart
= styler
.LineStart(++curLine
);
146 } while (static_cast<Sci_Position
>(startPos
)+length
> curLineStart
);
149 static const char *const emptyWordListDesc
[] = {
153 LexerModule
lmDiff(SCLEX_DIFF
, ColouriseDiffDoc
, "diff", FoldDiffDoc
, emptyWordListDesc
);