summaryrefslogtreecommitdiff
path: root/chickadee/readline.scm
blob: ff370e82f487582f84526ae9be9220c4fab31b2e (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
;;; Chickadee Game Toolkit
;;; Copyright © 2021 David Thompson <dthompson2@worcester.edu>
;;;
;;; Chickadee is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published
;;; by the Free Software Foundation, either version 3 of the License,
;;; or (at your option) any later version.
;;;
;;; Chickadee is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program.  If not, see
;;; <http://www.gnu.org/licenses/>.

;;; Commentary
;;
;; GNU readline bindings for use with the Chickadee REPL.  The
;; guile-readline C extension is not compatible with the alternative,
;; callback-based readline interface so here comes the FFI to the
;; rescue.
;;
;;; Code:

(define-module (chickadee readline)
  #:use-module (chickadee config)
  #:use-module (system foreign)
  #:export (bind-readline-variable
            install-readline-handler
            remove-readline-handler
            readline-read-char
            add-readline-history))

;;;
;;; Setup
;;;

(define libreadline (dynamic-link* %libreadline))

(define (readline-func return-type function-name arg-types)
  (pointer->procedure return-type
                      (dynamic-func function-name libreadline)
                      arg-types))

(define-syntax-rule (define-foreign name return-type func-name arg-types)
  (define name
    (readline-func return-type func-name arg-types)))

;;;
;;; Variables
;;;

(define-foreign rl-variable-bind void "rl_variable_bind" '(* *))

(define (bind-readline-variable name value)
  (rl-variable-bind (string->pointer name) (string->pointer value)))

;;;
;;; Callbacks
;;;

(define-foreign rl-callback-handler-install void "rl_callback_handler_install" '(* *))
(define-foreign rl-callback-handler-remove void "rl_callback_handler_remove" '())
(define-foreign rl-callback-read-char void "rl_callback_read_char" '())
(define-foreign rl-callback-sigcleanup void "rl_callback_sigcleanup" '())

(define (install-readline-handler prompt proc)
  (let ((proc-ptr (procedure->pointer void
                                      (lambda (ptr)
                                        (proc (if (null-pointer? ptr)
                                                  ""
                                                  (pointer->string ptr))))
                                      '(*))))
    (rl-callback-handler-install (string->pointer prompt) proc-ptr)))

(define (remove-readline-handler)
  (rl-callback-handler-remove))

(define (readline-read-char)
  (rl-callback-read-char))

;;;
;;; History
;;;

(define-foreign add-history void "add_history" '(*))

(define (add-readline-history line)
  (add-history (string->pointer line)))