summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJose Antonio Ortega Ruiz <jao@gnu.org>2009-08-17 04:18:02 +0200
committerJose Antonio Ortega Ruiz <jao@gnu.org>2009-08-17 04:18:02 +0200
commit283e6f040449bb4f740991956007332c48308b38 (patch)
treea33bb00a155f11149b361f97aeebe2c0a1cc05ae
parent9d64bcb33f7ac1b3a06220842d04ce3c0534948e (diff)
downloadgeiser-chez-283e6f040449bb4f740991956007332c48308b38.tar.gz
geiser-chez-283e6f040449bb4f740991956007332c48308b38.tar.bz2
Simpler, more correct and efficient autodoc implementation.
Not that it was difficult: it's replacing an ugly kludge.
-rw-r--r--elisp/geiser-autodoc.el148
-rw-r--r--elisp/geiser-syntax.el27
-rw-r--r--scheme/guile/geiser/doc.scm85
-rw-r--r--scheme/plt/geiser/autodoc.ss97
4 files changed, 149 insertions, 208 deletions
diff --git a/elisp/geiser-autodoc.el b/elisp/geiser-autodoc.el
index 1225f87..16ca9ac 100644
--- a/elisp/geiser-autodoc.el
+++ b/elisp/geiser-autodoc.el
@@ -46,14 +46,6 @@
'font-lock-function-name-face
geiser-autodoc "highlighting procedure name in autodoc messages")
-(geiser-custom--defface autodoc-optional-arg-marker
- 'font-lock-keyword-face
- geiser-autodoc "highlighting #:opt marker in autodoc messages")
-
-(geiser-custom--defface autodoc-key-arg-marker
- 'font-lock-keyword-face
- geiser-autodoc "highlighting #:key marker in autodoc messages")
-
(defcustom geiser-autodoc-delay 0.3
"Delay before autodoc messages are fetched and displayed, in seconds."
:type 'number
@@ -74,82 +66,92 @@ when `geiser-autodoc-display-module-p' is on."
;;; Procedure arguments:
(make-variable-buffer-local
- (defvar geiser-autodoc--last nil))
-
-(make-variable-buffer-local
- (defvar geiser-autodoc--last-result nil))
-
-(defun geiser-autodoc--function-args (form)
- (if (equal (car geiser-autodoc--last) form) (cdr geiser-autodoc--last)
- (when form
- (let ((res (geiser-eval--send/result
- `(:eval ((:ge autodoc) (quote (:scm ,form))))
- 500)))
- (when (and res (listp res))
- (unless (equalp res geiser-autodoc--last-result)
- (setq geiser-autodoc--last-result res)
- (setq geiser-autodoc--last
- (cons form
- (geiser-autodoc--str (cdr (assoc 'signature res))
- (or (cdr (assoc 'position res)) 0)
- (cdr (assoc 'module res))))))
- (cdr geiser-autodoc--last))))))
-
-(defun geiser-autodoc--insert-arg (arg current pos)
- (let ((p (point))
- (str (format "%s" (cond ((eq arg 'geiser-rest_marker) ".")
- ((eq arg 'geiser-opt_marker) "#:opt")
- ((eq arg 'geiser-key_marker) "#:key")
- (t arg))))
- (face (cond ((eq 'geiser-opt_marker arg)
- 'geiser-font-lock-autodoc-optional-arg-marker)
- ((eq 'geiser-key_marker arg)
- 'geiser-font-lock-autodoc-key-arg-marker)
- ((= current pos)
- 'geiser-font-lock-autodoc-current-arg)
- (t nil))))
- (insert str)
- (when (listp arg)
- (save-excursion
- (replace-regexp "(quote \\(.*\\))" "'\\1" nil p (point))
- (replace-string "nil" "()" t p (point))))
- (when face (put-text-property p (point) 'face face))))
+ (defvar geiser-autodoc--cached-signatures nil))
+
+(defun geiser-autodoc--get-signatures (funs)
+ (when funs
+ (let ((missing) (cached))
+ (if (not geiser-autodoc--cached-signatures)
+ (setq missing funs)
+ (dolist (f funs)
+ (let ((cf (assq f geiser-autodoc--cached-signatures)))
+ (if cf (push cf cached)
+ (push f missing)))))
+ (unless cached
+ (setq geiser-autodoc--cached-signatures nil))
+ (if (not missing)
+ geiser-autodoc--cached-signatures
+ (let ((res (geiser-eval--send/result `(:eval ((:ge autodoc)
+ (quote ,missing)))
+ 500)))
+ (when res
+ (setq geiser-autodoc--cached-signatures (append cached res))))))))
+
+(defun geiser-autodoc--insert-args (args current &optional pos)
+ (dolist (a args)
+ (let ((p (point)))
+ (insert (format "%s" a))
+ (when (or (and (numberp pos)
+ (numberp current)
+ (setq current (1+ current))
+ (= (1+ pos) current))
+ (and (symbolp current)
+ (listp a)
+ (eq current (car a))))
+ (put-text-property p (point) 'face 'geiser-font-lock-autodoc-current-arg)
+ (setq pos nil current nil)))
+ (insert " "))
+ (when args (backward-char))
+ current)
(defsubst geiser-autodoc--proc-name (proc module)
(let ((str (if module
(format geiser-autodoc-procedure-name-format module proc)
proc)))
- (put-text-property 0 (length str)
- 'face 'geiser-font-lock-autodoc-procedure-name
- str)
- str))
-
-(defun geiser-autodoc--str (signature pos module)
- (when (consp signature)
- (let* ((proc (car signature))
- (args (cdr signature))
- (len (if (listp args) (length args) 0))
- (current 1)
- (pos (if (> pos len) len pos)))
- (if (eq args 'variable)
- (geiser-autodoc--proc-name proc module)
- (save-current-buffer
- (set-buffer (geiser-syntax--font-lock-buffer))
- (erase-buffer)
- (insert (format "(%s" (geiser-autodoc--proc-name proc module)))
- (dolist (a args)
- (insert " ")
- (geiser-autodoc--insert-arg a current pos)
- (setq current (1+ current)))
- (insert ")")
- (buffer-string))))))
+ (propertize str 'face 'geiser-font-lock-autodoc-procedure-name)))
+
+(defun geiser-autodoc--str (proc desc signature)
+ ;; (message "composing %s with desc %s and signature %s" proc desc signature)
+ (let ((cpos 1)
+ (pos (second desc))
+ (prev (third desc))
+ (module (cdr (assoc 'module signature)))
+ (reqs (cdr (assoc 'required signature)))
+ (opts (cdr (assoc 'optional signature)))
+ (keys (cdr (assoc 'key signature))))
+ (save-current-buffer
+ (set-buffer (geiser-syntax--font-lock-buffer))
+ (erase-buffer)
+ (insert (format "(%s " (geiser-autodoc--proc-name proc module)))
+ (setq cpos
+ (geiser-autodoc--insert-args reqs cpos (and (not (zerop pos)) pos)))
+ (when opts
+ (insert " [")
+ (setq cpos (geiser-autodoc--insert-args opts cpos pos))
+ (when keys
+ (insert " [")
+ (geiser-autodoc--insert-args keys prev nil)
+ (insert "]"))
+ (insert "]"))
+ (insert ")")
+ (buffer-string))))
+
+(defun geiser-autodoc--autodoc (path)
+ (let* ((funs (nreverse (mapcar 'car path)))
+ (signs (geiser-autodoc--get-signatures funs)))
+ (when signs
+ (catch 'signature
+ (dolist (f funs)
+ (let ((signature (cdr (assq f signs))))
+ (when signature
+ (throw 'signature (geiser-autodoc--str f (assq f path) signature)))))))))
;;; Autodoc function:
(defun geiser-autodoc--eldoc-function ()
(condition-case e
- (geiser-autodoc--function-args (geiser-syntax--get-partial-sexp))
+ (geiser-autodoc--autodoc (geiser-syntax--scan-sexps))
(error (format "Autodoc not available (%s)" (error-message-string e)))))
diff --git a/elisp/geiser-syntax.el b/elisp/geiser-syntax.el
index db1c842..475a556 100644
--- a/elisp/geiser-syntax.el
+++ b/elisp/geiser-syntax.el
@@ -94,6 +94,33 @@
(defsubst geiser-syntax--beginning-of-form ()
(memq (char-after (point)) '(?\" ?\()))
+(defun geiser-syntax--scan-sexp ()
+ (let ((p (point))
+ (n -1)
+ prev
+ head)
+ (ignore-errors
+ (backward-up-list)
+ (save-excursion
+ (forward-char)
+ (skip-syntax-forward "^_w" p)
+ (when (setq head (symbol-at-point))
+ (while (< (point) p)
+ (setq n (1+ n))
+ (setq prev (symbol-at-point))
+ (forward-sexp))))
+ (if head (list head n prev) 'skip))))
+
+(defun geiser-syntax--scan-sexps ()
+ (save-excursion
+ (goto-char (or (nth 8 (syntax-ppss)) (point)))
+ (let* ((sap (symbol-at-point))
+ (path (and sap `((,sap 0))))
+ s)
+ (while (setq s (geiser-syntax--scan-sexp))
+ (when (listp s) (push s path)))
+ path)))
+
(defun geiser-syntax--complete-partial-sexp (buffer begin end)
(geiser-syntax--with-buffer
(erase-buffer)
diff --git a/scheme/guile/geiser/doc.scm b/scheme/guile/geiser/doc.scm
index 3f060e3..d951f1c 100644
--- a/scheme/guile/geiser/doc.scm
+++ b/scheme/guile/geiser/doc.scm
@@ -37,76 +37,33 @@
#:use-module (oop goops)
#:use-module (srfi srfi-1))
-(define (autodoc form)
- (cond ((null? form) #f)
- ((symbol? form) (describe-application (list form)))
- ((not (pair? form)) #f)
- ((not (list? form)) (autodoc (pair->list form)))
- ((define-head? form) => autodoc)
- (else (autodoc/list form))))
-
-(define (autodoc/list form)
- (let ((lst (last form)))
- (cond ((and (symbol? lst) (describe-application (list lst))))
- ((and (pair? lst) (not (memq (car lst) '(quote))) (autodoc lst)))
- (else (describe-application form)))))
-
-(define (define-head? form)
- (define defforms '(define define* define-macro define-macro*
- define-method define-class define-generic))
- (and (= 2 (length form))
- (memq (car form) defforms)
- (car form)))
-
-(define (describe-application form)
- (let* ((fun (car form))
- (args (obj-args (symbol->object fun))))
+(define (autodoc ids)
+ (if (not (list? ids))
+ '()
+ (map (lambda (id) (or (autodoc* id) (list id))) ids)))
+
+(define (autodoc* id)
+ (let ((args (obj-args (symbol->object id))))
(and args
- (list (cons 'signature (signature fun args))
- (cons 'position (find-position args form))
- (cons 'module (symbol-module fun))))))
+ `(,@(signature id args)
+ (module . ,(symbol-module id))))))
(define (object-signature name obj)
(let ((args (obj-args obj)))
(and args (signature name args))))
-(define (signature fun args)
- (let ((req (arglst args 'required))
- (opt (arglst args 'optional))
- (key (arglst args 'keyword))
- (rest (assq-ref args 'rest)))
- (let ((sgn `(,fun ,@req
- ,@(if (not (null? opt)) (cons 'geiser-opt_marker opt) '())
- ,@(if (not (null? key)) (cons 'geiser-key_maker key) '()))))
- (if rest `(,@sgn geiser-rest_marker ,rest) sgn))))
-
-(define (find-position args form)
- (let* ((lf (length form))
- (lf-1 (- lf 1)))
- (if (= 1 lf) 0
- (let ((req (length (arglst args 'required)))
- (opt (length (arglst args 'optional)))
- (keys (map (lambda (k) (symbol->keyword (if (list? k) (car k) k)))
- (arglst args 'keyword)))
- (rest (assq-ref args 'rest)))
- (cond ((<= lf (+ 1 req)) lf-1)
- ((<= lf (+ 1 req opt)) (if (> opt 0) lf lf-1))
- ((or (memq (last form) keys)
- (memq (car (take-right form 2)) keys)) =>
- (lambda (sl)
- (+ 2 req
- (if (> opt 0) (+ 1 opt) 0)
- (- (length keys) (length sl)))))
- (else (+ 1 req
- (if (> opt 0) (+ 1 opt) 0)
- (if (null? keys) 0 (+ 1 (length keys)))
- (if rest 2 0))))))))
-
-(define (arglst args kind)
- (let ((args (assq-ref args kind)))
- (cond ((or (not args) (null? args)) '())
- ((list? args) args)
- (else (list args)))))
+(define (signature id args)
+ (define (arglst kind)
+ (let ((args (assq-ref args kind)))
+ (cond ((or (not args) (null? args)) '())
+ ((list? args) args)
+ (else (list args)))))
+ `(,id
+ (required ,@(arglst 'required))
+ (optional ,@(arglst 'optional)
+ ,@(let ((rest (assq-ref args 'rest)))
+ (if rest (list "...") '())))
+ (key ,@(arglst 'keyword))))
(define (obj-args obj)
(cond ((not obj) #f)
diff --git a/scheme/plt/geiser/autodoc.ss b/scheme/plt/geiser/autodoc.ss
index 6607a94..2fe3a83 100644
--- a/scheme/plt/geiser/autodoc.ss
+++ b/scheme/plt/geiser/autodoc.ss
@@ -31,39 +31,32 @@
(eval `(help ,symbol #:from ,mod)))))
(eval `(help ,symbol))))
-(define (autodoc form)
- (cond ((null? form) #f)
- ((symbol? form) (describe-application (list form)))
- ((not (pair? form)) #f)
- ((not (list? form)) (autodoc (pair->list form)))
- ((define-head? form) => autodoc)
- (else (autodoc/list form))))
-
-(define (autodoc/list form)
- (let ((lst (last form)))
- (cond ((and (symbol? lst) (describe-application (list lst))))
- ((and (pair? lst) (not (memq (car lst) '(quote))) (autodoc lst)))
- (else (describe-application form)))))
-
-(define (define-head? form)
- (define defforms '(-define
- define define-values
- define-method define-class define-generic define-struct
- define-syntax define-syntaxes -define-syntax))
- (and (= 2 (length form))
- (memq (car form) defforms)
- (car form)))
-
-(define (describe-application form)
- (let* ((fun (car form))
- (loc (symbol-location* fun))
- (name (car loc))
- (path (cdr loc))
- (sgn (and path (find-signature path name fun))))
- (and sgn
- (list (cons 'signature (format-signature fun sgn))
- (cons 'position (find-position sgn form))
- (cons 'module (module-path-name->name path))))))
+(define (autodoc ids)
+ (if (not (list? ids))
+ '()
+ (map (lambda (id) (or (autodoc* id) (list id))) ids)))
+
+(define (autodoc* id)
+ (and
+ (symbol? id)
+ (let* ((loc (symbol-location* id))
+ (name (car loc))
+ (path (cdr loc))
+ (sgn (and path (find-signature path name id))))
+ (and sgn
+ `(,id
+ (name . ,name)
+ ,@(format-signature sgn)
+ (module . ,(module-path-name->name path)))))))
+
+(define (format-signature sign)
+ (if (signature? sign)
+ `((required ,@(signature-required sign))
+ (optional ,@(signature-optional sign)
+ ,@(let ((rest (signature-rest sign)))
+ (if rest (list "...") '())))
+ (key ,@(signature-keys sign)))
+ '()))
(define signatures (make-hash))
@@ -167,44 +160,6 @@
(opt-no (- max-val min-val)))
(make-signature (args 0 min-val) (args min-val opt-no) '() #f)))))
-(define (format-signature fun sign)
- (cond ((symbol? sign) (cons fun sign))
- ((signature? sign)
- (let ((req (signature-required sign))
- (opt (signature-optional sign))
- (keys (signature-keys sign))
- (rest (signature-rest sign)))
- `(,fun
- ,@req
- ,@(if (null? opt) opt (cons 'geiser-opt_marker opt))
- ,@(if (null? keys) keys (cons 'geiser-key_maker keys))
- ,@(if rest (list 'geiser-rest_marker rest) '()))))
- (else #f)))
-
-(define (find-position sign form)
- (if (signature? sign)
- (let* ((lf (length form))
- (lf-1 (- lf 1)))
- (if (= 1 lf) 0
- (let ((req (length (signature-required sign)))
- (opt (length (signature-optional sign)))
- (keys (map (lambda (k) (symbol->keyword (if (list? k) (car k) k)))
- (signature-keys sign)))
- (rest (signature-rest sign)))
- (cond ((<= lf (+ 1 req)) lf-1)
- ((<= lf (+ 1 req opt)) (if (> opt 0) lf lf-1))
- ((or (memq (last form) keys)
- (memq (car (take-right form 2)) keys)) =>
- (lambda (sl)
- (+ 2 req
- (if (> opt 0) (+ 1 opt) 0)
- (- (length keys) (length sl)))))
- (else (+ 1 req
- (if (> opt 0) (+ 1 opt) 0)
- (if (null? keys) 0 (+ 1 (length keys)))
- (if rest 2 0)))))))
- 0))
-
(define (update-module-cache path . form)
(when (and (string? path)
(or (null? form)