Chapter 2. Setting Up the Scanner

Table of Contents
Loading Scanners as Dynamic Libraries
Linking Scanners with the Application
Creating a new Scanner

A scanner is, in GtkEditor context, a software module responsible for lexical analysis of the text being edited. Each instant of the editor widget can have associated at most one scanner, and this scanner implements the language specific part of syntax highlighting. Whenever text is modified the scanner analyses the changes and reports the matched tokens back to the editor. The editor then uses this to highlight the source code.

Assuming you have a pointer to a scanner (and we will show how to get that shortly) you can install it in an editor with the method gtk_editor_install_scanner. If, say, the scanner is a C scanner, installing it in an editor will change the editor from being a plain text editor to being a C source code editor.

Example 2-1. Installing a Scanner

  gtk_editor_install_scanner (editor, scanner);
      

The scanner implements all language specific analysis, so to configure the editor to another language, is a matter of installing a new scanner. [1] Most customization is therefore done through writing new scanners. We will only briefly discuss writing new scanners in this tutorial.

To the editor, a scanner is nothing more than an object implementing a specific interface. Any implementation of this interface can be used as a scanner. This gives you a lot of flexibility in configuration of the editor. We will not explore this in this tutorial, but only concentrate on using scanners created with the scannertool program distributed with the widget. This tool takes a specification of a scanner and generates a library that can be loaded at runtime or statically linked with your application. Distributed with the editor widget is a number of scanners. These are compiled with the scannertool and thus can be used as described in this tutorial. If you need support for a language not covered by the existing scanners you can use the existing scanners and the last section of this chapter as a guide to creating your own scanner.

Loading Scanners as Dynamic Libraries

The scanners supplied with the editor distribution (and the scanners created with the method described below) can be loaded at runtime. This is useful for source editor applications and IDEs where the different languages that could be edited is not fixed and is not necessarily known at compile time.

The function gtk_editor_load_scanner is used for this purpose. It takes as argument the name of the scanner and returns a pointer to the loaded scanner (or NULL if an error occurred during loading).

Example 2-2. Loading a Scanner at Runtime

  GtkEditorScanner *cscanner = gtk_editor_load_scanner ("c-scanner");
	

The scanners we create with the distribution has suffix .so, so we try to load both the "scanner_name" argument and "scanner_name.so". We always try "scanner_name" first and "scanner_name.so" last. We search in ~/.gtkeditor/scanners, <libpath>gtkeditor, and <libpath>, where <libpath> is any directory in you LD_LIBRARY_PATH. We search the different directories in that order, so to overwrite a system default, you can simply install a scanner in ~/.gtkeditor/scanners/.

To load a C scanner and install it in an editor, you write

Example 2-3. Loading and Installing a C Scanner

  cscanner = gtk_editor_load_scanner ("c-scanner");
  gtk_editor_install_scanner (editor, cscanner);
	

Of course you should check the return value of gtk_editor_load_scanner, but we omit checks in this tutorial sacrificing stability for clarity.

We can extend the program from Example 1-3 with loading a scanner. We will load the C scanner distributed with GtkEditor, so we assume this scanner has been installed somewhere in LD_LIBRARY_PATH. The updated program is shown in Example 2-4

Example 2-4. Creating a GtkEditor and loading a scanner

#include <stdlib.h>
#include <gtkeditor.h>

int
main (int argc, char *argv[]) 
{
  GtkWidget *window;
  GtkWidget *sw;
  GtkWidget *tkxt;
  GtkEditor *editor;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  editor = gtk_editor_new ();

  /* load and install a C scanner */
  cscanner = gtk_editor_load_scanner ("c-scanner");
  gtk_editor_install_scanner (editor, cscanner);

  sw = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
                                 GTK_POLICY_AUTOMATIC,
                                 GTK_POLICY_AUTOMATIC);

  tkxt = gtk_text_view_new_with_buffer(GTK_TEXT_BUFFER(editor));

  gtk_container_add (GTK_CONTAINER (window), sw);
  gtk_container_add (GTK_CONTAINER(sw), tkxt);

  gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);

  gtk_main ();

  return EXIT_SUCCESS;
}
      

After the scanner is installed, the editor has access to lexical information about the text being edited. If you run the program in the example, you wont really notice this, because we don't use this information to anything at this point. But you will see its use in Chapter 3. Unless you need to link scanners statically with your application, you should probably skip to this chapter now.

Notes

[1]

This is only true up to a certain point. If the scanner matches tokens that are very language specific, for example C pre-processor macros, and these should be highlighted, the highlighter also needs to know about them. For scanners sticking to generic tokens such as "comment", "keyword", "functions", etc. only the scanner need change. More on this in Chapter 3.