changelog shortlog graph tags branches changeset files revisions annotate raw help

Mercurial > core / lisp/lib/cli/clap/opt.lisp

changeset 479: ff3b057402d1
parent: 3e721a3349a0
child: 298ca41f7f5a
author: Richard Westhaver <ellis@rwest.io>
date: Tue, 25 Jun 2024 22:28:30 -0400
permissions: -rw-r--r--
description: light cleanup
1 ;;; cli/clap/opt.lisp --- Clap Opts
2 
3 ;; CLI Opt Objects
4 
5 ;;; Code:
6 (in-package :cli/clap/obj)
7 
8 ;;; Parsers
9 ;; TODO 2024-03-16: this should map directly to Lisp types (fixnum, boolean, etc)
10 (make-opt-parser string $val)
11 
12 (make-opt-parser boolean (when $val t))
13 
14 (make-opt-parser (form string) (read-from-string $val))
15 
16 (make-opt-parser (list form) (when (listp $val) $val))
17 
18 (make-opt-parser (symbol form) (when (symbolp $val) $val))
19 
20 (make-opt-parser (keyword form) (when (keywordp $val) $val))
21 
22 (make-opt-parser number (when $val (parse-number $val)))
23 
24 (make-opt-parser integer (when $val (parse-integer $val)))
25 
26 (make-opt-parser (file string)
27  (parse-native-namestring $val nil *default-pathname-defaults* :as-directory nil))
28 
29 (make-opt-parser (directory string)
30  (sb-ext:parse-native-namestring $val nil *default-pathname-defaults* :as-directory t))
31 
32 (make-opt-parser (pathname string)
33  (pathname $val))
34 
35 (declaim ((vector symbol) *cli-opt-kinds*))
36 (defvar *cli-opt-kinds* ;; make sure to keep this in sync with the list of parsers above
37  (let ((kinds '(boolean string form list symbol keyword number file directory pathname)))
38  (make-array (length kinds) :element-type 'symbol :initial-contents kinds)))
39 
40 ;;; Objects
41 (defstruct cli-opt
42  ;; note that cli-opts can have a nil or unbound name slot
43  (name "" :type string)
44  (kind 'boolean :type symbol)
45  (thunk nil :type (or null function symbol))
46  (val nil)
47  (global nil :type boolean)
48  (description nil :type (or null string))
49  (lock nil :type boolean))
50 
51 (defun %compose-short-opt (o arg)
52  (declare (ignorable arg))
53  (setf (cli-opt-val o) t)
54  (make-cli-node 'opt o))
55 
56 (defun %compose-long-opt (o args)
57  (declare (ignorable args))
58  (setf (cli-opt-val o) (or (pop args) t))
59  (make-cli-node 'opt o))
60 
61 (defmethod handle-unknown-argument ((self cli-opt) arg))
62 (defmethod handle-missing-argument ((self cli-opt) arg))
63 (defmethod handle-invalid-argument ((self cli-opt) arg))
64 
65 (defmethod initialize-instance :after ((self cli-opt) &key)
66  (with-slots (name thunk) self
67  (unless (stringp name) (setf name (format nil "~(~A~)" name)))
68  (when (symbolp thunk) (setf thunk (funcall (compile nil `(lambda () ,(symbol-function thunk))))))
69  self))
70 
71 (defmethod install-thunk ((self cli-opt) (lambda function) &optional compile)
72  "Install THUNK into the corresponding slot in cli-cmd SELF."
73  (let ((%thunk (if compile (compile nil lambda) lambda)))
74  (setf (cli-thunk self) %thunk)
75  self))
76 
77 (defmethod print-object ((self cli-opt) stream)
78  (print-unreadable-object (self stream :type t)
79  (format stream "~A :global ~A :val ~A"
80  (cli-opt-name self)
81  (cli-opt-global self)
82  (cli-opt-val self))))
83 
84 (defmethod print-usage ((self cli-opt) &optional stream)
85  (format stream "-~(~{~A~^/--~}~)~A~A"
86  (let ((n (cli-opt-name self)))
87  (declare (simple-string n))
88  (list (make-shorty n) n))
89  (if (cli-opt-global self) "* " " ")
90  (if-let ((d (and (slot-boundp self 'description) (cli-opt-description self))))
91  (format stream ": ~A" d)
92  "")))
93 
94 (defmethod cli-equal ((a cli-opt) (b cli-opt))
95  (with-slots (name global kind) a
96  (with-slots ((bn name) (bg global) (bk kind)) b
97  (and (equal name bn)
98  (eq global bg)
99  (equal kind bk)))))
100 
101 (defmethod call-opt ((self cli-opt) arg)
102  (when-let ((thunk (cli-opt-thunk self)))
103  (setf (cli-opt-val self) (funcall thunk arg))))
104 
105 (defmethod do-opt ((self cli-opt))
106  (call-opt self (cli-opt-val self)))
107 
108 (defun active-global-opt-p (opt)
109  "Return non-nil if OPT is active at runtime and global."
110  (and (cli-opt-lock opt) (cli-opt-global opt)))