LexDiff.cpp 5.8 KB

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