FLTK logo

[master] 2b1a2fe - Merge pull request #150 from erco77/master

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] 2b1a2fe - Merge pull request #150 from erco77/master "erco77" Nov 01, 2020  
 
commit 2b1a2fe8dde181e99c9787163f528cc79d663a3a
Merge: 1761523 dab049a
Author:     erco77 <erco@seriss.com>
AuthorDate: Sun Nov 1 12:48:52 2020 -0800
Commit:     GitHub <noreply@github.com>
CommitDate: Sun Nov 1 12:48:52 2020 -0800

    Merge pull request #150 from erco77/master
    
    Rewrite fluid CodeEditor syntax highlighting for issue #135

commit dab049a2bd701658d5354fc6d829c058edae1352
Merge: 1761523 d66e146
Author:     Greg Ercolano <erco@seriss.com>
AuthorDate: Sun Nov 1 12:16:59 2020 -0800
Commit:     Greg Ercolano <erco@seriss.com>
CommitDate: Sun Nov 1 12:16:59 2020 -0800

    Merge branch 'issue135-1.4.x'

commit d66e146a89cd92307cb404bb203a9ce46f890375
Author:     Greg Ercolano <erco@seriss.com>
AuthorDate: Sun Sep 20 16:05:16 2020 -0700
Commit:     Greg Ercolano <erco@seriss.com>
CommitDate: Sun Nov 1 12:16:23 2020 -0800

    Handle single quotes

commit 4d503899a3dec9df8380b3981f1a7259e9d6cb8c
Author:     Greg Ercolano <erco@seriss.com>
AuthorDate: Sat Sep 19 10:43:27 2020 -0700
Commit:     Greg Ercolano <erco@seriss.com>
CommitDate: Sun Nov 1 12:16:23 2020 -0800

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

commit 890533a863718ba10925a807b90e621d7a8cf24a
Author:     Greg Ercolano <erco@seriss.com>
AuthorDate: Thu Sep 17 23:57:14 2020 -0700
Commit:     Greg Ercolano <erco@seriss.com>
CommitDate: Sun Nov 1 12:16:23 2020 -0800

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

commit cec029dbee435e7f608b9f6a4a3d8e98f2c5a398
Author:     Greg Ercolano <erco@seriss.com>
AuthorDate: Wed Sep 16 09:33:24 2020 -0700
Commit:     Greg Ercolano <erco@seriss.com>
CommitDate: Sun Nov 1 12:16:23 2020 -0800

    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'.