AtlatestRepositorysigil-hooks

sigil-hooks / tree / src / sigilhooks.sgl

1;;; (sigil hooks) - Emacs-Style Hook System
2;;;
3;;; Hooks are lists of functions called when specific events occur.
4;;; Multiple handlers can be registered for each hook and are called
5;;; in order of registration.
6;;;
7;;; ## Basic Usage
8;;;
9;;; ```scheme
10;;; (import (sigil hooks))
11;;;
12;;; (define my-hook (make-hook))
13;;;
14;;; (add-hook! my-hook (lambda () (display "First\n")))
15;;; (add-hook! my-hook (lambda () (display "Second\n")))
16;;;
17;;; (run-hook my-hook)
18;;; ; prints: First
19;;; ; Second
20;;; ```
21;;;
22;;; ## Passing Arguments
23;;;
24;;; ```scheme
25;;; (define on-file-save (make-hook))
26;;;
27;;; (add-hook! on-file-save
28;;; (lambda (filename)
29;;; (display "Saved: ")
30;;; (display filename)))
31;;;
32;;; (run-hook-with-args on-file-save "document.txt")
33;;; ```
35(define-library (sigil hooks)
36 (export
37 make-hook
38 hook?
39 add-hook!
40 remove-hook!
41 clear-hook!
42 run-hook
43 run-hook-with-args
44 hook-empty?)
46 (begin
48 ;; A hook is a vector: #(hook handlers)
49 ;; where handlers is a list of functions
51 ;;; Create a new empty hook.
52 ;;;
53 ;;; ```scheme
54 ;;; (define my-hook (make-hook))
55 ;;; ```
56 (define (make-hook)
57 (: -> hook?)
58 (vector 'hook '()))
60 ;;; Check if a value is a hook.
61 ;;;
62 ;;; ```scheme
63 ;;; (hook? my-hook) ; => #t
64 ;;; (hook? '()) ; => #f
65 ;;; ```
66 (define (hook? obj)
67 (: any? -> boolean?)
68 (and (vector? obj)
69 (> (vector-length obj) 0)
70 (eq? (vector-ref obj 0) 'hook)))
72 ;; Internal: get handlers list
73 (define (hook-handlers hook)
74 (vector-ref hook 1))
76 ;; Internal: set handlers list
77 (define (hook-handlers-set! hook handlers)
78 (vector-set! hook 1 handlers))
80 ;;; Check if a hook has no handlers.
81 ;;;
82 ;;; ```scheme
83 ;;; (hook-empty? (make-hook)) ; => #t
84 ;;; ```
85 (define (hook-empty? hook)
86 (: hook? -> boolean?)
87 (null? (hook-handlers hook)))
89 ;;; Add a function to a hook.
90 ;;;
91 ;;; Functions are called in the order they are added.
92 ;;;
93 ;;; ```scheme
94 ;;; (add-hook! my-hook (lambda () (display "Called!")))
95 ;;; ```
96 (define (add-hook! hook func)
97 (: hook? procedure? -> void?)
98 (hook-handlers-set! hook
99 (append (hook-handlers hook) (list func))))
101 ;;; Remove a function from a hook.
102 ;;;
103 ;;; The function is matched by identity (eq?).
104 ;;;
105 ;;; ```scheme
106 ;;; (define my-fn (lambda () ...))
107 ;;; (add-hook! my-hook my-fn)
108 ;;; (remove-hook! my-hook my-fn)
109 ;;; ```
110 (define (remove-hook! hook func)
111 (: hook? procedure? -> void?)
112 (hook-handlers-set! hook
113 (filter (lambda (f) (not (eq? f func)))
114 (hook-handlers hook))))
116 ;;; Remove all handlers from a hook.
117 ;;;
118 ;;; ```scheme
119 ;;; (clear-hook! my-hook)
120 ;;; ```
121 (define (clear-hook! hook)
122 (: hook? -> void?)
123 (hook-handlers-set! hook '()))
125 ;;; Run a hook with no arguments.
126 ;;;
127 ;;; Calls each handler function in order.
128 ;;;
129 ;;; ```scheme
130 ;;; (run-hook my-hook)
131 ;;; ```
132 (define (run-hook hook)
133 (: hook? -> void?)
134 (for-each (lambda (f) (f)) (hook-handlers hook)))
136 ;;; Run a hook with arguments.
137 ;;;
138 ;;; Each handler receives the same arguments.
139 ;;;
140 ;;; ```scheme
141 ;;; (run-hook-with-args on-save-hook filename buffer)
142 ;;; ```
143 (define (run-hook-with-args hook . args)
144 (: hook? any? ... -> void?)
145 (for-each (lambda (f) (apply f args))
146 (hook-handlers hook)))
148 ))