Emacs: Implement a GObject’s virtual function ############################################# :date: 2016-01-13T13:31:12Z :category: blog :tags: c,development,emacs :url: 2016/01/13/emacs-implement-a-gobject-s-virtual-function/ :save_as: 2016/01/13/emacs-implement-a-gobject-s-virtual-function/index.html :status: published :author: "Gergely Polonkai" I have recently started creating a GLib implementation of the Matrix.org API. For that, I have created a GObject interface, MatrixAPI, which has as many virtual functions as API calls (which is a lot, and expanding). This way I ended up with the following scenario. In ``matrix-api.h`` I had a struct like this, with a lot more elements: .. code-block:: c typedef struct { void (*initial_sync)(MatrixAPI *api, MatrixAPICallback callback, gpointer user_data, GError **error); void (*sync)(MatrixAPI *api, MatrixAPICallback callback, gpointer user_data, GError **error); … And in ``matrix-http-api.c``, which implements ``MatrixAPI``, I have a function like this (again, with a lot more elements): .. code-block:: c static void matrix_http_api_matrix_api_init(GObjectInterface *iface) { iface->initial_sync = i_initial_sync; iface->sync = i_sync; … } And every time I wanted to implement a new function from the vtable, I had to copy the prototype, and add an ``iface->foo_bar = i_foo_bar`` line and an actual function header for ``i_foo_bar`` with the same parameters. That’s a cumbersome job for more than 40 function headers. But Emacs comes to the rescue! .. code-block:: lisp (require 'thingatpt) (defun get-point(symbol &optional arg) "Get point, optionally running a command beforehand" (funcall symbol arg) (point)) (defun copy-symbol-at-point() "Copy the symbol under point" (interactive) (save-excursion (let ((beg (get-point 'beginning-of-thing 'symbol)) (end (get-point 'end-of-thing 'symbol))) (copy-region-as-kill beg end)))) (defun implement-gobject-vfunc() "Change a vtable line of a GObject interface to an implementation line like: void (*my_iface_func)(type1 param1, type2 param2, ...); to iface->my_iface_func = i_my_iface_func;" (interactive) (save-excursion (let ((beg ((lambda() (search-forward "(*") (point)))) (end ((lambda() (back-to-indentation) (point))))) (kill-region beg end)) (copy-symbol-at-point) (insert "iface->") (end-of-thing 'symbol) (delete-char 1) (let ((beg (point)) (end ((lambda() (find-list-end) (point))))) (kill-region beg end)) (insert " = i_") (yank 2)) (next-line) (beginning-of-line)) (defun implement-gobject-vfunc-prototype() "Change a vtable line of a GObject interface to an implementation prototype line like: void (*my_iface_func)(type1 param1, type2 param2, ...); to static void i_my_iface_func(type1 param1, type2 param2, ...)" (interactive) (let ((beg ((lambda() (back-to-indentation) (point)))) (end ((lambda() (beginning-of-line) (point))))) (kill-region beg end)) (insert "static ") (search-forward "(*") (delete-char -3) (newline) (insert "i_") (end-of-thing 'symbol) (delete-char 1) (let ((beg (point)) (end ((lambda() (find-list-end) (point))))) (indent-region beg end)) (delete-char 1)) Now all I have to do is to copy the whole vtable entry into ``matrix_http_api_matrix_api_init()``, execute :kbd:`M-x implement-gobject-vfunc`, then put the same vtable entry somewhere before the interface init function, and execute :kbd:`M-x implement-gobject-vfunc-prototype`.