AtlatestRepositorysigil-hooks
sigil-hooks / tree / src / sigilhooks.sgl
1
;;; (sigil hooks) - Emacs-Style Hook System2
;;;3
;;; Hooks are lists of functions called when specific events occur.4
;;; Multiple handlers can be registered for each hook and are called5
;;; in order of registration.6
;;;7
;;; ## Basic Usage8
;;;9
;;; ```scheme10
;;; (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: First19
;;; ; Second20
;;; ```21
;;;22
;;; ## Passing Arguments23
;;;24
;;; ```scheme25
;;; (define on-file-save (make-hook))26
;;;27
;;; (add-hook! on-file-save28
;;; (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
(export37
make-hook38
hook?39
add-hook!40
remove-hook!41
clear-hook!42
run-hook43
run-hook-with-args44
hook-empty?)46
(begin48
;; A hook is a vector: #(hook handlers)49
;; where handlers is a list of functions51
;;; Create a new empty hook.52
;;;53
;;; ```scheme54
;;; (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
;;; ```scheme63
;;; (hook? my-hook) ; => #t64
;;; (hook? '()) ; => #f65
;;; ```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 list73
(define (hook-handlers hook)74
(vector-ref hook 1))76
;; Internal: set handlers list77
(define (hook-handlers-set! hook handlers)78
(vector-set! hook 1 handlers))80
;;; Check if a hook has no handlers.81
;;;82
;;; ```scheme83
;;; (hook-empty? (make-hook)) ; => #t84
;;; ```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
;;; ```scheme94
;;; (add-hook! my-hook (lambda () (display "Called!")))95
;;; ```96
(define (add-hook! hook func)97
(: hook? procedure? -> void?)98
(hook-handlers-set! hook99
(append (hook-handlers hook) (list func))))101
;;; Remove a function from a hook.102
;;;103
;;; The function is matched by identity (eq?).104
;;;105
;;; ```scheme106
;;; (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! hook113
(filter (lambda (f) (not (eq? f func)))114
(hook-handlers hook))))116
;;; Remove all handlers from a hook.117
;;;118
;;; ```scheme119
;;; (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
;;; ```scheme130
;;; (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
;;; ```scheme141
;;; (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
))