4.1 KiB
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:
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):
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!
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-excursionlet ((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-excursionlet ((beg ((lambda()
("(*")
(search-forward
(point))))lambda()
(end ((
(back-to-indentation)
(point)))))
(kill-region beg end))
(copy-symbol-at-point)"iface->")
(insert
(end-of-thing 'symbol)1)
(delete-char let ((beg (point))
(lambda()
(end ((
(find-list-end)
(point)))))
(kill-region beg end))" = i_")
(insert 2))
(yank
(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))))lambda()
(end ((
(beginning-of-line)
(point)))))
(kill-region beg end))"static ")
(insert "(*")
(search-forward -3)
(delete-char
(newline)"i_")
(insert
(end-of-thing 'symbol)1)
(delete-char let ((beg (point))
(lambda()
(end ((
(find-list-end)
(point)))))
(indent-region beg end))1)) (delete-char
Now all I have to do is to copy the whole vtable entry into matrix_http_api_matrix_api_init()
, execute M-x implement-gobject-vfunc
, then put the same vtable entry somewhere before the interface init function, and execute M-x implement-gobject-vfunc-prototype
.