cgtkgtktextview

GtkTextView text coloring not working as expected


I'm trying to use GtkTextView for highlighting C++ style comments in code but it does not seem to work right. I want to create a function that first resets all the highlight to default (black) and then paints only the part of the text that matches pattern /.?*/ While the regex part works I have serious problem with Gtk obedience - it just paints the text black and stops. Is there any logical explaination for this? Am I doing something wrong? I'm placing the sample code that should work but it does not. The compilation command is

gcc -o highlight_syntax_comments highlight_syntax_comments.c `pkg-config --cflags --libs gtk+-3.0`
#define GLIB_VERSION_2_28               (G_ENCODE_VERSION (2, 28))
#define GLIB_VERSION_MIN_REQUIRED       GLIB_VERSION_2_28

#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

GtkTextBuffer *buffer;
GtkTextIter iter;

size_t f_size;
char* string;
int err;

static void highlight_syntax() {
  GtkTextIter match_start, match_end;
  GtkTextSearchFlags flags;
  
  GtkTextTagTable* table = gtk_text_buffer_get_tag_table (buffer);
  GtkTextTag* orange_tag   = gtk_text_tag_table_lookup (table, "orange");
  GtkTextTag* black_tag  = gtk_text_tag_table_lookup (table, "black");
  GtkTextTag* green_tag  = gtk_text_tag_table_lookup (table, "green");
  
  // reset color to black
  gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER (buffer), &match_start);
  gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER (buffer), &match_end);
  gtk_text_buffer_apply_tag (GTK_TEXT_BUFFER (buffer), black_tag,  &match_start, &match_end);

  // color first 100 chars
  gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER (buffer), &match_start, 0);
  gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER (buffer), &match_end, 100);
  gtk_text_buffer_apply_tag (GTK_TEXT_BUFFER (buffer), orange_tag,  &match_start, &match_end);

}

static gboolean key_callback(GtkWidget *widget,
                             GdkEventKey *event,
                             GtkIMContext *im_context) {
  highlight_syntax();
  return FALSE;
}

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

#define FILE_OK 0
#define FILE_NOT_EXIST 1
#define FILE_TO_LARGE 2
#define FILE_READ_ERROR 3

char * c_read_file(const char * f_name, int * err, size_t* f_size) {
    char * buffer;
    size_t length;
    FILE * f = fopen(f_name, "rb");
    size_t read_length;

    if (f) {
        fseek(f, 0, SEEK_END);
        length = ftell(f);
        fseek(f, 0, SEEK_SET);

        buffer = (char *)malloc(length + 1);

        read_length = fread(buffer, 1, length, f);
        fclose(f);

        *err = FILE_OK;
        buffer[length] = '\0';
        *f_size = length;
    }
    else {
        *err = FILE_NOT_EXIST;

        return NULL;
    }

    return buffer;
}

int main(int argc, gchar *argv[]) {

  GtkWidget *window;
  GtkWidget *view;
  GtkWidget *vbox;
  GtkWidget *scrolled_window; 

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);

  GtkIMContext *im_context = gtk_im_multicontext_new();
  GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
  gtk_im_context_set_client_window(im_context, gdk_window);
  gtk_im_context_focus_in(im_context);

  vbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
  view = gtk_text_view_new();
  gtk_widget_add_events(view, GDK_BUTTON_PRESS_MASK);
  gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 0);

  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
  gtk_container_add (GTK_CONTAINER (scrolled_window),
                    vbox);

  buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
  gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0);
  
  gtk_text_buffer_create_tag(buffer, "orange",  "foreground", "#e87d3e", NULL); 
  gtk_text_buffer_create_tag(buffer, "green", "foreground", "#A6E22E", NULL); 
  gtk_text_buffer_create_tag(buffer, "black", "foreground", "#000000", NULL); 

  string = c_read_file("./highlight_syntax_comments.c", &err, &f_size);
  gtk_text_buffer_insert(buffer, &iter, string, -1);

  highlight_syntax();

  gtk_container_add(GTK_CONTAINER(window), scrolled_window);

  g_signal_connect(G_OBJECT(window), "destroy",
        G_CALLBACK(gtk_main_quit), NULL);
  g_signal_connect(window, "key-press-event",
      G_CALLBACK(key_callback), im_context);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}

Solution

  • This is explained in the documentation for gtk_text_tag_set_priority() — setting one tag does not remove another, so both the orange and black tags are applying to the text at the same time. Since the black tag was added to the tag table last, its priority is highest, so it overrides the orange tag, even though you applied the orange tag on the text after applying the black tag.

    The solution is to give the orange tag a higher priority, or make sure that you remove the black tag from the text that you want to apply the orange tag to.