library_name: cl-forms

system_name: cl-forms

macro_name: with-gensyms

macro_definition:
(defmacro with-gensyms ((&rest names) &body body)
  `(let ,(mapcar #'(lambda (name)
                     (list name `(make-symbol ,(symbol-name name)))) names)
    ,@body))

form_type: defmacro

args: ((&rest names) &body body)

status: extracted


macro_name: with-scanning-functions

macro_definition:
(defmacro with-scanning-functions (string-param position-place mode-place mode-wait-place &body body)
  (with-gensyms (num items position not-preceded-by string item new-mode until advancing)
    `(labels ((advance (,num)
               (setf ,position-place (+ ,position-place ,num))
               t)
              (peek-any (,items &key ,not-preceded-by)
               (incf *scan-calls*)
               (let* ((,items (if (stringp ,items)
                                  (coerce ,items 'list) ,items))
                      (,not-preceded-by (if (characterp ,not-preceded-by)
                                            (string ,not-preceded-by) ,not-preceded-by))
                      (,position ,position-place)
                      (,string ,string-param))
                 (let ((,item (and
                               (< ,position (length ,string))
                               (find ,string ,items
                                     :test #'(lambda (,string ,item)
                                               #+nil
                                               (format t "looking for ~S in ~S starting at ~S~%"
                                                       ,item ,string ,position)
                                               (if (characterp ,item)
                                                   (char= (elt ,string ,position)
                                                          ,item)
                                                   (search ,item ,string :start2 ,position
                                                           :end2 (min (length ,string)
                                                                      (+ ,position (length ,item))))))))))
                   (if (characterp ,item)
                       (setf ,item (string ,item)))
                   (if
                    (if ,item
                        (if ,not-preceded-by
                            (if (>= (- ,position (length ,not-preceded-by)) 0)
                                (not (string= (subseq ,string
                                                      (- ,position (length ,not-preceded-by))
                                                      ,position)
                                              ,not-preceded-by))
                                t)
                            t)
                        nil)
          ,item
                    (progn
                      (and *reset-position*
                           (setf ,position-place *reset-position*))
                      nil)))))
         (scan-any (,items &key ,not-preceded-by)
      (let ((,item (peek-any ,items :not-preceded-by ,not-preceded-by)))
        (and ,item (advance (length ,item)))))
         (peek (,item &key ,not-preceded-by)
      (peek-any (list ,item) :not-preceded-by ,not-preceded-by))
              (scan (,item &key ,not-preceded-by)
               (scan-any (list ,item) :not-preceded-by ,not-preceded-by)))
      (macrolet ((set-mode (,new-mode &key ,until (,advancing t))
                   (list 'progn
                         (list 'setf ',mode-place ,new-mode)
                         (list 'setf ',mode-wait-place
                               (list 'lambda (list ',position)
                                     (list 'let (list (list '*reset-position* ',position))
                                           (list 'values ,until ,advancing)))))))
        ,@body))))


macro_name: define-coloring-type

macro_definition:
(defmacro define-coloring-type (name fancy-name &key modes default-mode transitions formatters
                                autodetect parent formatter-variables (formatter-after-hook '(constantly ""))
                                invisible)
  (with-gensyms (parent-type term type string current-mode position position-foobage mode-wait new-position advance)
    `(let ((,parent-type (or (find-coloring-type ,parent)
                             (and ,parent
                                  (error "No such coloring type: ~S" ,parent)))))
      (setf (find-coloring-type ,name)
       (make-instance 'coloring-type
        :fancy-name ',fancy-name
        :modes (append ',modes (if ,parent-type (coloring-type-modes ,parent-type)))
        :default-mode (or ',default-mode
                          (if ,parent-type (coloring-type-default-mode ,parent-type)))
        ,@(if autodetect
              `(:autodetect-function ,autodetect))
        :parent-type ,parent-type
        :visible (not ,invisible)
        :formatter-initial-values (lambda nil
                                    (list* ,@(mapcar #'(lambda (e)
                                                         `(cons ',(car e) ,(second e)))
                                                     formatter-variables)
                                           (if ,parent-type
                                               (funcall (coloring-type-formatter-initial-values ,parent-type))
                                               nil)))
        :formatter-after-hook (lambda nil
                                (symbol-macrolet ,(mapcar #'(lambda (e)
                                                              `(,(car e) (cdr (assoc ',(car e) *formatter-local-variables*))))
                                                          formatter-variables)
                                    (concatenate 'string
                                                 (funcall ,formatter-after-hook)
                                                 (if ,parent-type
                                                     (funcall (coloring-type-formatter-after-hook ,parent-type))
                                                     ""))))
        :term-formatter
        (symbol-macrolet ,(mapcar #'(lambda (e)
                                      `(,(car e) (cdr (assoc ',(car e) *formatter-local-variables*))))
                                  formatter-variables)
            (lambda (,term)
              (labels ((call-parent-formatter (&optional (,type (car ,term))
                                                         (,string (cdr ,term)))
                         (if ,parent-type
                             (funcall (coloring-type-term-formatter ,parent-type)
                                      (cons ,type ,string))))
                       (call-formatter (&optional (,type (car ,term))
                                                  (,string (cdr ,term)))
                         (funcall
                          (case (first ,type)
                            ,@formatters
                            (t (lambda (,type text)
                                 (call-parent-formatter ,type text))))
                          ,type ,string)))
                (call-formatter))))
        :transition-functions
        (list
         ,@(loop for transition in transitions
                 collect (destructuring-bind (mode &rest table) transition
                           `(cons ',mode
                             (lambda (,current-mode ,string ,position)
                               (let ((,mode-wait (constantly nil))
                                     (,position-foobage ,position))
                                 (with-scanning-functions ,string ,position-foobage
                                                          ,current-mode ,mode-wait
                                                          (let ((*reset-position* ,position))
                                                            (cond ,@table))
                                                          (values ,position-foobage ,current-mode
                                                                  (lambda (,new-position)
                                                                    (setf ,position-foobage ,new-position)
                                                                    (let ((,advance (nth-value 1 (funcall ,mode-wait ,position-foobage))))
                                                                      (values ,position-foobage ,advance)))))
                                 )))))))))))


macro_name: with-each-stream-line

macro_definition:
(defmacro with-each-stream-line ((var stream) &body body)
  (let ((eof (gensym))
    (eof-value (gensym))
    (strm (gensym)))
    `(let ((,strm ,stream)
       (,eof ',eof-value))
      (do ((,var (read-line ,strm nil ,eof) (read-line ,strm nil ,eof)))
      ((eql ,var ,eof))
    ,@body))))

args: ((var stream) &body body)


macro_name: string-append

macro_definition:
(defmacro string-append (outputstr &rest args)
  `(setq ,outputstr (concatenate 'string ,outputstr ,@args)))

args: (outputstr &rest args)


macro_name: with-form-renderer

macro_definition:
(defmacro with-form-renderer (renderer &body body)
  "Bind *FORM-RENDERER* to RENDERER and evaluate BODY in that context."
  `(call-with-form-renderer ,renderer (lambda () ,@body)))

args: (renderer &body body)


macro_name: with-form-theme

macro_definition:
(defmacro with-form-theme (form-theme &body body)
  "Bind *FORM-THEME* to FORM-THEME and evaluate BODY in that context."
  `(call-with-form-theme ,form-theme (lambda () ,@body)))

args: (form-theme &body body)


macro_name: with-form

macro_definition:
(defmacro with-form (form &body body)
  "Bind *FORM* to FORM and evaluate BODY in that context."
  `(call-with-form ,form (lambda () ,@body)))

args: (form &body body)


macro_name: defform

macro_definition:
(defmacro defform (form-name args fields)
  "Define a form at top-level.

ARGS are the arguments passed to FORM class via MAKE-INSTANCE.
FIELDS are the form field specs.

@lisp
(forms:defform client-validated-form (:action \"/client-validation-post\"
                                              :client-validation t)
  ((name :string :value \"\" :constraints (list (clavier:is-a-string)
                                              (clavier:not-blank)
                                              (clavier:len :max 5))
         :validation-triggers '(:focusin))
   (single :boolean :value t)
   (sex :choice :choices (list \"Male\" \"Female\") :value \"Male\")
   (age :integer :constraints (list (clavier:is-an-integer)
                                    (clavier:greater-than -1)
                                    (clavier:less-than 200)))
   (email :email)
   (submit :submit :label \"Create\")))
@end lisp"
  (check-duplicate-fields fields)
  (alexandria:with-gensyms (fargs)
    `(setf (get ',form-name :form)
           (lambda (&rest ,fargs)
             (apply #'make-instance
                    'form
                    :name ',form-name
                    :fields (list ,@(loop for field in fields
                                          collect
                                          (destructuring-bind (field-name field-type &rest field-args) field
                                            `(cons ',field-name (make-form-field ,field-type :name ',(intern (string field-name)) ,@field-args)))))
                    (append ,fargs
                            (list ,@args)))))))

args: (form-name args fields)


macro_name: defform-builder

macro_definition:
(defmacro defform-builder (form-name args &body body)
  "Registers a function with arguments ARGS and body BODY as a form builder.

BODY is expected to instantiate a FORM object using ARGS in some way.

FORM-NAME is the symbol under which the FORM is registered.

Use FIND-FORM with FORM-NAME and expected arguments to obtain the registered form."
  (alexandria:with-unique-names (form)
    `(setf (get ',form-name :form)
           (lambda ,args
             (let ((,form (progn ,@body)))
               (check-type ,form forms:form)
               (setf (form-name ,form) ',form-name)
               ,form)))))

args: (form-name args &body body)


macro_name: with-form-fields

macro_definition:
(defmacro with-form-fields (fields form &body body)
  "Bind FIELDS to the form fields in FORM.

Example:

@lisp
(with-form-fields (name) form
   (print (field-value name)))
@end lisp

Also see: WITH-FORM-FIELD-VALUES "
  `(let ,(loop for field in fields
               collect `(,field (get-field ,form ',field)))
     ,@body))

args: (fields form &body body)


macro_name: with-form-field-values

macro_definition:
(defmacro with-form-field-values (fields form &body body)
  "Bind the value of FIELDS in FORM.

Example:

@lisp
(with-form-field-values (name) form
   (print name))
@end lisp"
  `(let ,(loop for field in fields
               collect `(,field (field-value (get-field ,form ',field))))
     ,@body))


macro_name: with-form-template

macro_definition:
(defmacro with-form-template ((&optional form-var) form-name args &body body)
  "Define a FORM named FORM-NAME and render it at the same time."
  (multiple-value-bind (new-body fields) (collect-replace-fields body)
    (let ((form-bind (or form-var (gensym "FORM"))))
      `(progn
         (defform ,form-name ,args
           ,fields)
         (let ((,form-bind (or ,form-var (find-form ',form-name))))
           (with-form ,form-bind
             (render-form-start)
             ,@new-body
             (render-form-end)))))))


macro_name: with-form-html-output

macro_definition:
(defmacro with-form-html-output (&body body)
  `(who:with-html-output (*html* (or *html*
				     (error "FORMS.WHO:*HTML* is unbound. Please bind it before rendering forms. See FORMS.WHO:*HTML* documentation.")))
     ,@body))

args: (&body body)