FLTK logo

[master] bcfa407 - Merge pull request #139 from erco77/issue135-1.4.x

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[master] bcfa407 - Merge pull request #139 from erco77/issue135-1.4.x "erco77" Oct 21, 2020  
 
commit bcfa407b6ba104cc7701efdeed3a11808bedb2dc
Merge: f718943 bedda58
Author:     erco77 <erco@seriss.com>
AuthorDate: Wed Oct 21 19:38:16 2020 -0700
Commit:     GitHub <noreply@github.com>
CommitDate: Wed Oct 21 19:38:16 2020 -0700

    Merge pull request #139 from erco77/issue135-1.4.x
    
    Rewrite CodeEditor syntax highlighting for issue #135

commit bedda5807e74bbc9f96ee1c446f89923c828a57b
Author:     Greg Ercolano <erco@seriss.com>
AuthorDate: Sun Sep 20 16:05:16 2020 -0700
Commit:     Greg Ercolano <erco@seriss.com>
CommitDate: Mon Oct 19 23:59:56 2020 -0700

    Handle single quotes

commit 0ceedf3bd6f6b13b096dc3c34d8f31b5e0376aa0
Author:     Greg Ercolano <erco@seriss.com>
AuthorDate: Sat Sep 19 10:43:27 2020 -0700
Commit:     Greg Ercolano <erco@seriss.com>
CommitDate: Mon Oct 19 23:59:50 2020 -0700

    Mods for Albrecht's 09/19/20 code review

commit 13baaf3d5d61f1196c49a0cf6f3eb69c241c8dcf
Author:     Greg Ercolano <erco@seriss.com>
AuthorDate: Thu Sep 17 23:57:14 2020 -0700
Commit:     Greg Ercolano <erco@seriss.com>
CommitDate: Thu Sep 17 23:57:14 2020 -0700

    Code cleanup: moved keyword/type arrays to StyleParse
    
    Needed to do this to prevent lower StyleParse class from #including upper CodeEditor.

commit 2f6034b68a1d96b3b0269407fee1016c6a599a6a
Author:     Greg Ercolano <erco@seriss.com>
AuthorDate: Wed Sep 16 09:33:24 2020 -0700
Commit:     Greg Ercolano <erco@seriss.com>
CommitDate: Wed Sep 16 09:33:24 2020 -0700

    Rewrite CodeEditor syntax highlighting for issue #135

 fluid/CMakeLists.txt |   1 +
 fluid/CodeEditor.cxx | 316 ++++++++++---------------------------------------
 fluid/CodeEditor.h   |  28 ++---
 fluid/Makefile       |   1 +
 fluid/StyleParse.cxx | 327 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fluid/StyleParse.h   |  61 ++++++++++
 6 files changed, 463 insertions(+), 271 deletions(-)

diff --git fluid/CMakeLists.txt fluid/CMakeLists.txt
index cbe0435..d429aff 100644
--- fluid/CMakeLists.txt
+++ fluid/CMakeLists.txt
@@ -18,6 +18,7 @@ if (NOT ANDROID)
 
 set (CPPFILES
   CodeEditor.cxx
+  StyleParse.cxx
   Fl_Function_Type.cxx
   Fl_Group_Type.cxx
   Fl_Menu_Type.cxx
diff --git fluid/CodeEditor.cxx fluid/CodeEditor.cxx
index 4dd1cef..3d7d475 100644
--- fluid/CodeEditor.cxx
+++ fluid/CodeEditor.cxx
@@ -1,7 +1,8 @@
 //
 // Code editor widget for the Fast Light Tool Kit (FLTK).
+// Syntax highlighting rewritten by erco@seriss.com 09/15/20.
 //
-// Copyright 1998-2016 by Bill Spitzak and others.
+// Copyright 1998-2020 by Bill Spitzak and others.
 //
 // This library is free software. Distribution and use rights are outlined in
 // the file "COPYING" which should have been included with this file.  If this
@@ -24,7 +25,6 @@
 #include <ctype.h>
 #include "CodeEditor.h"
 
-
 Fl_Text_Display::Style_Table_Entry CodeEditor::
                 styletable[] = {        // Style table
                   { FL_FOREGROUND_COLOR, FL_COURIER,        11 }, // A - Plain
@@ -33,83 +33,8 @@ Fl_Text_Display::Style_Table_Entry CodeEditor::
                   { FL_BLUE,             FL_COURIER,        11 }, // D - Strings
                   { FL_DARK_RED,         FL_COURIER,        11 }, // E - Directives
                   { FL_DARK_RED,         FL_COURIER_BOLD,   11 }, // F - Types
-                  { FL_BLUE,             FL_COURIER_BOLD,   11 }  // G - Keywords
-                };
-const char * const CodeEditor::
-                code_keywords[] = {     // Sorted list of C/C++ keywords...
-                  "and",
-                  "and_eq",
-                  "asm",
-                  "bitand",
-                  "bitor",
-                  "break",
-                  "case",
-                  "catch",
-                  "compl",
-                  "continue",
-                  "default",
-                  "delete",
-                  "do",
-                  "else",
-                  "false",
-                  "for",
-                  "goto",
-                  "if",
-                  "new",
-                  "not",
-                  "not_eq",
-                  "operator",
-                  "or",
-                  "or_eq",
-                  "return",
-                  "switch",
-                  "template",
-                  "this",
-                  "throw",
-                  "true",
-                  "try",
-                  "while",
-                  "xor",
-                  "xor_eq"
-                };
-const char * const CodeEditor::
-                code_types[] = {        // Sorted list of C/C++ types...
-                  "auto",
-                  "bool",
-                  "char",
-                  "class",
-                  "const",
-                  "const_cast",
-                  "double",
-                  "dynamic_cast",
-                  "enum",
-                  "explicit",
-                  "extern",
-                  "float",
-                  "friend",
-                  "inline",
-                  "int",
-                  "long",
-                  "mutable",
-                  "namespace",
-                  "private",
-                  "protected",
-                  "public",
-                  "register",
-                  "short",
-                  "signed",
-                  "sizeof",
-                  "static",
-                  "static_cast",
-                  "struct",
-                  "template",
-                  "typedef",
-                  "typename",
-                  "union",
-                  "unsigned",
-                  "virtual",
-                  "void",
-                  "volatile"
+                  { FL_BLUE,             FL_COURIER_BOLD,   11 }, // G - Keywords
+                  { 220, /* med cyan */  FL_COURIER,        11 }  // H - Single quote chars
                 };
 
 // attempt to make the fluid code editor widget honour textsize setting
@@ -123,139 +48,53 @@ void CodeEditor::textsize(Fl_Fontsize s) {
 } // textsize
 
 
-// 'compare_keywords()' - Compare two keywords...
-extern "C" {
-  static int compare_keywords(const void *a, const void *b) {
-    return strcmp(*((const char **)a), *((const char **)b));
-  }
-}
-
 // 'style_parse()' - Parse text and produce style data.
-void CodeEditor::style_parse(const char *text, char *style, int length) {
-  char          current;
-  int           col;
-  int           last;
-  char          buf[255],
-                *bufptr;
-  const char    *temp;
-
+void CodeEditor::style_parse(const char *in_tbuff,         // text buffer to parse
+                             char       *in_sbuff,         // style buffer we modify
+                             int         in_len,           // byte length to parse
+                             char        in_style) {       // starting style letter
   // Style letters:
   //
-  // A - Plain
-  // B - Line comments
-  // C - Block comments
-  // D - Strings
-  // E - Directives
-  // F - Types
-  // G - Keywords
-
-  for (current = *style, col = 0, last = 0; length > 0; length --, text ++) {
-    if (current == 'B' || current == 'F' || current == 'G') current = 'A';
-    if (current == 'A') {
-      // Check for directives, comments, strings, and keywords...
-      if (col == 0 && *text == '#') {
-        // Set style to directive
-        current = 'E';
-      } else if (strncmp(text, "//", 2) == 0) {
-        current = 'B';
-        for (; length > 0 && *text != '\n'; length --, text ++) *style++ = 'B';
-
-        if (length == 0) break;
-      } else if (strncmp(text, "/*", 2) == 0) {
-        current = 'C';
-      } else if (strncmp(text, "\\\"", 2) == 0) {
-        // Quoted quote...
-        *style++ = current;
-        *style++ = current;
-        text ++;
-        length --;
-        col += 2;
-        continue;
-      } else if (*text == '\"') {
-        current = 'D';
-      } else if (!last && (islower(*text) || *text == '_')) {
-        // Might be a keyword...
-        for (temp = text, bufptr = buf;
-             (islower(*temp) || *temp == '_') && bufptr < (buf + sizeof(buf) - 1);
-             *bufptr++ = *temp++) {
-          // nothing
-        }
-
-        if (!islower(*temp) && *temp != '_') {
-          *bufptr = '\0';
-
-          bufptr = buf;
-
-          if (bsearch(&bufptr, code_types,
-                      sizeof(code_types) / sizeof(code_types[0]),
-                      sizeof(code_types[0]), compare_keywords)) {
-            while (text < temp) {
-              *style++ = 'F';
-              text ++;
-              length --;
-              col ++;
-            }
-
-            text --;
-            length ++;
-            last = 1;
-            continue;
-          } else if (bsearch(&bufptr, code_keywords,
-                             sizeof(code_keywords) / sizeof(code_keywords[0]),
-                             sizeof(code_keywords[0]), compare_keywords)) {
-            while (text < temp) {
-              *style++ = 'G';
-              text ++;
-              length --;
-              col ++;
-            }
-
-            text --;
-            length ++;
-            last = 1;
-            continue;
-          }
-        }
-      }
-    } else if (current == 'C' && strncmp(text, "*/", 2) == 0) {
-      // Close a C comment...
-      *style++ = current;
-      *style++ = current;
-      text ++;
-      length --;
-      current = 'A';
-      col += 2;
-      continue;
-    } else if (current == 'D') {
-      // Continuing in string...
-      if (strncmp(text, "\\\"", 2) == 0) {
-        // Quoted end quote...
-        *style++ = current;
-        *style++ = current;
-        text ++;
-        length --;
-        col += 2;
-        continue;
-      } else if (*text == '\"') {
-        // End quote...
-        *style++ = current;
-        col ++;
-        current = 'A';
-        continue;
-      }
-    }
-
-    // Copy style info...
-    if (current == 'A' && (*text == '{' || *text == '}')) *style++ = 'G';
-    else *style++ = current;
-    col ++;
-
-    last = isalnum(*text) || *text == '_' || *text == '.';
-
-    if (*text == '\n') {
-      // Reset column and possibly reset the style
-      col = 0;
-      if (current == 'B' || current == 'E') current = 'A';
+  // 'A' - Plain
+  // 'B' - Line comments  // ..
+  // 'C' - Block comments /*..*/
+  // 'D' - Strings        "xxx"
+  // 'E' - Directives     #define, #include..
+  // 'F' - Types          void, char..
+  // 'G' - Keywords       if, while..
+  // 'H' - Chars          'x'
+
+  StyleParse sp;
+  sp.tbuff  = in_tbuff;
+  sp.sbuff  = in_sbuff;
+  sp.len    = in_len;
+  sp.style  = in_style;
+  sp.lwhite = 1;        // 1:while parsing over leading white and first char past, 0:past white
+  sp.col    = 0;
+  sp.last   = 0;
+
+  // Loop through the code, updating style buffer
+  char c;
+  while ( sp.len > 0 ) {
+    c = sp.tbuff[0];  // current char
+    if ( sp.style == 'C' ) {                              // Started in middle of comment block?
+      if ( !sp.parse_block_comment() ) break;
+    } else if ( strncmp(sp.tbuff, "/*", 2)==0 ) {         // C style comment block?
+      if ( !sp.parse_block_comment() ) break;
+    } else if ( c == '\\' ) {                             // Backslash escape char?
+      if ( !sp.parse_escape() ) break;
+    } else if ( strncmp(sp.tbuff, "//", 2)==0 ) {         // Line comment?
+      if ( !sp.parse_line_comment() ) break;
+    } else if ( c == '"' ) {                              // Start of double quoted string?
+      if ( !sp.parse_quoted_string('"', 'D') ) break;
+    } else if ( c == '\'' ) {                             // Start of single quoted string?
+      if ( !sp.parse_quoted_string('\'', 'H') ) break;
+    } else if ( c == '#' && sp.lwhite ) {                 // Start of '#' directive?
+      if ( !sp.parse_directive() ) break;
+    } else if ( !sp.last && (islower(c) || c == '_') ) {  // Possible C/C++ keyword?
+      if ( !sp.parse_keyword() ) break;
+    } else {                                              // All other chars?
+      if ( !sp.parse_all_else() ) break;
     }
   }
 }
@@ -267,12 +106,9 @@ void CodeEditor::style_unfinished_cb(int, void*) { }
 void CodeEditor::style_update(int pos, int nInserted, int nDeleted,
                               int /*nRestyled*/, const char * /*deletedText*/,
                               void *cbArg) {
-  CodeEditor    *editor = (CodeEditor *)cbArg;
-  int           start,                          // Start of text
-                end;                            // End of text
-  char          last,                           // Last style on line
-                *style,                         // Style data
-                *text;                          // Text data
+  CodeEditor *editor = (CodeEditor*)cbArg;
+  char       *style,                         // Style data
+             *text;                          // Text data
 
 
   // If this is just a selection change, just unselect the style buffer...
@@ -299,48 +135,16 @@ void CodeEditor::style_update(int pos, int nInserted, int nDeleted,
   // callbacks...
   editor->mStyleBuffer->select(pos, pos + nInserted - nDeleted);
 
-  // Re-parse the changed region; we do this by parsing from the
-  // beginning of the line of the changed region to the end of
-  // the line of the changed region...  Then we check the last
-  // style character and keep updating if we have a multi-line
-  // comment character...
-  start = editor->mBuffer->line_start(pos);
-  // the following code checks the style of the last character of the previous
-  // line. If it is a block comment, the previous line is interpreted as well.
-  int altStart = editor->mBuffer->prev_char(start);
-  if (altStart>0) {
-    altStart = editor->mBuffer->prev_char(altStart);
-    if (altStart>=0 && editor->mStyleBuffer->byte_at(start-2)=='C')
-      start = editor->mBuffer->line_start(altStart);
-  }
-  end   = editor->mBuffer->line_end(pos + nInserted);
-  text  = editor->mBuffer->text_range(start, end);
-  style = editor->mStyleBuffer->text_range(start, end);
-  if (start==end)
-    last = 0;
-  else
-    last  = style[end - start - 1];
-
-  style_parse(text, style, end - start);
+  // Reparse whole buffer, don't get cute. Maybe optimize range later
+  int len = editor->buffer()->length();
+  text  = editor->mBuffer->text_range(0, len);
+  style = editor->mStyleBuffer->text_range(0, len);
 
-  editor->mStyleBuffer->replace(start, end, style);
-  editor->redisplay_range(start, end);
+  style_parse(text, style, editor->mBuffer->length(), 'A');
 
-  if (start==end || last != style[end - start - 1]) {
-    // The last character on the line changed styles, so reparse the
-    // remainder of the buffer...
-    free(text);
-    free(style);
-
-    end   = editor->mBuffer->length();
-    text  = editor->mBuffer->text_range(start, end);
-    style = editor->mStyleBuffer->text_range(start, end);
-
-    style_parse(text, style, end - start);
-
-    editor->mStyleBuffer->replace(start, end, style);
-    editor->redisplay_range(start, end);
-  }
+  editor->mStyleBuffer->replace(0, len, style);
+  editor->redisplay_range(0, len);
+  editor->redraw();
 
   free(text);
   free(style);
@@ -394,7 +198,7 @@ CodeEditor::CodeEditor(int X, int Y, int W, int H, const char *L) :
                  sizeof(styletable) / sizeof(styletable[0]),
                  'A', style_unfinished_cb, this);
 
-  style_parse(text, style, mBuffer->length());
+  style_parse(text, style, mBuffer->length(), 'A');
 
   mStyleBuffer->text(style);
   delete[] style;
diff --git fluid/CodeEditor.h fluid/CodeEditor.h
index e865ac6..bf4b7b4 100644
--- fluid/CodeEditor.h
+++ fluid/CodeEditor.h
@@ -1,7 +1,7 @@
 //
 // Code editor widget for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2010 by Bill Spitzak and others.
+// Copyright 1998-2020 by Bill Spitzak and others.
 //
 // This library is free software. Distribution and use rights are outlined in
 // the file "COPYING" which should have been included with this file.  If this
@@ -15,29 +15,28 @@
 //
 
 #ifndef CodeEditor_h
-#  define CodeEditor_h
+#define CodeEditor_h
 
 //
 // Include necessary headers...
 //
 
-#  include <stdio.h>
-#  include <stdlib.h>
-#  include <string.h>
-#  include <ctype.h>
-#  include <FL/Fl.H>
-#  include <FL/Fl_Text_Buffer.H>
-#  include <FL/Fl_Text_Editor.H>
-
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <FL/Fl.H>
+#include <FL/Fl_Text_Buffer.H>
+#include <FL/Fl_Text_Editor.H>
+#include "StyleParse.h"
 
 class CodeEditor : public Fl_Text_Editor {
-  static Fl_Text_Display::Style_Table_Entry styletable[];
-  static const char * const code_keywords[];
-  static const char * const code_types[];
+  friend class StyleParse;
 
+  static Fl_Text_Display::Style_Table_Entry styletable[];
 
   // 'style_parse()' - Parse text and produce style data.
-  static void style_parse(const char *text, char *style, int length);
+  static void style_parse(const char *tbuff, char *sbuff, int len, char style);
 
   // 'style_unfinished_cb()' - Update unfinished styles.
   static void style_unfinished_cb(int, void*);
@@ -57,7 +56,6 @@ class CodeEditor : public Fl_Text_Editor {
 
   // attempt to make the fluid code editor widget honour textsize setting
   void textsize(Fl_Fontsize s);
-
 };
 
 class CodeViewer : public CodeEditor {
diff --git fluid/Makefile fluid/Makefile
index 2823e5f..a4656be 100644
--- fluid/Makefile
+++ fluid/Makefile
@@ -18,6 +18,7 @@ include ../makeinclude
 
 CPPFILES = \
 	CodeEditor.cxx \
+	StyleParse.cxx \
 	Fl_Function_Type.cxx \
 	Fl_Group_Type.cxx \
 	Fl_Menu_Type.cxx \
diff --git fluid/StyleParse.cxx fluid/StyleParse.cxx
new file mode 100644
index 0000000..abbb33f
--- /dev/null
+++ fluid/StyleParse.cxx
@@ -0,0 +1,327 @@
+//
+// Syntax highlighting for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2020 by Bill Spitzak and others.
+// Copyright 2020 Greg Ercolano.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file.  If this
+// file is missing or damaged, see the license at:
+//
+//     https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+//     https://www.fltk.org/bugs.php
+//
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>     // bsearch()
+#include "StyleParse.h"
+
+// Sorted list of C/C++ keywords...
+static const char * const code_keywords[] = {
+  "and",
+  "and_eq",
+  "asm",
+  "bitand",
+  "bitor",
+  "break",
+  "case",
+  "catch",
+  "compl",
+  "continue",
+  "default",
+  "delete",
+  "do",
+  "else",
+  "false",
+  "for",
+  "goto",
+  "if",
+  "new",
+  "not",
+  "not_eq",
+  "operator",
+  "or",
+  "or_eq",
+  "return",
+  "switch",
+  "template",
+  "this",
+  "throw",
+  "true",
+  "try",
+  "while",
+  "xor",
+  "xor_eq"
+};
+
+// Sorted list of C/C++ types...
+static const char * const code_types[] = {
+  "auto",
+  "bool",
+  "char",
+  "class",
+  "const",
+  "const_cast",
+  "double",
+  "dynamic_cast",
+  "enum",
+  "explicit",
+  "extern",
+  "float",
+  "friend",
+  "inline",
+  "int",
+  "long",
+  "mutable",
+  "namespace",
+  "private",
+  "protected",
+  "public",
+  "register",
+  "short",
+  "signed",
+  "sizeof",
+  "static",
+  "static_cast",
+  "struct",
+  "template",
+  "typedef",
+  "typename",
+  "union",
+  "unsigned",
+  "virtual",
+  "void",
+  "volatile"
+};
+
+// 'compare_keywords()' - Compare two keywords...
+extern "C" {
+  static int compare_keywords(const void *a, const void *b) {
+    return strcmp(*((const char **)a), *((const char **)b));
+  }
+}
+
+// See if 'find' is a C/C++ keyword.
+//     Refer to bsearch(3) for return value.
+//
+static void* search_keywords(char *find) {
+  return bsearch(&find, code_keywords,
+                 sizeof(code_keywords) / sizeof(code_keywords[0]),
+                 sizeof(code_keywords[0]), compare_keywords);
+}
+
+// See if 'find' is a C/C++ type.
+//     Refer to bsearch(3) for return value.
+//
+static void* search_types(char *find) {
+  return bsearch(&find, code_types,
+                 sizeof(code_types) / sizeof(code_types[0]),
+                 sizeof(code_types[0]), compare_keywords);
+}
+
+// Handle style parsing over a character
+//    Handles updating col counter when \n encountered.
+//    Applies the current style, advances to next text + style char.
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_over_char(int handle_crlf) {
+  char c = *tbuff;
+
+  // End of line?
+  if ( handle_crlf ) {
+    if ( c == '\n' ) {
+      lwhite = 1;           // restart leading white flag
+    } else {
+      // End of leading white? (used by #directive)
+      if ( !strchr(" \t", c) ) lwhite = 0;
+    }
+  }
+
+  // Adjust and advance
+  //    If handling crlfs, zero col on crlf. If not handling, let col continue to count past crlf
+  //    e.g. for multiline #define's that have lines ending in backslashes.
+  //
+  col = (c=='\n') ? (handle_crlf ? 0 : col) : col+1;   // column counter
+  tbuff++;                              // advance text ptr
+  *sbuff++ = style;                     // apply style & advance its ptr
+  if ( --len <= 0 ) return 0;           // keep track of length
+  return 1;
+}
+
+// Parse over white space using current style
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_over_white() {
+  while ( len > 0 && strchr(" \t", *tbuff))
+    { if ( !parse_over_char() ) return 0; }
+  return 1;
+}
+
+// Parse over non-white alphabetic text
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_over_alpha() {
+  while ( len > 0 && isalpha(*tbuff) )
+    { if ( !parse_over_char() ) return 0; }
+  return 1;
+}
+
+// Parse to end of line in specified style.
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_to_eol(char s) {
+  char save = style;
+  style = s;
+  while ( *tbuff != '\n' )
+    { if ( !parse_over_char() ) return 0; }
+  style = save;
+  return 1;
+}
+
+// Parse a block comment until end of comment or buffer.
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_block_comment() {
+  char save = style;
+  style = 'C';                            // block comment style
+  while ( len > 0 ) {
+    if ( strncmp(tbuff, "*/", 2) == 0 ) {
+      if ( !parse_over_char() ) return 0; // handle '*'
+      if ( !parse_over_char() ) return 0; // handle '/'
+      break;
+    }
+    if ( !parse_over_char() ) return 0;   // handle comment text
+  }
+  style = save;                           // revert style
+  return 1;
+}
+
+// Copy keyword from tbuff -> keyword[] buffer
+void StyleParse::buffer_keyword() {
+  char *key  = keyword;
+  char *kend = key + sizeof(keyword) - 1; // end of buffer
+  for ( const char *s=tbuff;
+        (islower(*s) || *s=='_') && (key < kend); 
+        *key++ = *s++ ) { }
+  *key = 0;     // terminate
+}
+
+// Parse over specified 'key'word in specified style 's'.
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_over_key(const char *key, char s) {
+  char save = style;
+  style = s;
+  // Parse over the keyword while applying style to sbuff
+  while ( *key++ )
+    { if ( !parse_over_char() ) return 0; }
+  last  = 1;
+  style = save;
+  return 1;
+}
+
+// Parse over angle brackets <..> in specified style.
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_over_angles(char s) {
+  if ( *tbuff != '<' ) return 1; // not <..>, early exit
+  char save = style;
+  style = s;
+  // Parse over angle brackets in specified style
+  while ( len > 0 && *tbuff != '>' )
+    { if ( !parse_over_char() ) return 0; }  // parse over '<' and angle content
+  if ( !parse_over_char() ) return 0;        // parse over trailing '>'
+  style = save;
+  return 1;
+}
+
+// Parse line for possible keyword
+//    spi.keyword[] will contain parsed word.
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_keyword() {
+  // Parse into 'keyword' buffer
+  buffer_keyword();
+  char *key = keyword;
+  // C/C++ type? (void, char..)
+  if ( search_types(key) )
+    return parse_over_key(key, 'F');           // 'type' style
+  // C/C++ Keyword? (switch, return..)
+  else if ( search_keywords(key) )
+    return parse_over_key(key, 'G');           // 'keyword' style
+  // Not a type or keyword? Parse over it
+  return parse_over_key(key, style);
+}
+
+// Style parse a quoted string, either "" or ''.
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_quoted_string(char quote_char, // e.g. '"' or '\''
+                                    char in_style) { // style for quoted text
+  style = in_style;                      // start string style
+  if ( !parse_over_char() ) return 0;    // parse over opening quote
+
+  // Parse until closing quote reached
+  char c;
+  while ( len > 0 ) {
+    c = tbuff[0];
+    if ( c == quote_char ) {              // Closing quote? Parse and done
+      if ( !parse_over_char() ) return 0; // close quote
+      break;
+    } else if ( c == '\\' ) {             // Escape sequence? Parse over, continue
+      if ( !parse_over_char() ) return 0; // escape
+      if ( !parse_over_char() ) return 0; // char being escaped
+      continue;
+    }
+    // Keep parsing until end of buffer or closing quote..
+    if ( !parse_over_char() ) return 0;
+  }
+  style = 'A';                            // revert normal style
+  return 1;
+}
+
+// Style parse a directive (#include, #define..)
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_directive() {
+  style = 'E';                             // start directive style
+  if ( !parse_over_char()  )    return 0;  // Parse over '#'
+  if ( !parse_over_white() )    return 0;  // Parse over any whitespace after '#'
+  if ( !parse_over_alpha() )    return 0;  // Parse over the directive
+  style = 'A';                             // revert normal style
+  if ( !parse_over_white() )    return 0;  // Parse over white after directive
+  if ( !parse_over_angles('D')) return 0;  // #include <..> (if any)
+  return 1;
+}
+
+// Style parse a line comment to end of line.
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_line_comment() {
+  return parse_to_eol('B');
+}
+
+// Parse a backslash escape character sequence.
+//    Purposefully don't 'handle' \n, since an escaped \n should be
+//    a continuation of a line, such as in a multiline #directive.
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_escape() {
+  const char no_crlf = 0;
+  if ( !parse_over_char(no_crlf) ) return 0;     // backslash
+  if ( !parse_over_char(no_crlf) ) return 0;     // char escaped
+  return 1;
+}
+
+// Parse all other non-specific characters
+//    Returns 0 if hit end of buffer, 1 otherwise.
+//
+int StyleParse::parse_all_else() {
+  last = isalnum(*tbuff) || *tbuff == '_' || *tbuff == '.';
+  return parse_over_char();
+}
diff --git fluid/StyleParse.h fluid/StyleParse.h
new file mode 100644
index 0000000..2fcc4f4
--- /dev/null
+++ fluid/StyleParse.h
@@ -0,0 +1,61 @@
+//
+// Syntax highlighting for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2020 by Bill Spitzak and others.
+// Copyright 2020 Greg Ercolano.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file.  If this
+// file is missing or damaged, see the license at:
+//
+//     https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+//     https://www.fltk.org/bugs.php
+//
+
+#ifndef StyleParse_h
+#define StyleParse_h
+
+// Class to manage style parsing, friend of CodeEditor
+class StyleParse {
+public:
+  const char *tbuff;        // text buffer
+  char       *sbuff;        // style buffer
+  int         len;          // running length
+  char        style;        // current style
+  char        lwhite;       // leading white space (1=white, 0=past white)
+  int         col;          // line's column counter
+  char        keyword[40];  // keyword parsing buffer
+  char        last;         // flag for keyword parsing
+
+  StyleParse() {
+    tbuff  = 0;
+    sbuff  = 0;
+    len    = 0;
+    style  = 0;
+    lwhite = 1;
+    col    = 0;
+    last   = 0;
+  }
+
+  // Methods to aid in parsing
+  int  parse_over_char(int handle_crlf=1);
+  int  parse_over_white();
+  int  parse_over_alpha();
+  int  parse_to_eol(char s);
+  int  parse_block_comment();     // "/* text.. */"
+  void buffer_keyword();
+  int  parse_over_key(const char *key, char s);
+  int  parse_over_angles(char s);
+  int  parse_keyword();           // "switch"
+  int  parse_quoted_string(char quote_char, char in_style);
+                                  // "hello", 'x'
+  int  parse_directive();         // "#define"
+  int  parse_line_comment();      // "// text.."
+  int  parse_escape();            // "\'"
+  int  parse_all_else();          // all other code
+};
+
+#endif // StyleParse_h
Direct Link to Message ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.