[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[bug#45893] [PATCH v2 2/3] guix: scripts: Add hint for option typo.
From: |
zimoun |
Subject: |
[bug#45893] [PATCH v2 2/3] guix: scripts: Add hint for option typo. |
Date: |
Sat, 16 Jan 2021 01:26:33 +0100 |
* guix/utils.scm (levenshtein-distance): New procedure.
(string-closest): New procedure.
* guix/scripts.scm (option-hint): New procedure.
(parse-command-line): Add 'option-hint'.
---
guix/scripts.scm | 21 ++++++++++++++++++++
guix/utils.scm | 51 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/guix/scripts.scm b/guix/scripts.scm
index 34cba35401..03d45c0888 100644
--- a/guix/scripts.scm
+++ b/guix/scripts.scm
@@ -4,6 +4,7 @@
;;; Copyright © 2015, 2016 Alex Kost <alezost@gmail.com>
;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
;;; Copyright © 2021 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -112,6 +113,23 @@ procedure, but both the category and synopsis are meant to
be read (parsed) by
doc
body ...)))))
+(define (option-hint guess options)
+ "Return the closest long-name from name based on Levenshtein distance."
+ (define (options->long-names options)
+ (fold (lambda (name res)
+ (match name
+ ((? char?) res)
+ ((? string?) (cons name res))))
+ '()
+ (fold append '() (map option-names options))))
+
+ (fold (lambda (name res)
+ (if (string-null? res)
+ (string-append "@code{" name "}")
+ (string-append "@code{" name "}, " res)))
+ ""
+ (string-closest guess (options->long-names options))))
+
(define (args-fold* args options unrecognized-option-proc operand-proc . seeds)
"A wrapper on top of `args-fold' that does proper user-facing error
reporting."
@@ -149,6 +167,9 @@ parameter of 'args-fold'."
;; Actual parsing takes place here.
(apply args-fold* args options
(lambda (opt name arg . rest)
+ (display-hint
+ (format #f (G_ "Do you mean ~a?~%")
+ (option-hint name options)))
(leave (G_ "~A: unrecognized option~%") name))
argument-handler
seeds))
diff --git a/guix/utils.scm b/guix/utils.scm
index f8b05e7e80..2a0fb28917 100644
--- a/guix/utils.scm
+++ b/guix/utils.scm
@@ -8,6 +8,7 @@
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2018, 2020 Marius Bakke <marius@gnu.org>
;;; Copyright © 2020 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -114,7 +115,10 @@
call-with-decompressed-port
compressed-output-port
call-with-compressed-output-port
- canonical-newline-port))
+ canonical-newline-port
+
+ levenshtein-distance
+ string-closest))
;;;
@@ -847,6 +851,51 @@ be determined."
;; raising an error would upset Geiser users
#f))))))
+
+;;;
+;;; Hint based on Levenshtein distance
+;;;
+
+(define (levenshtein-distance s1 s2)
+ "Compute the Levenshtein distance between two strings."
+ ;; Naive implemenation
+ (define loop
+ (memoize
+ (lambda (as bt)
+ (match as
+ ('() (length bt))
+ ((a s ...)
+ (match bt
+ ('() (length as))
+ ((b t ...)
+ (if (char=? a b)
+ (loop s t)
+ (1+ (min
+ (loop as t)
+ (loop s bt)
+ (loop s t)))))))))))
+
+ (let ((c1 (string->list s1))
+ (c2 (string->list s2)))
+ (loop c1 c2)))
+
+(define (string-closest trial tests)
+ "Return the list from TESTS the closest from the string TRIAL based on
+Levenshtein distance."
+ (match (fold (lambda (test res)
+ (let ((dist (levenshtein-distance trial test)))
+ (match res
+ ((val lst)
+ (if (< dist val)
+ (list dist (list test))
+ (if (= dist val)
+ (list dist (cons test lst))
+ res)))
+ (_ (list dist (list test))))))
+ '()
+ tests)
+ ((_ rest ...) (match rest ((head _ ...) head)))))
+
;;; Local Variables:
;;; eval: (put 'call-with-progress-reporter 'scheme-indent-function 1)
;;; End:
--
2.29.2
- [bug#45893] [PATCH v2 3/3] ui: Add command hint., (continued)
- [bug#45893] [PATCH v2 3/3] ui: Add command hint., zimoun, 2021/01/15
- [bug#45893] [PATCH 0/2] DRAFT: Hint for options., Ludovic Courtès, 2021/01/19
- [bug#45893] [PATCH 0/2] DRAFT: Hint for options., zimoun, 2021/01/19
- [bug#45893] [PATCH 0/2] DRAFT: Hint for options., Ludovic Courtès, 2021/01/26
- [bug#45893] [PATCH 0/2] DRAFT: Hint for options., zimoun, 2021/01/26
- [bug#45893] Hint for package name: too slow!, zimoun, 2021/01/19
- [bug#45893] Hint for package name: full matrix iteration, zimoun, 2021/01/20
- [bug#45893] [PATCH 0/2] DRAFT: Hint for options., Ludovic Courtès, 2021/01/26
- [bug#45893] [PATCH 0/2] DRAFT: Hint for options., zimoun, 2021/01/26
- [bug#45893] [PATCH 0/2] DRAFT: Hint for options., Ludovic Courtès, 2021/01/27
- [bug#45893] [PATCH v2 2/3] guix: scripts: Add hint for option typo.,
zimoun <=
- [bug#45893] [PATCH 0/2] DRAFT: Hint for options., Ludovic Courtès, 2021/01/19
- [bug#45893] [PATCH v3 1/3] utils: Add string distance., zimoun, 2021/01/19