Function: icalendar-define-component
icalendar-define-component is a macro defined in icalendar-macs.el.gz.
Signature
(icalendar-define-component SYMBOLIC-NAME COMPONENT-NAME DOC &key ((:keyword-face KEYWORD-FACE) 'icalendar-keyword NONDEFAULT-KEYWORD-FACE) ((:name-face NAME-FACE) 'icalendar-component-name NONDEFAULT-NAME-FACE) CHILD-SPEC OTHER-VALIDATOR LINK)
Documentation
Define iCalendar component COMPONENT-NAME under SYMBOLIC-NAME.
COMPONENT-NAME should be the name of the component as it should appear in iCalendar data.
Regular expressions to match the component boundaries are defined
named COMPONENT-NAME-begin and COMPONENT-NAME-end (or
OTHER-begin and OTHER-end, where OTHER is derived from
SYMBOLIC-NAME by removing any prefix icalendar- and suffix
-component if COMPONENT-NAME is nil).
Group 1 of these regexes matches the "BEGIN" or "END"
keyword that marks a component boundary.
Group 2 matches the component name.
A function to match the component boundaries is defined called
icalendar-match-COMPONENT-NAME-component (or
icalendar-match-OTHER-component, with OTHER as above). This
function is used to provide syntax highlighting in
icalendar-mode.
The following keyword arguments are accepted:
:child-spec - a plist mapping the following keywords to lists
of type symbols:
:one - properties or components that must appear exactly once
:one-or-more - properties or components that must appear at least once and
may appear more than once
:zero-or-one - properties or components that must appear at most once
:zero-or-more - properties or components that may appear more than once
:allow-others - if non-nil, other children 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.
:keyword-face - a face symbol for highlighting the BEGIN/END keyword
(default: icalendar-keyword)
:name-face - a face symbol for highlighting the component name
(default: icalendar-component-name)
:link - a string containing a URL for documentation of this component
Source Code
;; Defined in /usr/src/emacs/lisp/calendar/icalendar-macs.el.gz
;; Define components:
(cl-defmacro ical:define-component (symbolic-name component-name doc
&key
((:keyword-face keyword-face)
'ical:keyword nondefault-keyword-face)
((:name-face name-face)
'ical:component-name nondefault-name-face)
child-spec
other-validator
link)
"Define iCalendar component COMPONENT-NAME under SYMBOLIC-NAME.
COMPONENT-NAME should be the name of the component as it should
appear in iCalendar data.
Regular expressions to match the component boundaries are defined
named `COMPONENT-NAME-begin' and `COMPONENT-NAME-end' (or
`OTHER-begin' and `OTHER-end', where `OTHER' is derived from
SYMBOLIC-NAME by removing any prefix `icalendar-' and suffix
`-component' if COMPONENT-NAME is nil).
Group 1 of these regexes matches the \"BEGIN\" or \"END\"
keyword that marks a component boundary.
Group 2 matches the component name.
A function to match the component boundaries is defined called
`icalendar-match-COMPONENT-NAME-component' (or
`icalendar-match-OTHER-component', with OTHER as above). This
function is used to provide syntax highlighting in
`icalendar-mode'.
The following keyword arguments are accepted:
:child-spec - a plist mapping the following keywords to lists
of type symbols:
:one - properties or components that must appear exactly once
:one-or-more - properties or components that must appear at least once and
may appear more than once
:zero-or-one - properties or components that must appear at most once
:zero-or-more - properties or components that may appear more than once
:allow-others - if non-nil, other children 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.
:keyword-face - a face symbol for highlighting the BEGIN/END keyword
(default: `icalendar-keyword')
:name-face - a face symbol for highlighting the component name
(default: `icalendar-component-name')
:link - a string containing a URL for documentation of this component"
(declare (doc-string 2))
(let* (;; Regexes:
(name-rx (or component-name 'ical:name))
(component-dname (if component-name
(downcase component-name)
(string-trim (symbol-name symbolic-name)
"icalendar-" "-component")))
(begin-rx-name (intern (concat "icalendar-" component-dname "-begin")))
(end-rx-name (intern (concat "icalendar-" component-dname "-end")))
;; Related functions:
(matcher-name
(intern (concat "icalendar-match-" component-dname "-component")))
(type-predicate-name
(intern (concat "icalendar-" component-dname "-component-p")))
;; Faces:
(has-faces (or nondefault-name-face nondefault-keyword-face))
;; Documentation:
(header "It names a component type defined by
`icalendar-define-component'.")
(name-doc (if (not component-name)
"\nNAME must match rx `icalendar-name'"
""))
(syntax-doc (format "Syntax:\nBEGIN:%s\n[contentline ...]\nEND:%1$s%s"
(or component-name "NAME")
name-doc))
(child-doc
(concat
"The following properties and components are required or "
"allowed\nas children in syntax nodes of this type:\n\n"
(ical:format-child-spec child-spec)
(when (plist-get child-spec :allow-others)
"\nOther properties and components 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-component t
'ical:matcher (function ,matcher-name)
'ical:begin-rx (quote ,begin-rx-name)
'ical:end-rx (quote ,end-rx-name)
'ical:child-spec (quote ,child-spec)
'ical:other-validator (function ,other-validator)
'ical:type-documentation ,full-doc
'ical:link ,link)))
;; Regexes which match:
;; Group 1: BEGIN or END, and
;; Group 2: the component name
(rx-define ,begin-rx-name
(seq line-start
(group-n 1 "BEGIN")
":"
(group-n 2 ,name-rx)
line-end))
(rx-define ,end-rx-name
(seq line-start
(group-n 1 "END")
":"
(group-n 2 ,name-rx)
line-end))
(defun ,matcher-name (limit)
,(concat (format "Matcher for %s component boundaries.\n"
(or component-name "unrecognized"))
"(Defined by `icalendar-define-component'.)")
(re-search-forward (rx (or ,begin-rx-name ,end-rx-name)) limit t))
;; CL-type to represent syntax nodes for this component:
(defun ,type-predicate-name (node)
,(format "Return non-nil if NODE represents a %s component."
(or component-name "unrecognized"))
(and (ical:ast-node-p node)
(eq (ical:ast-node-type node) (quote ,symbolic-name))))
(cl-deftype ,symbolic-name () '(satisfies ,type-predicate-name))
;; 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 ,keyword-face) t t)
(2 (quote ,name-face) t t)))
ical:font-lock-keywords))
;; Associate the print name with the type symbol for
;; `icalendar-parse-component', `icalendar-print-component' etc.:
(when ,component-name
(push (cons ,component-name (quote ,symbolic-name))
ical:component-types)))))