aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2017-11-09 23:29:39 +0100
committerLudovic Courtès <ludo@gnu.org>2017-11-09 23:54:47 +0100
commita2985bb101faac9f085176e0329488b91b81dfb5 (patch)
treeb2c27f187aabe74c3cf619bcb8b2dc3c16e2c098
parent935542fbde17f0bc865cbcbb8d9f632bd592cc96 (diff)
downloadguix-a2985bb101faac9f085176e0329488b91b81dfb5.tar.gz
guix-a2985bb101faac9f085176e0329488b91b81dfb5.zip
ui: Provide hints for unbound-variable errors.
* guix/ui.scm (known-variable-definition): New procedure. (report-load-error): Handle 'unbound-variable'.
-rw-r--r--guix/ui.scm42
1 files changed, 42 insertions, 0 deletions
diff --git a/guix/ui.scm b/guix/ui.scm
index 02f3638f3a..9f790b6451 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -229,6 +229,38 @@ messages."
(else
#t))))))
+(define (known-variable-definition variable)
+ "Search among the currently loaded modules one that defines a variable named
+VARIABLE and return it, or #f if none was found."
+ (define (module<? m1 m2)
+ (match (module-name m2)
+ (('gnu _ ...) #t)
+ (('guix _ ...)
+ (match (module-name m1)
+ (('gnu _ ...) #f)
+ (_ #t)))
+ (_ #f)))
+
+ (let loop ((modules (list (resolve-module '() #f #f #:ensure #f)))
+ (suggestions '()))
+ (match modules
+ (()
+ ;; Pick the "best" suggestion.
+ (match (sort suggestions module<?)
+ (() #f)
+ ((first _ ...) first)))
+ ((head tail ...)
+ (let ((next (append tail
+ (hash-map->list (lambda (name module)
+ module)
+ (module-submodules head)))))
+ (match (module-local-variable head variable)
+ (#f (loop next suggestions))
+ (_
+ (match (module-name head)
+ (('gnu _ ...) head) ;must be that one
+ (_ (loop next (cons head suggestions)))))))))))
+
(define* (display-hint message #:optional (port (current-error-port)))
"Display MESSAGE, a l10n message possibly containing Texinfo markup, to
PORT."
@@ -256,6 +288,16 @@ ARGS is the list of arguments received by the 'throw' handler."
(let ((loc (source-properties->location properties)))
(format (current-error-port) (G_ "~a: error: ~a~%")
(location->string loc) message)))
+ (('unbound-variable proc message (variable) _ ...)
+ (match args
+ ((key . args)
+ (print-exception (current-error-port) frame key args)))
+ (match (known-variable-definition variable)
+ (#f
+ (display-hint (G_ "Did you forget a @code{use-modules} form?")))
+ (module
+ (display-hint (format #f (G_ "Try adding @code{(use-modules ~a)}.")
+ (module-name module))))))
(('srfi-34 obj)
(if (message-condition? obj)
(if (error-location? obj)