aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/edit_keymap.erl
blob: c69c37df6c589db999416b92c38b6ab96df1056f (plain)
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.