html-template-generate-helpers.rkt
#lang racket/base
;; For legal info, see file "info.rkt".

(require "planet-neil-html-writing.rkt")

;;------------ Error-Catching Output Port

(provide html-template-error-catching-output-port)
(define html-template-error-catching-output-port
  (make-output-port
   'html-template-error-catching-output-port ; name
   always-evt ; evt
   (lambda (s start end non-block? breakable?) ; write-out
     (error 'html-template-error-catching-output-port
            "write-out attempted"))
   (lambda () ; close
     (error 'html-template-error-catching-output-port
            "close attempted"))
   (lambda (special non-block? breakable?) ; write-out-special
     (error 'html-template-error-catching-output-port
            "write-out-special attempted"))
   ;; TODO: Catch the other operations too?
   
   ;;     (lambda (s start end)
   ;;       (wrap-evt always-evt
   ;;                 (lambda (x)
   ;;                   (- end start))))
   ;;     (lambda (special) always-evt)
   ))

;;--------------------------------------------------------- For Opcode "format"

;; TODO: !!! Do we really want to handle byte strings by passing them through
;; (format "~S")?

(provide %html-template:format/content/write)
(define (%html-template:format/content/write val out)
  ;; TODO: Make this extensible and/or pluggable.
  (cond ((string? val) (write-html val out))
        (else          (write-html (format "~S" val) out))))

(provide %html-template:format/attribute-value/write)
(define (%html-template:format/attribute-value/write val out)
  ;; TODO: Make this extensible and/or pluggable.
  (cond ((string? val) (write-html-attribute-value-part val out))
        (else          (write-html-attribute-value-part (format "~S" val) out))))

(provide %html-template:format/content/bytes)
(define (%html-template:format/content/bytes val)
  ;; TODO: Make this extensible and/or pluggable.
  (cond ((string? val) (html->bytes val))
        (else          (html->bytes (format "~S" val)))))

(provide %html-template:format/attribute-value/bytes)
(define (%html-template:format/attribute-value/bytes val)
  ;; TODO: Make this extensible and/or pluggable.
  (cond ((string? val) (html-attribute-value->bytes val))
        (else          (html-attribute-value->bytes (format "~S" val)))))

;;------------------------------------------------------- For Opcode "verbatim"

(provide %html-template:write-verbatim)
(define (%html-template:write-verbatim val out)
  (let loop ((val val))
    (cond ((null?   val) (void))
          ((pair?   val) (loop (car val)) (loop (cdr val)))
          ((bytes?  val) (write-bytes  val out))
          ((string? val) (write-string val out))
          (else '%html-template:write-verbatim
                "invalid value: ~S"
                val))))

(provide %html-template:verbatim->bytes)
(define (%html-template:verbatim->bytes val)
  (let ((reverse-lst (let loop ((val         val)
                                (reverse-lst '()))
                       (cond ((null?   val) reverse-lst)
                             ((pair?   val) (loop (cdr val) (loop (car val) reverse-lst)))
                             ((bytes?  val) (cons val reverse-lst))
                             ((string? val) (cons (string->bytes/utf-8 val) reverse-lst))
                             (else '%html-template:verbatim->bytes
                                   "invalid value: ~S"
                                   val)))))
    (if (null? reverse-lst)
        #""
        (apply bytes-append (reverse reverse-lst)))))