package ecaml

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file keymap.ml

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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
open! Core_kernel
open! Import

module Q = struct
  include Q

  let copy_keymap = "copy-keymap" |> Symbol.intern
  and current_global_map = "current-global-map" |> Symbol.intern
  and define_key = "define-key" |> Symbol.intern
  and keymap_parent = "keymap-parent" |> Symbol.intern
  and lookup_key = "lookup-key" |> Symbol.intern
  and make_keymap = "make-keymap" |> Symbol.intern
  and make_sparse_keymap = "make-sparse-keymap" |> Symbol.intern
  and minor_mode_map_alist = "minor-mode-map-alist" |> Symbol.intern
  and minor_mode_overriding_map_alist =
    "minor-mode-overriding-map-alist" |> Symbol.intern
  and set_keymap_parent = "set-keymap-parent" |> Symbol.intern
  and set_transient_map = "set-transient-map" |> Symbol.intern
  and special_event_map = "special-event-map" |> Symbol.intern
  and suppress_keymap = "suppress-keymap" |> Symbol.intern
  and undefined = "undefined" |> Symbol.intern
  and use_global_map = "use-global-map" |> Symbol.intern
end

include Value.Make_subtype (struct
    let name = "keymap"
    let here = [%here]
    let is_in_subtype = Value.is_keymap
  end)

type keymap = t [@@deriving sexp_of]

let equal = eq

let parent t =
  let result = Symbol.funcall1 Q.keymap_parent (t |> to_value) in
  if Value.is_nil result then None else Some (result |> of_value_exn)
;;

let set_parent t parent =
  Symbol.funcall2_i
    Q.set_keymap_parent
    (t |> to_value)
    (match parent with
     | None -> Value.nil
     | Some parent -> parent |> to_value)
;;

let set_transient t = Symbol.funcall1_i Q.set_transient_map (t |> to_value)

module Kind = struct
  type t =
    | Full
    | Sparse
  [@@deriving sexp_of]
end

let create ?(kind = Kind.Sparse) ?menu_name () =
  Symbol.funcall1
    (match kind with
     | Full -> Q.make_keymap
     | Sparse -> Q.make_sparse_keymap)
    (match menu_name with
     | None -> Value.nil
     | Some menu_name -> menu_name |> Value.of_utf8_bytes)
  |> of_value_exn
;;

let deep_copy t = Symbol.funcall1 Q.copy_keymap (t |> to_value) |> of_value_exn
let global () = Symbol.funcall0 Q.current_global_map |> of_value_exn
let set_global t = Symbol.funcall1_i Q.use_global_map (t |> to_value)

module Entry = struct
  type t =
    | Absent
    | Command of Command.t
    | Keyboard_macro of Key_sequence.t
    | Keymap of keymap
    | Symbol of Symbol.t
    | Undefined
    | Value of Value.t
  [@@deriving sexp_of]

  let to_value = function
    | Absent -> Value.nil
    | Command c -> c |> Command.to_value
    | Keyboard_macro k -> k |> Key_sequence.to_value
    | Keymap k -> k |> to_value
    | Symbol s -> s |> Symbol.to_value
    | Undefined -> Q.undefined |> Symbol.to_value
    | Value v -> v
  ;;

  let of_value_exn value =
    if Value.is_nil value
    then Absent
    else if Value.is_command value
    then Command (value |> Command.of_value_exn)
    else if Value.is_keymap value
    then Keymap (value |> of_value_exn)
    else if Value.eq value (Q.undefined |> Symbol.to_value)
    then Undefined
    else if Value.is_symbol value
    then Symbol (value |> Symbol.of_value_exn)
    else (
      match Key_sequence.of_value_exn value with
      | k -> Keyboard_macro k
      | exception _ -> Value value)
  ;;

  let type_ =
    Value.Type.create [%sexp "Keymap.Entry"] [%sexp_of: t] of_value_exn to_value
  ;;
end

let lookup_key_exn ?(accept_defaults = false) t key_sequence =
  let result =
    Symbol.funcall3
      Q.lookup_key
      (t |> to_value)
      (key_sequence |> Key_sequence.to_value)
      (accept_defaults |> Value.of_bool)
  in
  if Value.is_integer result
  then
    raise_s
      [%message
        "[Keymap.lookup_key_exn] got too long key sequence"
          (key_sequence : Key_sequence.t)];
  result |> Entry.of_value_exn
;;

let define_key t key_sequence entry =
  Symbol.funcall3_i
    Q.define_key
    (t |> to_value)
    (key_sequence |> Key_sequence.to_value)
    (entry |> Entry.to_value)
;;

let minor_mode_map_alist =
  Var.create Q.minor_mode_map_alist Value.Type.(list (tuple Symbol.type_ type_))
;;

let minor_mode_overriding_map_alist =
  Buffer_local.wrap_existing
    Q.minor_mode_overriding_map_alist
    Value.Type.(list (tuple Symbol.type_ type_))
;;

let find_minor_mode_map assoc symbol = List.Assoc.find assoc symbol ~equal:Symbol.equal

let override_minor_mode_map symbol ~f =
  match
    find_minor_mode_map
      (Buffer_local.Private.get_in_current_buffer minor_mode_overriding_map_alist)
      symbol
  with
  | Some t -> f t
  | None ->
    let t =
      match
        find_minor_mode_map (Current_buffer0.value_exn minor_mode_map_alist) symbol
      with
      | Some t -> deep_copy t
      | None -> create ()
    in
    f t;
    Buffer_local.Private.set_in_current_buffer
      minor_mode_overriding_map_alist
      ((symbol, t)
       :: Buffer_local.Private.get_in_current_buffer minor_mode_overriding_map_alist)
;;

let special_event_map = Var.create Q.special_event_map type_

let suppress_keymap ?(suppress_digits = false) t =
  Symbol.funcall2_i Q.suppress_keymap (t |> to_value) (suppress_digits |> Value.of_bool)
;;