summaryrefslogtreecommitdiff
path: root/scheme/mit/geiser/emacs.scm
blob: d94c10534418c6c0ed46d9ea634dd631777fcedb (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
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
;;;; package: (runtime geiser)
(declare (usual-integrations))

(load-option 'format)

(define (all-completions prefix environment)
  (let (;; (prefix
        ;;  (if (environment-lookup environment 'PARAM:PARSER-CANONICALIZE-SYMBOLS?)
        ;;      (string-downcase prefix)
        ;;      prefix))
        (completions '()))
    (for-each-interned-symbol
     (lambda (symbol)
       (if (and (string-prefix-ci? prefix (symbol-name symbol)) ; was string-prefix?, now defaults to case-insensitive (MIT/GNU Scheme's default)
                (environment-bound? environment symbol))
           (set! completions (cons (symbol-name symbol) completions)))
       unspecific))
    completions))

(define (operator-arglist symbol env)
  (let ((type (environment-reference-type env symbol)))
    (let ((ans (if (eq? type 'normal)
                   (let ((binding (environment-lookup env symbol)))
                     (if (and binding
                              (procedure? binding))
                         (cons symbol (read-from-string (string-trim (with-output-to-string
                                                                       (lambda () (pa binding))))))
                         #f))
                   #f ;; macros
                   )))
      ans)))

(define (geiser:operator-arglist symbol env)
  (let* ((arglist (operator-arglist symbol env))
         (operator symbol))
    (if arglist
        (let loop ((arglist (cdr arglist))
                   (optionals? #f)
                   (required '())
                   (optional '()))
          (cond ((null? arglist)
                 `(,operator ("args" (("required" ,@(reverse required)) ("optional" ,@(reverse optional)) ("key"))))) ;; ("module" ,module)
                ((symbol? arglist)
                 (loop '()
                       #t
                       required
                       (cons "..." (cons arglist optional))))
                ((eq? (car arglist) #!optional)
                 (loop (cdr arglist)
                       #t
                       required
                       optional))
                (else
                 (loop
                  (cdr arglist)
                  optionals?
                  (if optionals? required (cons (car arglist) required))
                  (if optionals? (cons (car arglist) optional) optional)))))
        '())))


(define (read-from-string str)
  (with-input-from-string str
    read))

(define (all-packages)
  (let loop ((package (name->package '()))) ;;  system-global-package
    (cons package
          (append-map loop (package/children package)))))

(define anonymous-package-prefix
  "environment-")

(define (env->pstring env)
  (let ((package (environment->package env)))
    (if package
        (write-to-string (package/name package))
        (string anonymous-package-prefix (object-hash env)))))

(define geiser-repl (nearest-repl))

(define (set-geiser-repl-prompt! env)
  (set-repl/prompt! geiser-repl (format #f "~s =>" (package/name (environment->package env))))
  env)

(define geiser-env #f)

(define (get-symbol-definition-location object)
  (let ((file (cond ((and (entity? object)
                          (procedure? object))
                     (receive (a b)
                         (compiled-entry/filename-and-index (entity-procedure object))
                       b
                       a))
                    ((compiled-procedure? object)
                     (receive (a b)
                         (compiled-entry/filename-and-index object)
                       b
                       a))
                    (else
                     '()))))
    (fix-mit-source-dir
     (if (and (string? file)
              (string-suffix? ".inf" file))
         (string-append (substring file 0 (- (string-length file) 3)) "scm")
         file))))

(define (fix-mit-source-dir filename)
  (let ((default-location "/usr/lib/mit-scheme-x86-64/"))
    (if (and geiser:mit-scheme-source-directory
             (not (string-null? geiser:mit-scheme-source-directory)))
        (if (string-prefix? default-location filename)
            (string-append geiser:mit-scheme-source-directory (substring filename (string-length default-location) (string-length filename)))
            filename)
        filename)))

(define geiser:mit-scheme-source-directory #f)

;;;; ***************************************************************************

(define (geiser:eval module form . rest)
  rest
  (let* ((output (open-output-string))
         (environment (package/environment (find-package (if module module '(user)) #t)))
         (result (with-output-to-port output
                   (lambda ()
                     (eval form environment)))))
    (write `((result ,(write-to-string result)) (output . ,(get-output-string output))))))

(define (geiser:autodoc ids . rest)
  rest
  (cond ((null? ids) '())
        ((not (list? ids))
         (geiser:autodoc (list ids)))
        ((not (symbol? (car ids)))
         (geiser:autodoc (cdr ids)))
        (else
         (let ((details (map (lambda (id) (geiser:operator-arglist id (->environment '(user)))) ids)))
           details))))

(define (geiser:module-completions prefix . rest)
  rest
  (filter (lambda (pstring)
            (substring? prefix (write-to-string pstring)))
          (map (lambda (package) (env->pstring (package/environment package))) (all-packages))))

(define (geiser:completions prefix . rest)
  rest
  (sort (all-completions prefix (->environment '(user)))
        string<?))

(define (geiser:ge environment)
  (let ((env (package/environment (find-package environment #t))))
    (set-geiser-repl-prompt! env)
    (set! geiser-env env))
  (ge environment))

(define (geiser:load-file filename)
  (load filename))

(define (geiser:module-exports module)
  (let* ((pkg (find-package module #t))
         (children (map package/name (package/children pkg)))
         (env (package/environment pkg)))
    (let loop ((vars '())
               (procs '())
               (syntax '())
               (bindings (environment-bindings env)))
      (if (null? bindings)
          `(("vars" . ,vars) ("procs" . ,procs) ("syntax" . ,syntax) ("modules" . ,(map list children)))
          (let* ((binding (car bindings))
                 (name (car binding))
                 (value (if (null? (cdr binding)) 'unassigned (cadr binding)))
                 (ref-type (environment-reference-type env name)))
            (cond ((eq? 'macro ref-type)
                   (loop vars
                         procs
                         (cons `(,name ("signature")) syntax)
                         (cdr bindings)))
                  ((procedure? value)
                   (loop vars
                         (cons `(,name ("signature" . ,(geiser:operator-arglist name env))) procs)
                         syntax
                         (cdr bindings)))
                  (else
                   (loop (cons `(,name) vars)
                         procs
                         syntax
                         (cdr bindings)))))))))

(define (geiser:symbol-documentation symbol)
  (if (environment-bound? geiser-env symbol)
      (let ((ref-type (environment-reference-type geiser-env symbol))
            (value (environment-safe-lookup geiser-env symbol)))
        (case ref-type
          ((macro)
           `(("signature" ,symbol ("args"))
             ("docstring" . "Macro")))
          ((unassigned)
           `(("signature" ,symbol ("args"))
             ("docstring" . "Value: Unassigned~%")))
          ((normal)
           (if (procedure? value)
               (let ((signature (geiser:operator-arglist symbol geiser-env)))
                 `(("signature" . ,signature)
                   ("docstring" . ,(format #f "Procedure:~%~a~%" (with-output-to-string (lambda () (pp value)))))))
               `(("signature" ,symbol ("args"))
                 ("docstring" . ,(format #f "Value:~%~a~%" (with-output-to-string (lambda () (pp value))))))
               ))
          (else
           `(("signature" ,symbol ("args"))
             ("docstring" . "Unknown thing...")))))
      '()))

(define (geiser:symbol-location symbol)
  (if (environment-bound? geiser-env symbol)
      (let ((ref-type (environment-reference-type geiser-env symbol))
            (value (environment-safe-lookup geiser-env symbol)))
        (if (eq? ref-type 'normal)
            (let ((file (get-symbol-definition-location value)))
              `(("name" . ,symbol)
                ("file" . ,file)
                ("line")))
            '()))
      `(("name" . ,symbol)
        ("file")
        ("line"))))

(define (geiser:module-location symbol)
  `(("name" . ,symbol)
    ("file")
    ("line")))


(define (geiser:newline)
  #f)

(define (geiser:no-values)
  #f)

(define (geiser:set-mit-scheme-source-directory dir)
  (set! geiser:mit-scheme-source-directory dir))

(define (geiser:callers symbol)
  symbol
  #f)

(define (geiser:callees symbol)
  symbol
  #f)

(set-geiser-repl-prompt! (package/environment (find-package '(user))))