/ gui-lib / framework / keybinding-lang.rkt
keybinding-lang.rkt
 1  #lang scheme
 2  (require mred
 3           string-constants
 4           framework
 5           scheme/class)
 6  
 7  (provide (rename-out (kl-module-begin #%module-begin))
 8           (except-out (all-from-out scheme) #%module-begin)
 9           (all-from-out framework
10                         mred
11                         scheme/class))
12  
13  (define-syntax (kl-module-begin stx)
14    (syntax-case stx ()
15      [(mb a ...) 
16       (with-syntax ([#%keymap (datum->syntax (syntax mb) '#%keymap)]
17                     [#%keybinding (datum->syntax (syntax mb) '#%keybinding)]
18                     [keybinding (datum->syntax (syntax mb) 'keybinding)])
19         (syntax (#%plain-module-begin 
20                  (define #%keymap (make-object keymap:aug-keymap%))
21                  (provide #%keymap)
22                  (define name-counter (make-hash))
23                  (define (unique-name raw-name)
24                    (let ([last-number (hash-ref name-counter raw-name #f)])
25                      (cond
26                        [last-number
27                         (hash-set! name-counter raw-name (+ last-number 1))
28                         (format "~a:~a" raw-name last-number)]
29                        [else
30                         (hash-set! name-counter raw-name 2)
31                         raw-name])))
32                  (define (#%keybinding key proc src line col pos)
33                    (unless (string? key)
34                      (error 'keybinding "expected string as first argument, got ~e (other arg ~e)" key proc))
35                    (unless (and (procedure? proc)
36                                 (procedure-arity-includes? proc 2))
37                      (error 'keybinding "expected procedure of two arguments as second argument, got ~e (other arg ~e)"
38                             proc
39                             key))
40                    (let ([name 
41                           (unique-name
42                            (cond
43                              [(symbol? (object-name proc))
44                               (format "~a" (object-name proc))]
45                              [(and line col)
46                               (format "~a:~a.~a" src line col)]
47                              [else
48                               (format "~a:~a" src pos)]))])
49                      (send #%keymap add-function name 
50                            (λ (x y)
51                              (let ([end-edit-sequence
52                                     (λ ()
53                                       (when (is-a? x editor<%>)
54                                         (let loop ()
55                                           (when (send x in-edit-sequence?)
56                                             (send x end-edit-sequence)
57                                             (loop)))))])
58                                (with-handlers ([exn:fail? 
59                                                 (λ (x)
60                                                   (end-edit-sequence)
61                                                   (message-box (string-constant drscheme)
62                                                                (format (string-constant user-defined-keybinding-error) 
63                                                                        name
64                                                                        (exn-message x))))])
65                                  (proc x y)
66                                  (when (is-a? x editor<%>)
67                                    (when (send x in-edit-sequence?)
68                                      (end-edit-sequence)
69                                      (message-box (string-constant drscheme)
70                                                   (format (string-constant user-defined-keybinding-error) 
71                                                           name
72                                                           "Editor left in edit-sequence"))))))))
73                      (send #%keymap map-function key name)))
74                  (define-syntax (keybinding stx)
75                    (syntax-case stx ()
76                      [(_ key val)
77                       (with-syntax ([src (syntax-source stx)]
78                                     [line (syntax-line stx)]
79                                     [col (syntax-column stx)]
80                                     [pos (syntax-position stx)])
81                         (syntax (#%keybinding key val 'src 'line 'col 'pos)))]))
82                  a ...)))]))