Skip to content

Instantly share code, notes, and snippets.

@shanemhansen
Last active May 2, 2017 21:26
Show Gist options
  • Save shanemhansen/ae13a4730f038714fa4d7984a8a64454 to your computer and use it in GitHub Desktop.
Save shanemhansen/ae13a4730f038714fa4d7984a8a64454 to your computer and use it in GitHub Desktop.
Using go to write emacs plugins
#include <emacs-module.h>
// this is all boilerplate to deal with the fact that C function pointers aren't callable in go
typedef emacs_value (*internFunc) (emacs_env *env, const char *symbol_name);
typedef emacs_env *(*getEnvFunc) (struct emacs_runtime *ert);
typedef emacs_value (*makeFuncFunc) (emacs_env *env,
ptrdiff_t min_arity,
ptrdiff_t max_arity,
emacs_value (*function) (emacs_env *env,
ptrdiff_t nargs,
emacs_value args[],
void *)
EMACS_NOEXCEPT,
const char *documentation,
void *data);
typedef emacs_value (*funcallFunc) (emacs_env *env,
emacs_value function,
ptrdiff_t nargs,
emacs_value args[]);
typedef emacs_value (*makeIntegerFunc) (emacs_env *env, intmax_t value);
typedef emacs_value (*make_string) (emacs_env *env,
const char *contents, ptrdiff_t length);
// these are c functions to call c function pointers
emacs_value bridge_intern(internFunc f, emacs_env *env, const char *symbol_name) {
return f(env, symbol_name);
}
emacs_value bridge_funcall(funcallFunc f,emacs_env *env,
emacs_value function,
ptrdiff_t nargs,
emacs_value args[]) {
return f(env, function, nargs, args);
}
emacs_env* bridge_getenv(getEnvFunc f, struct emacs_runtime *ert) {
return f(ert);
}
emacs_value bridge_makefunction(makeFuncFunc f,emacs_env *env,
ptrdiff_t min_arity,
ptrdiff_t max_arity,
emacs_value (*function) (emacs_env *env,
ptrdiff_t nargs,
emacs_value args[],
void *)
EMACS_NOEXCEPT,
const char *documentation,
void *data) {
return f(env, min_arity, max_arity, function, documentation, data);
}
emacs_value bridge_makeinteger(makeIntegerFunc f, emacs_env *env, intmax_t value) {
return f(env, value);
}
emacs_value Fmymod_test(emacs_env* env , ptrdiff_t nargs , emacs_value args[], char* dataemacs_value);
emacs_value CallMyFunction(emacs_env* env , ptrdiff_t nargs , emacs_value args[], char* data) {
return Fmymod_test(env, nargs, args, data);
}
package main
// #cgo CFLAGS: -I /home/shansen/code/emacs-25.2/src/
// #include <emacs-module.h>
// #include <stdlib.h>
// typedef emacs_value (*internFunc) (emacs_env *env, const char *symbol_name);
// typedef emacs_env *(*getEnvFunc) (struct emacs_runtime *ert);
// typedef emacs_value (*makeFuncFunc) (emacs_env *env,
// ptrdiff_t min_arity,
// ptrdiff_t max_arity,
// emacs_value (*function) (emacs_env *env,
// ptrdiff_t nargs,
// emacs_value args[],
// void *)
// EMACS_NOEXCEPT,
// const char *documentation,
// void *data);
// typedef emacs_value (*funcallFunc) (emacs_env *env,
// emacs_value function,
// ptrdiff_t nargs,
// emacs_value args[]);
// typedef emacs_value (*makeIntegerFunc) (emacs_env *env, intmax_t value);
// extern emacs_value bridge_makeinteger(makeIntegerFunc f, emacs_env *env, intmax_t value);
// extern emacs_value bridge_intern(internFunc f, emacs_env *env, const char *symbol_name);
// extern emacs_value bridge_funcall(funcallFunc f,emacs_env *env,
// emacs_value function,
// ptrdiff_t nargs,
// emacs_value args[]);
// extern emacs_env* bridge_getenv(getEnvFunc f, struct emacs_runtime *ert);
// extern emacs_value bridge_makefunction(makeFuncFunc f,emacs_env *env,
// ptrdiff_t min_arity,
// ptrdiff_t max_arity,
// emacs_value (*function) (emacs_env *env,
// ptrdiff_t nargs,
// emacs_value args[],
// void *)
// EMACS_NOEXCEPT,
// const char *documentation,
// void *data);
// extern emacs_value CallMyFunction(emacs_env* env , ptrdiff_t nargs , emacs_value args[], char* data);
// extern emacs_value (*make_string) (emacs_env *env,
// const char *contents, ptrdiff_t length);
import "C"
import "sync"
import "time"
func main() {
}
//export plugin_is_GPL_compatible
func plugin_is_GPL_compatible() C.int {
return 1
}
var once sync.Once
var tchan = make(chan int64, 1)
//export Fmymod_test
func Fmymod_test(env *C.emacs_env, nargs C.ptrdiff_t, args *C.emacs_value, data *C.char) C.emacs_value {
// silly goroutine demo
once.Do(func() {
go func() {
for {
select {
case tchan <- time.Now().Unix():
default:
}
time.Sleep(time.Second)
}
}()
})
select {
case val := <-tchan:
return C.bridge_makeinteger(env.make_integer, env, C.intmax_t(val))
default:
return C.bridge_makeinteger(env.make_integer, env, 0)
}
}
func bind_function(env *C.emacs_env, name *C.char, Sfun C.emacs_value) {
/* Set the function cell of the symbol named NAME to SFUN using
the 'fset' function. */
/* Convert the strings to symbols by interning them */
str := C.CString("fset")
// defer C.free(unsafe.Pointer(str))
var Qfset C.emacs_value = C.bridge_intern(env.intern, env, str)
var Qsym C.emacs_value = C.bridge_intern(env.intern, env, name)
/* Prepare the arguments array */
var args []C.emacs_value = []C.emacs_value{Qsym, Sfun}
/* Make the call (2 == nb of arguments) */
C.bridge_funcall(env.funcall, env, Qfset, C.ptrdiff_t(len(args)), &args[0])
}
//export emacs_module_init
func emacs_module_init(ert *C.struct_emacs_runtime) C.int {
env := C.bridge_getenv(ert.get_environment, ert)
/* create a lambda (returns an emacs_value) */
docs := C.CString("my documentation")
var fun C.emacs_value = C.bridge_makefunction(env.make_function, env,
0, /* min. number of arguments */
0, /* max. number of arguments */
(*[0]byte)(C.CallMyFunction), /* actual function pointer */
docs, /* docstring */
nil, /* user pointer of your choice (data param in Fmymod_test) */
)
modtest := C.CString("mymod-test")
bind_function(env, modtest, fun)
mymod := C.CString("mymod")
provide(env, mymod)
/* loaded successfully */
return 0
}
/* Provide FEATURE to Emacs. */
func provide(env *C.emacs_env, feature *C.char) {
/* call 'provide' with FEATURE converted to a symbol */
prov := C.CString("provide")
var Qfeat C.emacs_value = C.bridge_intern(env.intern, env, feature)
var Qprovide C.emacs_value = C.bridge_intern(env.intern, env, prov)
var args []C.emacs_value = []C.emacs_value{Qfeat}
C.bridge_funcall(env.funcall, env, Qprovide, C.ptrdiff_t(len(args)), &args[0])
}
(load-file "./mymod.so")
(print (mymod-test))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment