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