git.fiddlerwoaroof.com
Browse code

Restructure to add conditional format chars

fiddlerwoaroof authored on 05/12/2016 23:44:07
Showing 3 changed files
... ...
@@ -4,7 +4,8 @@
4 4
   :description "Describe format-string-builder here"
5 5
   :author "fiddlerwoaroof"
6 6
   :license "MIT"
7
-  :depends-on (:alexandria)
7
+  :depends-on (:alexandria
8
+	       :serapeum)
8 9
   :serial t
9 10
   :components ((:file "package")
10 11
                (:file "format-string-builder")))
... ...
@@ -1,7 +1,5 @@
1 1
 (in-package #:format-string-builder)
2 2
 
3
-(defvar *format-command-stream*)
4
-
5 3
 (defclass format-string-command ()
6 4
   ((at-p :initarg :at-p :accessor at-p :initform nil)
7 5
    (colon-p :initarg :colon-p :accessor colon-p :initform nil)))
... ...
@@ -16,6 +14,9 @@
16 14
    (end-char :initarg :end-char :accessor end-char)
17 15
    (modifiers :initarg :modifiers :accessor modifiers :initform nil)))
18 16
 
17
+(defclass sectioned-format-string-command (compound-format-string-command)
18
+  ())
19
+
19 20
 (defmethod print-object ((obj compound-format-string-command) s)
20 21
   (declare (optimize (debug 3)))
21 22
   (print-unreadable-object (obj s :type t :identity t)
... ...
@@ -47,29 +48,30 @@
47 48
 
48 49
 (defmethod print-format-representation :around ((command format-string-command) s)
49 50
   (princ #\~ s)
50
-  (call-next-method))
51
-
52
-(defmethod print-format-representation :before ((command format-string-command) s)
51
+  (print-format-modifiers command s)
53 52
   (when (colon-p command)
54 53
     (princ #\: s))
55 54
   (when (at-p command)
56
-    (princ #\@ s)))
57
-
58
-(defmethod print-format-representation :before ((command simple-format-string-command) s)
59
-  (print-format-modifiers command s))
55
+    (princ #\@ s))
56
+  (call-next-method))
60 57
 
61 58
 (defmethod print-format-representation ((command simple-format-string-command) s)
62 59
   (princ (format-char command) s))
63 60
 
64 61
 (defmethod print-format-representation :before ((command compound-format-string-command) s)
65
-  (print-format-modifiers command s))
62
+  (princ (start-char command) s))
66 63
 
67 64
 (defmethod print-format-representation ((command compound-format-string-command) s)
68
-  (princ (start-char command) s)
69
-  (print-format-representation (contents command) s)
65
+  (print-format-representation (contents command) s))
66
+
67
+(defmethod print-format-representation :after ((command compound-format-string-command) s)
70 68
   (princ #\~ s)
71 69
   (princ (end-char command) s))
72 70
 
71
+(defmethod print-format-representation ((command sectioned-format-string-command) s)
72
+  (mapcar (op (princ _ s))
73
+	  (intersperse "~;" (contents command))))
74
+
73 75
 ;;; TODO: should this be a generic function?
74 76
 (defun convert-modifier (modifier)
75 77
   (flet ((validate-modifier (modifier)
... ...
@@ -134,10 +136,18 @@
134 136
                                          :at-p ,at-p
135 137
                                          :colon-p ,colon-p)))
136 138
 
139
+(defun define-sectioned-format-char (name start-char end-char &key at-p colon-p)
140
+  (setf (gethash (intern (string name) :keyword)
141
+		 *format-string-registry*)
142
+	`(sectioned-format-string-command :start-char ,start-char
143
+					  :end-char ,end-char
144
+					  :at-p ,at-p
145
+					  :colon-p ,colon-p)))
146
+
137 147
 (defmacro define-compound-format-chars (&body specs)
138 148
   `(progn
139 149
      ,@(loop for spec in specs
140
-             collect `(define-compound-format-char ,@spec))))
150
+	     collect `(define-compound-format-char ,@spec))))
141 151
 
142 152
 (defmacro define-simple-format-chars (&body specs)
143 153
   `(progn
... ...
@@ -160,20 +170,26 @@
160 170
                 (list* 'progn
161 171
                        (mapcar (lambda (spec)
162 172
                                  `(:compound ,@spec))
163
-                               specs))))
173
+                               specs)))
174
+	      (:sectioned (name (start-char end-char) &key at-p colon-p)
175
+		`(define-sectioned-format-char ,name ,start-char ,end-char
176
+					       :at-p ,at-p :colon-p ,colon-p)))
164 177
      ,@body))
165 178
 
166
-(defmacro &format (stream format-spec &rest args)
179
+(defmacro format* (stream format-spec &rest args)
167 180
   `(format ,stream
168
-           (make-format-string ',format-spec)
181
+           ,(make-format-string format-spec)
169 182
            ,@args))
170 183
 
171
-(defmacro define-message (name (&rest args) &body spec)
172
-  (with-gensyms (fs stream the-rest)
173
-    `(eval-when (:load-toplevel :compile-toplevel :execute)
174
-       (let ((,fs (make-format-string ',spec)))
175
-         (defun ,name (,stream ,@args &rest ,the-rest)
176
-           (apply #'format (list* ,stream ,fs ,@args ,the-rest)))))))
184
+(defmacro define-message (name (stream-arg &rest args) &body spec)
185
+  (flet ((get-argument-names (arg-list)
186
+           (loop for s in arg-list
187
+                 when (and (symbolp s) (not (char= (elt (symbol-name s) 0) #\&))) collect s
188
+                 when (consp s) collect (car s))))
189
+    (with-gensyms (fs the-rest)
190
+      `(let ((,fs ,(make-format-string spec)))
191
+         (defun ,name (,stream-arg ,@args &rest ,the-rest)
192
+           (apply #'format ,stream-arg ,fs ,@(get-argument-names args) ,the-rest))))))
177 193
 
178 194
 (define-format-chars
179 195
 
... ...
@@ -201,6 +217,9 @@
201 217
     (:cjust (#\< #\>) :at-p t :colon-p t)
202 218
     (:center (#\< #\>) :at-p t :colon-p t))
203 219
 
220
+  ;; Conditional output
221
+  (:sectioned :y-or-n (#\[ #\]) :colon-p t)
222
+
204 223
   ;; Case printing characters.
205 224
   (:compounds
206 225
     (:lowercase (#\( #\)))
... ...
@@ -223,12 +242,13 @@
223 242
     (:exit (#\^))
224 243
     (:go-to (#\*))
225 244
     (:end-section (#\;))
245
+    (:fresh-line (#\&))
226 246
     (:ensure-line (#\&))
227 247
     (:new-line (#\%))))
228 248
 
229
-(define-message hello (name)
249
+(define-message hello (stream name)
230 250
   (:titlecase () "hello" #\space :str))
231 251
 
232
-(define-message print-comma-separated ()
252
+(define-message print-comma-separated (stream)
233 253
   (:own-line ()
234 254
    (:rest () :str :exit ", ")))
... ...
@@ -2,6 +2,7 @@
2 2
 
3 3
 (defpackage #:format-string-builder
4 4
   (:use #:cl #:alexandria)
5
+  (:import #:serapeum #:intersperse #:op)
5 6
   (:export #:make-format-string
6 7
            #:define-message))
7 8