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
);
54 else if (lineBuffer
[3] == ' ')
55 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
57 styler
.ColourTo(endLine
, SCE_DIFF_DELETED
);
58 } else if (0 == strncmp(lineBuffer
, "+++ ", 4)) {
59 // I don't know of any diff where "+++ " is a position marker, but for
60 // consistency, do the same as with "--- " and "*** ".
61 if (atoi(lineBuffer
+4) && !strchr(lineBuffer
, '/'))
62 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
64 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
65 } else if (0 == strncmp(lineBuffer
, "====", 4)) { // For p4's diff
66 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
67 } else if (0 == strncmp(lineBuffer
, "***", 3)) {
68 // In a context diff, *** appears in both the header and the position markers.
69 // Also ******** is a chunk header, but here it's treated as part of the
70 // position marker since there is no separate style for a chunk header.
71 if (lineBuffer
[3] == ' ' && atoi(lineBuffer
+4) && !strchr(lineBuffer
, '/'))
72 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
73 else if (lineBuffer
[3] == '*')
74 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
76 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
77 } else if (0 == strncmp(lineBuffer
, "? ", 2)) { // For difflib
78 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
79 } else if (lineBuffer
[0] == '@') {
80 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
81 } else if (lineBuffer
[0] >= '0' && lineBuffer
[0] <= '9') {
82 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
83 } else if (lineBuffer
[0] == '-' || lineBuffer
[0] == '<') {
84 styler
.ColourTo(endLine
, SCE_DIFF_DELETED
);
85 } else if (lineBuffer
[0] == '+' || lineBuffer
[0] == '>') {
86 styler
.ColourTo(endLine
, SCE_DIFF_ADDED
);
87 } else if (lineBuffer
[0] == '!') {
88 styler
.ColourTo(endLine
, SCE_DIFF_CHANGED
);
89 } else if (lineBuffer
[0] != ' ') {
90 styler
.ColourTo(endLine
, SCE_DIFF_COMMENT
);
92 styler
.ColourTo(endLine
, SCE_DIFF_DEFAULT
);
96 static void ColouriseDiffDoc(Sci_PositionU startPos
, Sci_Position length
, int, WordList
*[], Accessor
&styler
) {
97 char lineBuffer
[DIFF_BUFFER_START_SIZE
] = "";
98 styler
.StartAt(startPos
);
99 styler
.StartSegment(startPos
);
100 Sci_PositionU linePos
= 0;
101 for (Sci_PositionU i
= startPos
; i
< startPos
+ length
; i
++) {
102 if (AtEOL(styler
, i
)) {
103 if (linePos
< DIFF_BUFFER_START_SIZE
) {
104 lineBuffer
[linePos
] = 0;
106 ColouriseDiffLine(lineBuffer
, i
, styler
);
108 } else if (linePos
< DIFF_BUFFER_START_SIZE
- 1) {
109 lineBuffer
[linePos
++] = styler
[i
];
110 } else if (linePos
== DIFF_BUFFER_START_SIZE
- 1) {
111 lineBuffer
[linePos
++] = 0;
114 if (linePos
> 0) { // Last line does not have ending characters
115 if (linePos
< DIFF_BUFFER_START_SIZE
) {
116 lineBuffer
[linePos
] = 0;
118 ColouriseDiffLine(lineBuffer
, startPos
+ length
- 1, styler
);
122 static void FoldDiffDoc(Sci_PositionU startPos
, Sci_Position length
, int, WordList
*[], Accessor
&styler
) {
123 Sci_Position curLine
= styler
.GetLine(startPos
);
124 Sci_Position curLineStart
= styler
.LineStart(curLine
);
125 int prevLevel
= curLine
> 0 ? styler
.LevelAt(curLine
- 1) : SC_FOLDLEVELBASE
;
129 const int lineType
= styler
.StyleAt(curLineStart
);
130 if (lineType
== SCE_DIFF_COMMAND
)
131 nextLevel
= SC_FOLDLEVELBASE
| SC_FOLDLEVELHEADERFLAG
;
132 else if (lineType
== SCE_DIFF_HEADER
)
133 nextLevel
= (SC_FOLDLEVELBASE
+ 1) | SC_FOLDLEVELHEADERFLAG
;
134 else if (lineType
== SCE_DIFF_POSITION
&& styler
[curLineStart
] != '-')
135 nextLevel
= (SC_FOLDLEVELBASE
+ 2) | SC_FOLDLEVELHEADERFLAG
;
136 else if (prevLevel
& SC_FOLDLEVELHEADERFLAG
)
137 nextLevel
= (prevLevel
& SC_FOLDLEVELNUMBERMASK
) + 1;
139 nextLevel
= prevLevel
;
141 if ((nextLevel
& SC_FOLDLEVELHEADERFLAG
) && (nextLevel
== prevLevel
))
142 styler
.SetLevel(curLine
-1, prevLevel
& ~SC_FOLDLEVELHEADERFLAG
);
144 styler
.SetLevel(curLine
, nextLevel
);
145 prevLevel
= nextLevel
;
147 curLineStart
= styler
.LineStart(++curLine
);
148 } while (static_cast<Sci_Position
>(startPos
)+length
> curLineStart
);
151 static const char *const emptyWordListDesc
[] = {
155 LexerModule
lmDiff(SCLEX_DIFF
, ColouriseDiffDoc
, "diff", FoldDiffDoc
, emptyWordListDesc
);