;;;; SPDX-FileCopyrightText: Atlas Engineer LLC ;;;; SPDX-License-Identifier: BSD-3-Clause ;; `uiop:define-package' instead of `nyxt:define-package' since it does not ;; depend on Nyxt. (uiop:define-package :nyxt/types (:use :cl) (:import-from :serapeum #:export-always) (:documentation "Package for types. It's useful to have a separate package because some types may need to generate functions for the `satisfies' type condition.")) (in-package :nyxt/types) ;; types:proper-list doesn't check its element type. (defun list-of-p (list type) "Return non-nil if LIST contains only elements of the given TYPE." (and (listp list) (every (lambda (x) (typep x type)) list))) (export-always 'list-of) (deftype list-of (type) "The empty list or a proper list of TYPE elements. Unlike `(cons TYPE *)', it checks all the elements. `(cons TYPE *)' does not accept the empty list." (unless (trivial-types:type-specifier-p type) (error "Invalid type specifier: ~a" type)) (let ((predicate-name (intern (string-upcase (uiop:strcat "LIST-OF-" (remove-if (complement #'alphanumericp) (princ-to-string type)) "-P")) (find-package :nyxt/types)))) (unless (fboundp predicate-name) (setf (fdefinition predicate-name) (lambda (object) (list-of-p object type)))) `(and list (satisfies ,predicate-name)))) (export-always 'alist-of) (deftype alist-of (key-type &optional value-type) "Alist of dotted conses." `(list-of (cons ,key-type ,(or value-type key-type)))) (export-always 'cookie-policy) (deftype cookie-policy () "The type of cookie policy to apply." `(member :accept :never :no-third-party)) ;; The following types represent the positional arguments documented at ;; https://developer.mozilla.org/en-US/docs/Web/API/Selection/modify#parameters (export-always 'selection-action) (deftype selection-action () "The type of change to apply." '(member :move :extend)) (export-always 'selection-direction) (deftype selection-direction () "The direction in which to adjust the current selection." '(member :forward :backward)) (export-always 'selection-scale) (deftype selection-scale () "The distance to adjust the current selection or cursor position." '(member :character :word :sentence :line :paragraph :lineboundary :sentenceboundary :paragraphboundary :documentboundary)) (export-always 'html-string-p) (defun html-string-p (string) "Check whether the STRING is an HTML string: - Having proper starting/ending tags. - Being parseable with Plump." (serapeum:and-let* ((string string) (-p (stringp string)) (trimmed (string-trim serapeum:whitespace string)) (has-closing-tag (ppcre:scan "$" trimmed)) (html (ignore-errors (plump:parse trimmed))) (single-child (serapeum:single (plump:children html))) (child (elt (plump:children html) 0))) (plump:element-p child))) (export-always 'maybe) (deftype maybe (&rest types) "An optional/maybe type for a value that is either one of TYPES, or NIL." `(or null ,@types)) (export-always 'maybe*) (deftype maybe* (&rest types) "A lenient `maybe' with all the 'empty' sequences as null value." `(or null (array * (0)) ,@types))