Menu

#2062 Incorrect highlight of C/C++ code in multiline #if macro.

Bug
closed-fixed
5
2019-01-11
2018-11-20
No

Paste the following code in SciTe

#include <stdio.h>
#include <stdlib.h>

#define DEFINE5

#if defined(DEFINE1) || defined(DEFINE2) || \
    defined(DEFINE3) || defined(DEFINE4) || \
    defined(DEFINE5)

void test_function(int p1, int p2);

#endif

int main()
{
    printf("Hello world!\n");
    return 0;
}

When DEFINE3, DEFINE4 or DEFINE5 are defined but no DEFINE1 or DEFINE2 the code between the #if and #endif is shown grayed out.

I've tried this in
SciTE Version 4.1.2 compiled for GTK+ 3.24.1
In Debian testing (Buster).

The following diff shows a hack that makes it work correctly.

Index: lexers/LexCPP.cxx
===================================================================
--- lexers/LexCPP.cxx (revisión: 11511)
+++ lexers/LexCPP.cxx (copia de trabajo)
@@ -203,12 +203,26 @@
    std::string restOfLine;
    Sci_Position i =0;
    char ch = styler.SafeGetCharAt(start, '\n');
-   const Sci_Position endLine = styler.LineEnd(styler.GetLine(start));
+   Sci_Position endLine = styler.LineEnd(styler.GetLine(start));
    while (((start+i) < endLine) && (ch != '\r')) {
        const char chNext = styler.SafeGetCharAt(start + i + 1, '\n');
        if (ch == '/' && (chNext == '/' || chNext == '*'))
            break;
-       if (allowSpace || (ch != ' '))
+       if (ch == '\\' && (chNext == '\r' || chNext == '\n')) {
+           i++;
+           const char chNext2 = styler.SafeGetCharAt(start + i + 1, '\n');
+           if (chNext == '\r' && chNext2 == '\n') { // Windows line endings
+               i++;
+               ch = styler.SafeGetCharAt(start + i + 1, '\n');
+           } else if (chNext == '\r' && chNext2 != '\n') { // MAC line endings
+               ch = chNext2;
+           } else if (chNext == '\n') { // Unix line endings
+               ch = chNext2;
+           }
+           endLine = styler.LineEnd(styler.GetLine(start + i + 1));
+           i++;
+           continue;
+       } else if (allowSpace || (ch != ' '))
            restOfLine += ch;
        i++;
        ch = chNext;

Discussion

  • Neil Hodgson

    Neil Hodgson - 2018-11-30

    That patch has a bunch of special cases for the three common line end types and isn't robust if it needs to handle other line ends like NEL, PS, or LS.

    I'd prefer to use the fact that styler.LineEnd() knows about the different line ends and check that againt the current position, producing something more like this:

    --- a/lexers/LexCPP.cxx Thu Nov 29 07:50:35 2018 +1100
    +++ b/lexers/LexCPP.cxx Fri Nov 30 17:12:56 2018 +1100
    @@ -201,17 +201,27 @@
    
     std::string GetRestOfLine(LexAccessor &styler, Sci_Position start, bool allowSpace) {
        std::string restOfLine;
    -   Sci_Position i =0;
    +   Sci_Position line = styler.GetLine(start);
    +   Sci_Position pos = start;
    +   Sci_Position endLine = styler.LineEnd(line);
        char ch = styler.SafeGetCharAt(start, '\n');
    -   const Sci_Position endLine = styler.LineEnd(styler.GetLine(start));
    -   while (((start+i) < endLine) && (ch != '\r')) {
    -       const char chNext = styler.SafeGetCharAt(start + i + 1, '\n');
    -       if (ch == '/' && (chNext == '/' || chNext == '*'))
    -           break;
    -       if (allowSpace || (ch != ' '))
    -           restOfLine += ch;
    -       i++;
    -       ch = chNext;
    +   while (pos < endLine) {
    +       if (ch == '\\' && ((pos + 1) == endLine)) {
    +           // Continuation line
    +           line++;
    +           pos = styler.LineStart(line);
    +           endLine = styler.LineEnd(line);
    +           ch = styler.SafeGetCharAt(pos, '\n');
    +       } else {
    +           const char chNext = styler.SafeGetCharAt(pos + 1, '\n');
    +           if (ch == '/' && (chNext == '/' || chNext == '*'))
    +               break;
    +           if (allowSpace || (ch != ' ')) {
    +               restOfLine += ch;
    +           }
    +           pos++;
    +           ch = chNext;
    +       }
        }
        return restOfLine;
     }
    

    This worked on all the test cases I tried but you should test it further.

     
    • Fabián Inostroza

      Hi,
      Your patch is working fine, thanks.

       
  • Neil Hodgson

    Neil Hodgson - 2018-12-03
    • status: open --> open-fixed
    • assigned_to: Neil Hodgson
     
  • Neil Hodgson

    Neil Hodgson - 2018-12-03

    Committed fix as [a40b6a].

    Note that this fix does not force relexing of the whole logical line if the user edits a continuation line.

     

    Related

    Commit: [a40b6a]

  • Neil Hodgson

    Neil Hodgson - 2019-01-11
    • status: open-fixed --> closed-fixed
     

Log in to post a comment.