1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
-module(edit_keymap).
-export([start_link_server/0, new/1, keymap_exists/1,
global_set_key/2, set_key/3,
bind/3, bind_each/2, delete/1, lookup/2, test/0]).
-export([server/0]).
start_link_server() ->
case whereis(?MODULE) of
Pid when is_pid(Pid) ->
{error, {already_started, Pid}};
undefined ->
Pid = spawn_link(?MODULE, server, []),
register(?MODULE, Pid),
{ok, Pid}
end.
server() ->
receive
{request, From, {create, Name}} ->
Reply = case keymap_exists(Name) of
true ->
{error, {already_exists, Name}};
false ->
ets:new(Name, [named_table, set, public]),
Name
end,
From ! {reply, Reply};
_ ->
true
end,
server().
new(Name) ->
?MODULE ! {request, self(), {create, Name}},
receive {reply, R} -> R end.
keymap_exists(Name) ->
case ets:info(Name) of
undefined ->
false;
_ ->
true
end.
global_set_key(KeySeq, Binding) ->
set_key(global_map, KeySeq, Binding).
%% e.g. set_key(edit_globalmap, "C-x C-f", {edit_file, find_file, []})
set_key(KeyMap, KeySeq, Binding) ->
set_key_traverse(KeyMap, string:tokens(KeySeq, " "), Binding).
set_key_traverse(KeyMap, [Key], Binding) ->
bind(KeyMap, Key, Binding),
ok;
set_key_traverse(KeyMap, [MapKey | KeySeq], Binding) ->
case lookup(KeyMap, MapKey) of
{_, {keymap, SubMap}} ->
set_key_traverse(SubMap, KeySeq, Binding);
_ ->
error
end.
bind(Keymap, Key, Value) ->
ets:insert(Keymap, {Key, Value}).
%% Bind each item of a key-value list.
bind_each(Name, KVList) ->
lists:foreach(fun({Key, Value}) -> bind(Name, Key, Value) end,
KVList).
lookup(Name, Key) ->
%% First lookup by key-code number
case ets:lookup(Name, Key) of
[{Key, Value}] ->
{ok, Value};
[] ->
%% Next lookup by stringified name
String = edit_util:keyname(Key),
case ets:lookup(Name, String) of
[{String, Value}] ->
{ok, Value};
[] ->
unbound
end
end.
delete(Name) ->
ets:delete(Name).
test() ->
Map = new(test),
unbound = lookup(Map, key),
bind(Map, key, value),
{ok, value} = lookup(Map, key),
bind(Map, key, newvalue),
{ok, newvalue} = lookup(Map, key),
delete(Map),
ok.
|