Function: icalendar-define-property

icalendar-define-property is a macro defined in icalendar-macs.el.gz.

Signature

(icalendar-define-property SYMBOLIC-NAME PROPERTY-NAME DOC VALUE &key DEFAULT (UNRECOGNIZED default) (DEFAULT-TYPE (if (icalendar-value-type-symbol-p value) value 'icalendar-text)) OTHER-TYPES LIST-SEP CHILD-SPEC OTHER-VALIDATOR ((:name-face NAME-FACE) 'icalendar-property-name NONDEFAULT-NAME-FACE) ((:value-face VALUE-FACE) 'icalendar-property-value NONDEFAULT-VALUE-FACE) ((:warn-face WARN-FACE) 'icalendar-warning NONDEFAULT-WARN-FACE) EXTRA-FACES LINK)

Documentation

Define iCalendar property PROPERTY-NAME under SYMBOLIC-NAME.

PROPERTY-NAME should be the property name as it should appear in iCalendar data.

VALUE should either be a symbol for a value type defined with icalendar-define-type, or an rx regular expression. If it is a type symbol, the regex, reader and printer functions associated with that type will be used when parsing and serializing the property's value. If it is a regular expression, it is assumed that the values are strings of type icalendar-text which match that regular expression.

An rx regular expression named SYMBOLIC-NAME is defined to match the property:
  Group 1 of this regex matches PROPERTY-NAME.
  Group 2 matches VALUE.
  Group 3, if matched, contains any property value which does
   *not* match VALUE, and is incorrect according to the standard.
  Group 4, if matched, contains the (unparsed) property parameters;
   its boundaries can be used for parsing these.

This regex matches the entire string representing this property, from the beginning of the content line to the end of its value. Another regular expression named SYMBOLIC-NAME-value is also defined to match just the value part, after the separating colon, with groups 2 and 3 as above.

A function to match the complete property expression called icalendar-match-PROPERTY-NAME-property is defined. This function is used to provide syntax highlighting in icalendar-mode.

See the functions icalendar-read-property-value, icalendar-parse-property-value, icalendar-parse-property, and icalendar-print-property-node to convert properties defined with this macro to and from their text representation in iCalendar format.

The following keyword arguments are accepted:

:default - a (string representing the) default value, if
  the property is not specified in a given component.

:unrecognized - a (string representing the) value which must be
  substituted for values that are not recognized but
  syntactically correct according to RFC5545. Unrecognized values
  must be in match group 5 of the regex determined by VALUE. An
  unrecognized value will be preserved in the syntax tree
  metadata and printed instead of this value when the node is
  printed. Defaults to any value specified for :default.

:default-type - a type symbol naming the default type of the
  property's value. If the property's value differs from this
  type, an icalendar-valuetypeparam parameter will be added to
  the property's syntax node and printed when the node is
  printed. Default is VALUE if VALUE is a value type symbol,
  otherwise the type icalendar-text.

:other-types - a list of type symbols naming value types other
  than :default-type. These represent alternative types for the
  property's value. If parsing the property's value under its
  default type fails, these types will be tried in turn, and only
  if the property's value matches none of them will an error be
  signaled.

:list-sep - if the property accepts a list of values, this should
  be a string which separates the values (typically ","). If
  :list-sep is non-nil, the value string will first be split on
  the separator, then each value will be read according to VALUE
  and collected into a list when parsing. When printing, the
  inverse happens: values are printed individually and then
  joined with :list-sep. Passing this argument marks
  SYMBOLIC-NAME as a type that accepts a list of values for
  icalendar-expects-list-of-values-p.

:child-spec - a plist mapping the following keywords to lists
of type symbols:
  :one - parameters that must appear exactly once
  :one-or-more - parameters that must appear at least once and
                   may appear more than once
  :zero-or-one - parameters that must appear at most once
  :zero-or-more - parameters that may appear more than once
  :allow-others - if non-nil, other parameters besides those listed in
                   the above are allowed to appear. (In this case, a
                   :zero-or-more clause is redundant.)

:other-validator - a function to perform any additional validation of
  the component, beyond what icalendar-ast-node-valid-p checks.
  This function should accept one argument, a syntax node. It
  should return non-nil if the node is valid, or signal an
  icalendar-validation-error if it is not. Its name does not
  need to be quoted.

:name-face - a face symbol for highlighting the property name
  (default: icalendar-property-name)

:value-face - a face symbol for highlighting valid property values
  (default: icalendar-property-value)

:warn-face - a face symbol for highlighting invalid property values
  (default: icalendar-warning)

:extra-faces - a list of the form for HIGHLIGHT in font-lock-keywords.
  In particular, ((GROUPNUM FACENAME [OVERRIDE [LAXMATCH]])...)
  can be used to apply different faces to different match subgroups.

:link - a string containing a URL for documentation of this property

Source Code

;; Defined in /usr/src/emacs/lisp/calendar/icalendar-macs.el.gz
;; Define properties:
(cl-defmacro ical:define-property (symbolic-name property-name doc value
                                   &key default
                                        (unrecognized default)
                                        (default-type
                                         (if (ical:value-type-symbol-p value)
                                             value
                                           'ical:text))
                                        other-types
                                        list-sep
                                        child-spec
                                        other-validator
                                        ((:name-face name-face)
                                         'ical:property-name nondefault-name-face)
                                        ((:value-face value-face)
                                         'ical:property-value nondefault-value-face)
                                        ((:warn-face warn-face)
                                         'ical:warning nondefault-warn-face)
                                        extra-faces
                                        link)
  "Define iCalendar property PROPERTY-NAME under SYMBOLIC-NAME.
PROPERTY-NAME should be the property name as it should appear in
iCalendar data.

VALUE should either be a symbol for a value type defined with
`icalendar-define-type', or an `rx' regular expression.  If it is
a type symbol, the regex, reader and printer functions associated
with that type will be used when parsing and serializing the
property's value.  If it is a regular expression, it is assumed
that the values are strings of type `icalendar-text' which match
that regular expression.

An `rx' regular expression named SYMBOLIC-NAME is defined to
match the property:
  Group 1 of this regex matches PROPERTY-NAME.
  Group 2 matches VALUE.
  Group 3, if matched, contains any property value which does
   *not* match VALUE, and is incorrect according to the standard.
  Group 4, if matched, contains the (unparsed) property parameters;
   its boundaries can be used for parsing these.

This regex matches the entire string representing this property,
from the beginning of the content line to the end of its value.
Another regular expression named `SYMBOLIC-NAME-value' is also
defined to match just the value part, after the separating colon,
with groups 2 and 3 as above.

A function to match the complete property expression called
`icalendar-match-PROPERTY-NAME-property' is defined.  This
function is used to provide syntax highlighting in
`icalendar-mode'.

See the functions `icalendar-read-property-value',
`icalendar-parse-property-value', `icalendar-parse-property', and
`icalendar-print-property-node' to convert properties defined
with this macro to and from their text representation in
iCalendar format.

The following keyword arguments are accepted:

:default - a (string representing the) default value, if
  the property is not specified in a given component.

:unrecognized - a (string representing the) value which must be
  substituted for values that are not recognized but
  syntactically correct according to RFC5545.  Unrecognized values
  must be in match group 5 of the regex determined by VALUE.  An
  unrecognized value will be preserved in the syntax tree
  metadata and printed instead of this value when the node is
  printed.  Defaults to any value specified for :default.

:default-type - a type symbol naming the default type of the
  property's value.  If the property's value differs from this
  type, an `icalendar-valuetypeparam' parameter will be added to
  the property's syntax node and printed when the node is
  printed.  Default is VALUE if VALUE is a value type symbol,
  otherwise the type `icalendar-text'.

:other-types - a list of type symbols naming value types other
  than :default-type.  These represent alternative types for the
  property's value.  If parsing the property's value under its
  default type fails, these types will be tried in turn, and only
  if the property's value matches none of them will an error be
  signaled.

:list-sep - if the property accepts a list of values, this should
  be a string which separates the values (typically \",\").  If
  :list-sep is non-nil, the value string will first be split on
  the separator, then each value will be read according to VALUE
  and collected into a list when parsing.  When printing, the
  inverse happens: values are printed individually and then
  joined with :list-sep.  Passing this argument marks
  SYMBOLIC-NAME as a type that accepts a list of values for
  `icalendar-expects-list-of-values-p'.

:child-spec - a plist mapping the following keywords to lists
of type symbols:
  :one           - parameters that must appear exactly once
  :one-or-more   - parameters that must appear at least once and
                   may appear more than once
  :zero-or-one   - parameters that must appear at most once
  :zero-or-more  - parameters that may appear more than once
  :allow-others  - if non-nil, other parameters besides those listed in
                   the above are allowed to appear.  (In this case, a
                   :zero-or-more clause is redundant.)

:other-validator - a function to perform any additional validation of
  the component, beyond what `icalendar-ast-node-valid-p' checks.
  This function should accept one argument, a syntax node.  It
  should return non-nil if the node is valid, or signal an
  `icalendar-validation-error' if it is not.  Its name does not
  need to be quoted.

:name-face - a face symbol for highlighting the property name
  (default: `icalendar-property-name')

:value-face - a face symbol for highlighting valid property values
  (default: `icalendar-property-value')

:warn-face - a face symbol for highlighting invalid property values
  (default: `icalendar-warning')

:extra-faces - a list of the form for HIGHLIGHT in `font-lock-keywords'.
  In particular, ((GROUPNUM FACENAME [OVERRIDE [LAXMATCH]])...)
  can be used to apply different faces to different match subgroups.

:link - a string containing a URL for documentation of this property"
  (declare (doc-string 2))
  (let* (;; Value RX:
        (full-value-rx-name
         (intern (concat (symbol-name symbolic-name) "-property-value")))
        (values-rx (when list-sep
                    `(seq ,value (zero-or-more ,list-sep ,value))))
        ;; Related functions:
        (property-dname (if property-name
                            (downcase property-name)
                          (string-trim (symbol-name symbolic-name)
                                       "icalendar-" "-property")))
        (matcher-name
         (intern (concat "icalendar-match-" property-dname "-property")))
        (type-predicate-name
         (intern (concat "icalendar-" property-dname "-property-p")))
        ;; Faces:
        (has-faces (or nondefault-name-face nondefault-value-face
                       nondefault-warn-face extra-faces))
        ;; Documentation:
        (header "It names a property type defined by `icalendar-define-property'.")
        (val-list (if list-sep (concat "VAL1" list-sep "VAL2" list-sep "...")
                    "VAL"))
        (default-doc (if default (format "The default value is: \"%s\"\n" default)
                       ""))
        (s (if list-sep "s" "")) ; to make plurals
        (val-doc (concat "VAL" s " "
                         "must be " (unless list-sep "a ")
                         (format "value%s of one of the following types:\n" s)
                         (string-join
                          (cons
                           (format "`%s' (default)" default-type)
                           (mapcar (lambda (type) (format "`%s'" type))
                                   other-types))
                          "\n")
                         default-doc))
        (name-doc (if property-name "" "NAME must match rx `icalendar-name'"))
        (syntax-doc (format "Syntax: %s[;PARAM...]:%s\n%s\n%s\n"
                            (or property-name "NAME") val-list name-doc val-doc))
        (child-doc
         (concat
          "The following parameters are required or allowed\n"
          "as children in syntax nodes of this type:\n\n"
          (ical:format-child-spec child-spec)
          (when (plist-get child-spec :allow-others)
            "\nOther parameters of any type are also allowed.\n")))
        (full-doc (concat header "\n\n" doc "\n\n" syntax-doc "\n\n" child-doc)))

    `(progn
       ;; Type metadata needs to be available at both compile time and
       ;; run time.  In particular, `ical:value-type-symbol-p' needs to
       ;; work at compile time.
       (eval-and-compile
         (setplist (quote ,symbolic-name)
                   (list
                    'ical:is-type t
                    'ical:is-property t
                    'ical:matcher (function ,matcher-name)
                    'ical:default-value ,default
                    'ical:default-type (quote ,default-type)
                    'ical:other-types (quote ,other-types)
                    'ical:list-sep ,list-sep
                    'ical:substitute-value ,unrecognized
                    'ical:value-type
                    (when (ical:value-type-symbol-p (quote ,value))
                      (quote ,value))
                    'ical:value-rx (quote ,value)
                    'ical:values-rx (quote ,values-rx)
                    'ical:full-value-rx (quote ,full-value-rx-name)
                    'ical:child-spec (quote ,child-spec)
                    'ical:other-validator (function ,other-validator)
                    'ical:type-documentation ,full-doc
                    'ical:link ,link)))

       ;; Value regex which matches:
       ;; Group 2: correct values of the property, and
       ;; Group 3: incorrect values up to end-of-line (for syntax warnings)
       (rx-define ,full-value-rx-name
         (or (group-n 2 ,(or values-rx value))
             (group-n 3 (zero-or-more not-newline))))

       ;; Full property regex which matches:
       ;; Group 1: the property name,
       ;; Group 2: correct values of the property, and
       ;; Group 3: incorrect values up to end-of-line (for syntax warnings)
       (rx-define ,symbolic-name
         (seq line-start
              (group-n 1 ,(or property-name 'ical:name))
              (group-n 4 (zero-or-more ical:other-param-safe))
              ":"
              ,full-value-rx-name
              line-end))

       ;; Matcher:
       (defun ,matcher-name (limit)
         ,(concat (format "Matcher for `%s' property.\n" symbolic-name)
                  "(Defined by icalendar-define-property.)")
         (re-search-forward (rx ,symbolic-name) limit t))

       ;; CL-type to represent syntax nodes for this property:
       (defun ,type-predicate-name (node)
         ,(format "Return non-nil if NODE represents a %s property." property-name)
         (and (ical:ast-node-p node)
              (eq (ical:ast-node-type node) (quote ,symbolic-name))))

       (cl-deftype ,symbolic-name () '(satisfies ,type-predicate-name))

       ;; Associate the print name with the type symbol for
       ;; `icalendar-parse-property', `icalendar-print-property-node', etc.:
       (when ,property-name
         (push (cons ,property-name (quote ,symbolic-name)) ical:property-types))

       ;; Generate an entry for font-lock-keywords in icalendar-mode:
       (when ,has-faces
         ;; Avoid circular load of icalendar-mode.el in
         ;; icalendar-parser.el (which does not use the *-face
         ;; keywords), while still allowing external code to add to
         ;; font-lock-keywords dynamically:
         (require 'icalendar-mode)
         (push (quote (,matcher-name
                       (1 (quote ,name-face) t t)
                       (2 (quote ,value-face) t t)
                       (3 (quote ,warn-face) t t)
                       ,@extra-faces))
               ical:font-lock-keywords)))))