This site has been retired. For up to date information, see handbook.gnome.org or gitlab.gnome.org.


[Home] [TitleIndex] [WordIndex

GtkSourceView: styles

Current Situation

GtkSourceViewTagStyles are stored in the GtkSourceDefaultStyleScheme->styles hash table using the translatable name as a key. These GtkSourceTagStyles are the only ones available (you need to create a new GtkSourceStyleScehme to add new ones).

When gtk_source_buffer_set_language() is called, the GtkSourceBuffer gets the GtkSourceTags from the GtkSourceLanguage with gtk_source_language_get_tags() and stores them in the GtkSourceTagTable. The list is created by the GtkSourceLanguage by asking the parser (without passing any GtkSourceEngine) to read the .lang file and create the GtkSourceTags and associate them to the GtkSourceTagStyles.

To associate a GtkSourceTag to a GtkSourceTagStyle, gtk_source_language_get_tag_style() is called. This function looks first in tag_id_to_style (user defined), then in tag_id_to_style_name and finally, if no match is found, normal_style is used.

Gedit, to visualize the GtkSourceTag to customize, uses gtk_source_language_get_tags() and shows the "name" property which holds the translated name of the GtkSourceTag. The "id" property is instead used to store the values in GConf (/gedit-2/preferences/syntax_highlighting/{language_id}/{tag_id})

Problems:

Proposed Changes

Each .lang file has some style tags, each style has an identifier, a translatable name and an optional "default-to" attribute. The real styles (i.e. color, bold and so on) are stored in a theme file and handled using GtkSourceTheme. To allow the user to change only single styles (and not just the theme) the programmer should implement the interface GtkSourceStyleConfigurator.

xml.lang:

<styles>
  <style id="comment" _name="Comment" />
  <style id="entity" _name="Entity" default-to="escape" />
</styles>

When the library needs the style named "entity" the following operations are executed until a style is found:

If a "default-to" attribute is not set we use the value of the "id" attribute, so, in the example, if "xml:comment" does not exist in the theme the library will use "def:comment".

Some languages, such as C++, use the styles from another language, to do so the "use" attribute is required.

cpp.lang:

<styles use="c" />

If the library needs the style for C++ keywords the following operations are executed:

Styles of an included language (such as Javascript in HTML) are not configurable from the container language.

If there is a style that cannot be mapped to a default style and there is not a "default-to" attribute then we should just use the normal style.

<styles>
  <style id="my-unknown-style" _name="..." />
</styles>

TODO: In c.lang we have:

<context ref="def:decimal" />

and in def.lang:

<context id="decimal" style-ref="decimal">
  <match>...</match>
</context>

So the user cannot configure the style for the numbers in C, because "def" will be considered an external language, such as Javascript in HTML. I have no clue how to resolve this.

The idea behind the new API is that the programer should never use directly GtkSourceTag, we could even make this class private to gtksourceview (note that GtkSyntaxTag and GtkPatternTag need to be private as they are only used by the old engine.)

These are the steps required to implement a configuration window for single styles:

Theme files

This is an example of a theme file:

<styles>
  <style id="def:normal">
  </style>
  <style id="def:comment">
    <bold>true</bold>
    <foreground>#0000FF</foreground>
  </style>
  <style id="c:comment" extends="def:comment">
    <italic>true</italic>
  </style>
</styles>

Because of the "extends" attribute the "c:comment" style in the previous example is equivalent to:

<style id="c:comment">
  <bold>true</bold>
  <foreground>#0000FF</foreground>
  <italic>true</italic>
</style>

Proposed API

gtksourcestyle.h

/* GtkSourceStyle is different from the old GtkSourceTagStyle because it does not
 * contain the "is_default" variable. As we break compatibility I prefer to change
 * the name removing "Tag" because the programmer will not have to handle directly
 * tags anymore. */
typedef struct _GtkSourceStyle GtkSourceStyle;

typedef enum {
        GTK_SOURCE_STYLE_USE_BACKGROUND = 1 << 0,
        GTK_SOURCE_STYLE_USE_FOREGROUND = 1 << 1
} GtkSourceStyleMask;

struct _GtkSourceStyle {
        GtkSourceStyleMask      mask;

        GdkColor                foreground;
        GdkColor                background;

        gboolean                italic;
        gboolean                bold;
        gboolean                underline;
        gboolean                strikethrough;

        /* Reserved for future expansion. */
        guint8                  reserved[16];
};

/* PaoloMaggi suggests to use something similar to PangoAttrList to represent a style. */

gtksourcelanguagesmanager.h

/* Now we have a gtk_source_language_[s|g]et_theme, but I think we do not need a different theme for
 * every language. */
GtkSourceStyleTheme         *gtk_source_languages_manager_get_style_theme               (GtkSourceLanguagesManager *lm);
void                     gtk_source_languages_manager_set_style_theme           (GtkSourceLanguagesManager *lm,
                                                                                 GtkSourceStyleTheme       *theme);

GtkSourceStyleConfigurator      *gtk_source_languages_manager_get_style_configurator    (GtkSourceLanguagesManager  *lm);
void                             gtk_source_languages_manager_set_style_configurator    (GtkSourceLanguagesManager  *lm,
                                                                                         GtkSourceStyleConfigurator *configurator);

/* Returns the list of the ids of the available themes. */
const GSList                    *gtk_source_languages_manager_get_available_themes
                                                                                (GtkSourceLanguagesManager *sm);

/* Returns the translated name of the theme. */
gchar                           *gtk_source_languages_manager_get_theme_name
                                                                                (GtkSourceLanguagesManager *sm,
                                                                                 const gchar                  *theme_id);

/* Returns the list of directory where to search the themes, this value can be set
 * as a construct time property. */
const GSList                    *gtk_source_languages_manager_get_theme_files_dirs
                                                                                (GtkSourceLanguagesManager *sm);

gtksourcelanguage.h

/* GSList of const gchar pointers. */
GSList *gtk_source_language_get_style_ids (const GtkSourceLanguage *language);

/* Returns the (translated) name associated to style_id. */
const gchar *gtk_source_language_get_style_name (const GtkSourceLanguage *language,
                                                 const gchar             *style_id);

/* Returns a copy of the style for style_id.
 * is_default is TRUE if this style has not been customized by the user, so
 * the restore button in a configuration dialog can be disabled. */
GtkSourceStyle *gtk_source_language_get_style (const GtkSourceLanguage *language,
                                               const gchar            *style_id,
                                               gboolean               *is_default);

/* Sets the style associated to style_id.
 * If there is a GtkSourceStyleConfigurator its set_style method will
 * be called. If style in NULL then the style is restored to its default. */
gboolean gtk_source_language_set_style (GtkSourceLanguage    *language,
                                        const gchar          *style_id,
                                        const GtkSourceStyle *style);

gtksourcestyleconfigurator.h

/* To allow styles customization the programmer should implement the
 * interface GtkSourceStyleConfigurator. */
typedef struct _GtkSourceStyleConfiguratorClass  GtkSourceStyleConfiguratorClass;

struct _GtkSourceStyleConfiguratorClass
{
        GTypeInterface  base_iface;

        /* vtable */
        /* Returns NULL if the style has not be configured. */
        GtkSourceStyle  * (* get_style)         (GtkSourceStyleConfigurator *configurator,
                                                 const gchar                *language_id,
                                                 const gchar                *style_id);

        /* If style is NULL than the association is removed. */
        void            * (* set_style)         (GtkSourceStyleConfigurator *configurator,
                                                 const gchar                *language_id,
                                                 const gchar                *style_id,
                                                 const GtkSourceStyle       *style);

        /* Padding for future expansion */
        void (*_gtk_source_reserved1) (void);
        void (*_gtk_source_reserved2) (void);
        void (*_gtk_source_reserved3) (void);
        void (*_gtk_source_reserved4) (void);
};

Removed or modified functions

Thoughts / ideas / opinions

Old thoughts / ideas / opinions

This section contains thoughts about the old proposal (without schemes representing themes.)

PaoloMaggi: I have several comments about both the API and the XML format. BTW, as pbor suggested I think we should try to solve the problems step by step also because it seems we all have very few time and at the same time want to see the new_hl_engine out.

So, let us focus first on the XML format. I'd like to see language definition and style definitions somewhat uncoupled. So I think that we should not define styles in the .lang file. As we already have in the new .lang file format, the .lang file should contain only the list of styles used by the language (it could be eventually empty if only "default styles are used", i.e. we should be able to use for example "def::command" in style-ref). We can then create a second XML file containing the definition of the styles used by the default style scheme. We can have something like:

<styles>
  <style id="def::normal">
  </style>
  <style id="def::comment">
    <bold>true</bold>
    <foreground>#0000FF</foreground>
  </style>
  <style id="c::comment" ref="def:comment">
    <italic>true</italic>
  </style>
</styles>

2024-10-23 11:37