[gtk+/wip/otte/tokenizer: 7/42] inspector: Implement rudimentary syntax hilighting



commit f378ed306a3639ccc9956dcefb890d0201b3088f
Author: Benjamin Otte <otte redhat com>
Date:   Tue Mar 8 06:54:35 2016 +0100

    inspector: Implement rudimentary syntax hilighting
    
    We hilight comments in blue and strings in red. Go us!

 gtk/inspector/css-editor.c  |  224 +++++++++++++++++++++++++++++++++++++++++++
 gtk/inspector/css-editor.ui |   12 +++
 2 files changed, 236 insertions(+), 0 deletions(-)
---
diff --git a/gtk/inspector/css-editor.c b/gtk/inspector/css-editor.c
index c4af9a6..76ccbc1 100644
--- a/gtk/inspector/css-editor.c
+++ b/gtk/inspector/css-editor.c
@@ -26,6 +26,8 @@
 #include "css-editor.h"
 
 #include "gtkcssprovider.h"
+#include "gtkcssrbtreeprivate.h"
+#include "gtkcsstokenizerprivate.h"
 #include "gtkstyleprovider.h"
 #include "gtkstylecontext.h"
 #include "gtktextview.h"
@@ -37,10 +39,30 @@
 #include "gtktextiter.h"
 
 
+typedef struct _GtkCssChunk GtkCssChunk;
+typedef struct _GtkCssChunkSize GtkCssChunkSize;
+
+struct _GtkCssChunkSize
+{
+  gsize              bytes;
+  gsize              chars;
+  gsize              line_breaks;
+  gsize              line_bytes;
+  gsize              line_chars;
+};
+
+struct _GtkCssChunk
+{
+  GtkCssToken        token;
+
+  GtkCssChunkSize    size;
+};
+
 struct _GtkInspectorCssEditorPrivate
 {
   GtkWidget *view;
   GtkTextBuffer *text;
+  GtkCssRbTree *tokens;
   GtkCssProvider *provider;
   GtkToggleButton *disable_button;
   guint timeout;
@@ -61,6 +83,62 @@ css_error_free (gpointer data)
   g_free (error);
 }
 
+static void
+gtk_css_chunk_clear (gpointer data)
+{
+  GtkCssChunk *chunk = data;
+
+  gtk_css_token_clear (&chunk->token);
+}
+
+static void
+gtk_css_chunk_size_clear (GtkCssChunkSize *size)
+{
+  size->bytes = 0;
+  size->chars = 0;
+  size->line_breaks = 0;
+  size->line_bytes = 0;
+  size->line_chars = 0;
+}
+
+static void
+gtk_css_chunk_size_add (GtkCssChunkSize *size,
+                        GtkCssChunkSize *add)
+{
+  size->bytes += add->bytes;
+  size->chars += add->chars;
+  size->line_breaks += add->line_breaks;
+  if (add->line_breaks)
+    {
+      size->line_bytes = add->line_bytes;
+      size->line_chars = add->line_chars;
+    }
+  else
+    {
+      size->line_bytes += add->bytes;
+      size->line_chars += add->chars;
+    }
+}
+
+static void
+gtk_css_chunk_augment (GtkCssRbTree *tree,
+                       gpointer      aug,
+                       gpointer      node,
+                       gpointer      lnode,
+                       gpointer      rnode)
+{
+  GtkCssChunkSize *size = aug;
+  GtkCssChunk *chunk = node;
+
+  gtk_css_chunk_size_clear (size);
+
+  if (lnode)
+    gtk_css_chunk_size_add (size, gtk_css_rb_tree_get_augment (tree, lnode));
+  gtk_css_chunk_size_add (size, &chunk->size);
+  if (rnode)
+    gtk_css_chunk_size_add (size, gtk_css_rb_tree_get_augment (tree, rnode));
+}
+ 
 static gboolean
 query_tooltip_cb (GtkWidget             *widget,
                   gint                   x,
@@ -216,6 +294,132 @@ save_clicked (GtkButton             *button,
 }
 
 static void
+gtk_css_chunk_get_iters (GtkInspectorCssEditor *ce,
+                         GtkCssChunk           *chunk,
+                         GtkTextIter           *start,
+                         GtkTextIter           *end)
+{
+  GtkInspectorCssEditorPrivate *priv = ce->priv;
+  GtkCssChunk *c, *l, *prev = NULL;
+  gsize offset;
+
+  offset = 0;
+  l = gtk_css_rb_tree_get_left (priv->tokens, chunk);
+  if (l)
+    {
+      GtkCssChunkSize *size = gtk_css_rb_tree_get_augment (priv->tokens, l);
+      offset = size->chars;
+    }
+  else
+    {
+      offset = 0;
+    }
+  prev = chunk;
+  for (c = gtk_css_rb_tree_get_parent (priv->tokens, chunk);
+       c != NULL;
+       c = gtk_css_rb_tree_get_parent (priv->tokens, c))
+    {
+      l = gtk_css_rb_tree_get_left (priv->tokens, c);
+
+      if (l != prev)
+        {
+          GtkCssChunkSize *size = gtk_css_rb_tree_get_augment (priv->tokens, l);
+          offset += size->chars;
+          offset += c->size.chars;
+        }
+      prev = c;
+    }
+
+  if (start)
+    gtk_text_buffer_get_iter_at_offset (priv->text, start, offset);
+  if (end)
+    gtk_text_buffer_get_iter_at_offset (priv->text, end, offset + chunk->size.chars);
+}
+
+static void
+update_token_tags (GtkInspectorCssEditor *ce,
+                   GtkCssChunk           *start,
+                   GtkCssChunk           *end)
+{
+  GtkInspectorCssEditorPrivate *priv = ce->priv;
+  GtkCssChunk *chunk;
+
+  for (chunk = start;
+       chunk != end;
+       chunk = gtk_css_rb_tree_get_next (priv->tokens, chunk))
+    {
+      GtkTextIter start, end;
+      const char *tag_name;
+
+      if (chunk->token.type == GTK_CSS_TOKEN_COMMENT)
+        tag_name = "comment";
+      else if (chunk->token.type == GTK_CSS_TOKEN_STRING)
+        tag_name = "string";
+      else
+        continue;
+
+      gtk_css_chunk_get_iters (ce, chunk, &start, &end);
+      gtk_text_buffer_apply_tag_by_name (priv->text, tag_name, &start, &end);
+    }
+}
+
+static void
+update_tokenize (GtkInspectorCssEditor *ce)
+{
+  GtkInspectorCssEditorPrivate *priv = ce->priv;
+  GtkCssTokenizer *tokenizer;
+  GtkCssChunk *chunk;
+  GBytes *gbytes;
+  char *text;
+  gsize bytes = 0;
+  gsize chars = 0;
+  gsize lines = 1;
+
+  if (priv->tokens)
+    gtk_css_rb_tree_unref (priv->tokens);
+  priv->tokens = gtk_css_rb_tree_new (GtkCssChunk,
+                                      GtkCssChunkSize,
+                                      gtk_css_chunk_augment,
+                                      gtk_css_chunk_clear,
+                                      NULL);
+
+  text = get_current_text (priv->text);
+  gbytes = g_bytes_new_take (text, strlen (text));
+  tokenizer = gtk_css_tokenizer_new (gbytes, NULL, ce, NULL);
+  chunk = gtk_css_rb_tree_insert_after (priv->tokens, NULL);
+
+  for (gtk_css_tokenizer_read_token (tokenizer, &chunk->token);
+       chunk->token.type != GTK_CSS_TOKEN_EOF;
+       gtk_css_tokenizer_read_token (tokenizer, &chunk->token))
+    {
+      chunk->size.bytes = gtk_css_tokenizer_get_byte (tokenizer) - bytes;
+      bytes += chunk->size.bytes;
+      chunk->size.chars = gtk_css_tokenizer_get_char (tokenizer) - chars;
+      chars += chunk->size.chars;
+      chunk->size.line_breaks = gtk_css_tokenizer_get_line (tokenizer) - lines;
+      lines += chunk->size.line_breaks;
+      if (chunk->size.line_breaks)
+        {
+          chunk->size.line_bytes = gtk_css_tokenizer_get_line_byte (tokenizer);
+          chunk->size.line_chars = gtk_css_tokenizer_get_line_char (tokenizer);
+        }
+      else
+        {
+          chunk->size.line_bytes = chunk->size.bytes;
+          chunk->size.line_chars = chunk->size.chars;
+        }
+
+      chunk = gtk_css_rb_tree_insert_after (priv->tokens, chunk);
+    } 
+
+  gtk_css_rb_tree_remove (priv->tokens, chunk);
+  gtk_css_tokenizer_unref (tokenizer);
+  g_bytes_unref (gbytes);
+
+  update_token_tags (ce, gtk_css_rb_tree_get_first (priv->tokens), NULL);
+}
+
+static void
 update_style (GtkInspectorCssEditor *ce)
 {
   gchar *text;
@@ -228,6 +432,16 @@ update_style (GtkInspectorCssEditor *ce)
   g_free (text);
 }
 
+static void
+clear_all_tags (GtkInspectorCssEditor *ce)
+{
+  GtkTextIter start, end;
+
+  gtk_text_buffer_get_start_iter (ce->priv->text, &start);
+  gtk_text_buffer_get_end_iter (ce->priv->text, &end);
+  gtk_text_buffer_remove_all_tags (ce->priv->text, &start, &end);
+}
+
 static gboolean
 update_timeout (gpointer data)
 {
@@ -235,7 +449,9 @@ update_timeout (gpointer data)
 
   ce->priv->timeout = 0;
 
+  clear_all_tags (ce);
   update_style (ce);
+  update_tokenize (ce);
 
   return G_SOURCE_REMOVE;
 }
@@ -313,6 +529,11 @@ gtk_inspector_css_editor_init (GtkInspectorCssEditor *ce)
 {
   ce->priv = gtk_inspector_css_editor_get_instance_private (ce);
   gtk_widget_init_template (GTK_WIDGET (ce));
+  ce->priv->tokens = gtk_css_rb_tree_new (GtkCssChunk,
+                                          GtkCssChunkSize,
+                                          gtk_css_chunk_augment,
+                                          gtk_css_chunk_clear,
+                                          NULL);
 }
 
 static void
@@ -332,6 +553,9 @@ finalize (GObject *object)
   if (ce->priv->timeout != 0)
     g_source_remove (ce->priv->timeout);
 
+  if (ce->priv->tokens)
+    gtk_css_rb_tree_unref (ce->priv->tokens);
+
   destroy_provider (ce);
 
   g_list_free_full (ce->priv->errors, css_error_free);
diff --git a/gtk/inspector/css-editor.ui b/gtk/inspector/css-editor.ui
index ad69197..189e17b 100644
--- a/gtk/inspector/css-editor.ui
+++ b/gtk/inspector/css-editor.ui
@@ -3,6 +3,18 @@
   <object class="GtkTextTagTable" id="tags">
     <child type="tag">
       <object class="GtkTextTag">
+        <property name="name">comment</property>
+        <property name="foreground">blue</property>
+      </object>
+    </child>
+    <child type="tag">
+      <object class="GtkTextTag">
+        <property name="name">string</property>
+        <property name="foreground">red</property>
+      </object>
+    </child>
+    <child type="tag">
+      <object class="GtkTextTag">
         <property name="name">warning</property>
         <property name="underline">single</property>
         <property name="underline-rgba">darkorange</property>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]