Last active
May 2, 2017 21:26
-
-
Save shanemhansen/ae13a4730f038714fa4d7984a8a64454 to your computer and use it in GitHub Desktop.
Using go to write emacs plugins
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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