1 /+ dub.json:
2 {
3   "name": "emacs-dman",
4   "targetType": "dynamicLibrary",
5   "dependencies": {
6     "d-emacs-module": { "path": ".." }
7   }
8 }
9 +/
10 // How to test
11 // $ dub build --single ./dman.d
12 // $ emacs -batch -l dman_test.el
13 
14 module dman;
15 
16 import emacs_module.deimos;
17 
18 import core.runtime: Runtime;
19 import std.datetime.systime : Clock;
20 import std.format : format;
21 import std.string : fromStringz;
22 
23 
24 private enum string dman = `
25  o       o
26  |        \
27   \ ___   /
28    |,-oo\\
29    ||    || < %s
30    ||    ||
31    ||   //
32    ||__//
33    '---
34     \  \
35     /  /
36     ^  ^
37 `;
38 
39 // Wraps elisp "message" func with dman.
40 private void dman_message(T)(emacs_env* env, T arg) {
41   emacs_value func = env.intern(env, "message");
42   emacs_value[1] args;
43   string hello = format!dman(arg);
44   args[0] = env.make_string(env, hello.ptr, hello.length);
45   env.funcall(env, func, args.length, args.ptr);
46 }
47 
48 // Returns true if type of value is string.
49 bool stringp(emacs_env* env, emacs_value value) {
50   return env.eq(env, env.type_of(env, value), env.intern(env, "string"));
51 }
52 
53 // Functions bellow are exported to emacs.
54 extern (C):
55 
56 int plugin_is_GPL_compatible;
57 
58 emacs_value dman_time(
59     emacs_env* env, ptrdiff_t nargs, emacs_value* args, void* data) {
60   dman_message(env, Clock.currTime());
61   return env.intern(env, "t");
62 }
63 
64 emacs_value dman_say(
65     emacs_env* env, ptrdiff_t nargs, emacs_value* args, void* data) {
66   if (nargs == 1 && stringp(env, args[0])) {
67     string str;
68     char[128] buf;
69     ptrdiff_t size = buf.length;
70     // TODO(karita): Use dynamic array and handle errors.
71     env.copy_string_contents(env, args[0], buf.ptr, &size);
72     dman_message(env, fromStringz(buf));
73     return env.intern(env, "t");
74   }
75   dman_message(env, "Usage: (dman-say [string])");
76   return env.intern(env, "nil");
77 }
78 
79 int emacs_module_init(emacs_runtime* ert) {
80   // Validate Emacs runtime and environment.
81   if (ert.size < emacs_runtime.sizeof)
82     return 1;
83 
84   emacs_env* env = ert.get_environment(ert);
85   if (env.size < emacs_env.sizeof)
86     return 2;
87 
88   // Initialize D runtime.
89   Runtime.initialize();
90   dman_message(env, "Hello Emacs from D!!");
91 
92   // Register functions.
93   emacs_value[2] fn_sym_pair;
94   fn_sym_pair[0] = env.intern(env, "dman-time");
95   fn_sym_pair[1] = env.make_function(
96       env, /*min_arity=*/0, /*max_arity=*/0,
97       /*function=*/&dman_time,
98       /*documentation=*/"Dman tells you current time.",
99       /*data=*/null);
100   env.funcall(env, env.intern(env, "defalias"),
101               fn_sym_pair.length, fn_sym_pair.ptr);
102 
103   fn_sym_pair[0] = env.intern(env, "dman-say");
104   fn_sym_pair[1] = env.make_function(
105       env, /*min_arity=*/1, /*max_arity=*/1,
106       /*function=*/&dman_say,
107       /*documentation=*/"Dman repeats your string.",
108       /*data=*/null);
109   env.funcall(env, env.intern(env, "defalias"),
110               fn_sym_pair.length, fn_sym_pair.ptr);
111 
112   return 0;
113 }