File loading and saving in GtkSourceView, finally

Last year GtkSourceView saw a new search and replace API. This year it’s the file loading and saving that has just landed! It is in the continuity of making the gedit source code more reusable for other text editors.

In short, the back-end part of the file loading and saving in gedit has been moved to GtkSourceView, with a new and more flexible API to better wrap the feature. The code has been modified to follow GIO conventions for asynchronous operations, to use GTask internally, and replace the uses of GSettings by properties, among other things.

The file loader auto-detects encodings, newline types and compression type (yes gedit can open gzip files). Invalid characters can also be displayed with their corresponding hexadecimal value, because GtkTextBuffer accepts only valid UTF-8 text. And progress information is reported during the operation.

The API is stateful: the file parameters (encoding etc) are remembered between a file loading and a file saving in a GtkSourceFile object. Unfortunately the new API is still quite low-level. The application must configure the file loader and the file saver, and some errors are returned to the application.

So the front-end and errors handling is still implemented in gedit. Errors and progress information are displayed in an info bar, above the GtkSourceView widget. For some errors, gedit proposes different actions to the user, like choosing another encoding.

API design

If you are a text editor developer, don’t hesitate to have a look at the GtkSourceFile API. The API can still change during this 3.13 development cycle. The notes about the API design are available on bugzilla (there has been four iterations). Here is a summary.

The API is a bit heavy, with the following classes: GtkSourceEncoding, GtkSourceFile, GtkSourceFileLoader and GtkSourceFileSaver. There are good reasons for having two class’ names derived from a verb (“to load” and “to save”), which is generally a hint that those classes should be replaced by a method (i.e. an action). The reasons are partly similar with the new GSubprocessLauncher in GIO: the FileLoader and FileSaver classes are there not only for launching the operation, but also for configuring it with a nicer and more extensible API than one function with a dozen parameters. With the FileLoader and FileSaver, we can add properties, functions and even signals. And the FileLoader and FileSaver classes are quite useful in gedit: when an error occurs and the user clicks on a button in the info bar, the loader or saver object is reconfigured and the operation is relaunched, without the need to keep the initial configuration around. Also, the FileLoader or FileSaver properties are applied to the GtkSourceFile object only on a successful operation, so the GtkSourceFile state is (normally) consistent with the underlying file on the disk, at least at the time of the last load or save done with GtkSourceView.

Possible follow-ups work

A possible follow-up is to make the front-end code more reusable, either by creating higher-level classes in GtkSourceView, or by creating a git submodule, like the libgd (without API stability guarantees in the latter case).

Another possible follow-up is to analyze and improve the performances, which are currently quite bad. For short files it is not visible of course, but opening a very big log file takes more time than with other popular text editors.

There are other possible improvements, like unescaping invalid characters when saving, or avoid blocking the GtkTextBuffer when (auto-)saving a short remote file on a slow network connection.

Changes for gedit plugins

Unfortunately there are some changes in the gedit API for plugins, mainly in GeditDocument. Fortunately the changes are well documented, and most plugins should still work without any modification.

Conclusion

The file loading and saving can quickly become a fairly complex beast. Now this code is available for other GTK+ text editors.

Thanks to Paolo Borelli for the reviews!

TL;DR:

  • In GtkSourceView: 29 files changed, 7909 insertions(+), 3 deletions(-)
  • In gedit: 49 files changed, 1888 insertions(+), 8819 deletions(-)
  • In gedit-plugins: 11 files changed, 22 insertions(+), 31 deletions(-)

This is a 12% code increase in GtkSourceView, and a 6% code decrease in gedit.

PS: As usual, some tests would be more than welcome before the stable version in September.

Leave a Reply