We use reStructuredText/sphinx for Builder’s documentation because, quite frankly, I found it the easiest for writing massive amounts of documentation in short order. I’m not sure if it’s what I want to stick with long term, but it’s doing the job short term.
However, one thing we don’t get (and I really want) out of any documentation system is support for cross-referencing the user documentation and API docs. This would be useful for us in Builder because we are the use-case for turning users into contributors. Reading our documentation on writing plugins and then locating the API docs should be seamless.
So last week I put together a prototype to generate reStructuredText/Sphinx API docs from .gir files. It will use the provided .gir, including any located dependencies, and generate API docs for them. It can’t be 100% complete for C because the .gir is missing some information that are only found in the sgml files. But it does an okay job.
Mostly, this was just a prototype to see what the state of the documentation systems are. I’m still fairly dissatisfied and am leaning towards the path of “more prototyping necessary”. For example, some things I still want from a modern documentation platform:
Cross-referencing among user and API docs
Switch between C, Python, GJS, etc
Jump to function/class source code
Find example usage of API in GNOME git
Partial gettext/i18n support so we don’t have to translate API docs, but can still cross-reference them.
Fast lookup indexes for use in IDE auto-completion docs using only read-only mmap()‘d files.
We might want surrogate links to API docs when cross-referencing so end-user documentation stays small.
The GtkSourceView library has this handy concept of a GtkSourceGutterRenderer. They are similar in concept to a GtkCellRenderer but for the gutter to the left or right of the text editor.
Like a GtkCellRenderer, you pack it into a container and they are placed one after another with some amount of optional spacing in-between. This is convenient because you can start quickly by mixing and matching what you need from existing components. Those include text (such as line numbers), pixbuf rendering, or even code folding regions.
However, there is a cost to this sort of composition. One is function call overhead, but that isn’t particularly interesting to me because there are ways to amortize that away (like we did with the pixel cache). The real problem is one of physical space. Each time a renderer is added, the width of the gutter is increased.
Builder 3.26.0 added a new column for breakpoints, and so we increased our width by another 18 pixels or so. Enough to be cumbersome. It looked like the following which has 4 renderers displayed.
Line changes (git)
Once you reach some level of complexity, you need to bite the bullet and implement a single renderer that has all the features you want in one place. It allows you to overlap content for density and use the background itself as a component. We just did that for Builder and here is what it looks like.
There are a couple other nice points performance-wise by implementing the gutter as a single renderer. We can take a number of “shortcuts” in the render path that a generic renderer cannot without sacrificing flexibility. Since the gutter is not pixel cached, this has improved the performance of kinetic scrolling on various HiDPI displays. There is always more performance work to do, but I’m rather happy with the result so far.
You’ll find this in the upcoming 3.26.1 release of Builder and is already available in Builder’s Nightly flatpak.
I’ve been aggressively pushing forward our new layout branch to integrate the new design work we’ve been iterating on. I don’t think we need to have it all done to merge to master, so we are rapidly approaching the time-frame for the branch to land.
There is much from the design still missing, but every day more pieces come together. I expect to have a good portion of it done by GUADEC.
A lot happened this week on the wip/chergert/layout branch. Here are some highlights.
Georges landed a “focus mode” fullscreen mode for Builder.
We’ve landed a patch in flatpak-builder to update terminal titles. This will allow us to scrape that info via the PTY in Builder for better progress messages.
Document titlebars now match the primary-color of the content. We also fade between states. This took some craftiness to avoid cascading the entire CSS tree. Video example below.
DzlPropertiesGroup is a convenient GActionGroup implementation for exporting multiple object properties from a GObject. This is more convenient than GPropertyAction when you are exposing lots of properties together.
The TODO plugin was ported to C and employs various techniques to use reduce memory overhead.
Dazzle gained convenience API to do insertion sort on a GtkListStore in O(log n) time by accessing the GSequence directly. This should be a safe layer-violation on Gtk+ 3.x.
Terminal, Devhelp, and HTML-Preview were ported to the new layout design.
IdeSymbolResolver gained a “find nearest scope” API which is used to update the scope name in the document titlebar. Both C and Vala are supported. Other languages need an implementation still.
The project tree was tweaked to look more like the mockup. While this won’t be our default project-tree for 3.26, we will keep it around and therefore it should match the design.
Overview map was ported to the new layout design.
Plugins should use the new IdeBuffer::change-settled API to be notified of when they should update their state based on buffer content (unless alternate API is provided via the plugin interface).
We’ve added type icons to the devhelp search that match the language-feature icons used elsewhere in Builder.
Scrolling to the insertion point on buffer load has been vastly improved.
Performance of buffer loading has also improved.
Todo and build diagnostics have been ported to the new design.
You can do some pretty evil things with GtkTreeView if you put your mind to it. One of the most common questions over the years has been how to reflow (wrap) text. The short answer is you can’t. The answer for those willing to hack around it is something like:
So the real question is “Why not use GtkListBox?”
GtkListBox is a fantastic widget. But there are some things it does not deal well with today. I presume that once it can deal with only keeping a minimum number of widgets in memory (and the size-request magic that goes with it) it would be a better solution.
Builder keeps a lot of widgets active during the lifetime of the application, and that makes style propagation particularly slow. The fewer widgets we can use, the more responsive we can keep things. (And of course, there are multiple ways to do this).
If you find yourself needing to troubleshoot Builder (hopefully just during our development cycles) you can now run the command “counters” from the command bar (Ctrl+Enter). This gives you access to some internal counters.
You can get these out of process too, using dazzle-list-counters PID which cracks open the shared memory page and dumps the counters.
As you might imagine, the counters are in libdazzle now so you can have the same sort of feature in your (C-based) applications quite easily.
Long time GNOME contributor and foundation member Travis Reitter had a medical emergency earlier this month. You might consider donating to the gofundme to help him and his family out during the marathon to recovery.
Let’s remind everyone what GNOME is about, people!
Years ago during my tenure at MongoDB I worked on a couple libraries. Notably the libbson and mongo-c-driver libraries. One neat feature we had was this concept called BCON which stood for BSON C Object Notation. It was a succinct format for creating BSON documents that made it easier to reason about what you were creating.
So I decided to do the same thing this evening around json-glib because I found I was writing a lot of code to create objects/arrays/etc.
Since this uses va_list it’s technically less type safe than your other options. But it uses some magic struct initializers to get things in a situation where we can bail at runtime if you did something wrong.
The other half that I’m currently still missing is the extraction support. If you replace JCON_NEW() with JCON_EXTRACT(node) and the values with pointers to values, you can quickly extract documents.