{{{ #!html
This document describes a proposal for comment and review. It is not actually implemented anywhere. }}} == Overview == Characters in Hemlock buffers can have properties. A character property is defined by a property name and value, each of which can be an arbitrary object. Character property names are compared using `EQL`. Property values are compared using a special function `CHARPROP-EQUAL`. The absence of a property is indicated by property value of `NIL`. Property names that are keywords are reserved for use by Hemlock as predefined property names. Other objects (most notably non-keyword symbols) are available for use as user-defined properties. In addition to properties associated with Hemlock buffers, it is possible to associate properties with Hemlock views. View properties are maintained separately from buffer properties, and can be changed independently. When looking up character properties through a view, the view value of a property overrides the buffer value. A character can have any number of properties. A set of properties can be represented by a plist, i.e. an alternating list of property name and value. As with plists, when the same property name appears multiple times, the first (leftmost) value is used. Some functions are defined to return a value representing a set of properties. Unless explicitly stated, user code should not assume any particular representation of this value -- it might be a plist, it might be a hash table, or it might be some other internal representation. Some functions are defined to take an argument representing a set of properties. All such functions accept any of: a plist, a hash table, or any value returned by a function that returns a set of properties. All non-keyword symbols mentioned here are exported from the `HEMLOCK-INTERFACE` package and hence are accessible from both the `HEMLOCK` and `HEMLOCK-INTERNALS` packages. == Display Properties == Hemlock's display code looks at certain predefined properties to determine how the text in a buffer will be displayed, for example which font will be used or what the background color will be. The properties so used are called ''display properties''. The display looks at both view and buffer properties, but the only view properties it considers are those affecting color and underlines. Hemlock recognizes the following display properties: `:font-name`:: a string which names the font family or the specifc font, or one of `:document-font`, `:fixed-font`, `:system-font`. `:font-size`:: a real number, the size of the font `:font-weight`:: one of `:plain` or `:bold` `:font-width`:: one of `:condensed` or `:expanded` `:font-slant`:: one of `:italic` or `:roman` `:font-underline`:: one of `:single`, `:double`, or `:thick` `:font-color`:: a string or integer value as in HTML, e.g. `"Blue"` or `#x0000FF` `:background-color`:: same as above == Functions == === Setting and accessing === `(NEXT-CHARPROP-VALUE mark name &key view)` Returns the value of property `name` in the character after `mark`. If `view` is specified, first looks in view properties for `view`, then in buffer properties. `(PREVIOUS-CHARPROP-VALUE mark name &key view)` Returns the value of property `name` in the character before `mark`. If `view` is specified, first looks in view properties for `view`, then in buffer properties. `(SET-CHARPROP-VALUE mark name value &key count end view)` Sets the value of property `name` to `value` for characters at `mark`. Setting the value to `nil` effectively removes the property. Either `count` or `end` may be specified, but not both. If `count` is specified, applies to that many characters after `mark` (or before `mark` if count is negative). If `end` is specified, applies to characters between `mark` and `end`. The default is `:count 1`. If `view` is specified, sets the property in the view layer only, otherwise sets the buffer property. `(FIND-CHARPROP-VALUE mark name value &key count end view from-end)` Find a character whose `name` property has the value `value` and move `mark` there. `count` and `end` can be used to specify the range of buffer to search, the default is `:end` `(buffer-end-mark` `(mark-buffer mark))`. If `from-end` is specified, searches from the end of the range. `view` is as for `next-charprop-value`. Returns `mark` if successful, or `nil` if not, in the latter case, `mark` is unmoved. `(NEXT-CHARPROPS mark &key view filter)` Returns a value representing the set of properties of the character after mark. If `view` is specified, returns the union of view and buffer properties. `filter` can be used to limit the properties looked at. It can be a non-empty sequence of property names, or a function that takes a property name as an argument and returns true if the property is to be considered, or `:display` to consider only display properties, or `T`, the default, to consider all properties. `(PREVIOUS-CHARPROPS mark &key view filter)` Returns a value representing the set of properties of the character before mark. Arguments are as for `NEXT-CHARPROPS`. `(SET-CHARPROPS mark charprops &key count end view filter)` `charprops` should be a value representing a set of properties. Each property in in the set is applied as if by `set-charprop-value`. Properties not included in `charprops` but allowed by `filter` are set to `nil`, effectively removing them. Properties not allowed by `filter` are not changed. The default `filter` is `(charprops-names` `charprops)`. `(CHARPROPS-IN-REGION region-or-mark &key count end filter)` Returns a value representing the sequence of charprops for all the characters in a region. `count` and `end` can only be specified if `region-or-mark` is a mark, in which case they define the region as described for `set-charprop-value`. Only properties allowed by `filter` are recorded. The returned object doesn't encode the buffer range or the characters themselves, just the sequence of charprops. `(APPLY-CHARPROPS mark charprops-range &key filter from-end)` `charprops-range` must be a value returned by `charprops-in-region`. Applies the `charprops` in `charprops-range` to the sequence of characters starting at `mark` (or ending at `mark` if `from-end` is specified). `filter` can be used to restrict the set of properties applied. `(FIND-CHARPROPS mark charprops &key count end view filter from-end)` Find a character whose properties mark `charprops`, and move `mark` there. Only properties specified in `filter` are considered. `count`, `end`, `view` and `from-end` are like for `find-charprop-value`. Returns `mark` if successful, or `nil` if not, in the latter case, `mark` is unmoved. `(FIND-CHARPROPS-CHANGE mark &key count end view filter from-end)` Find a character whose properties are different from `next-charprops` if `from-end` is `nil`, or different from `previous-charprops` if `from-end` is non-`nil`. Only properties allowed by `filter` are considered. If successful, move `mark` there and return it, else leave `mark` unchanged and return `nil`. === Utility functions === `(CHARPROP-EQUAL name value1 value2)` Returns true if `value1` and `value2` are equivalent property values for `name`. By default, it compares strings using `STRING=` (so it's case sensitive), numbers using `=` (so that 12 and 12.0 are equivalent) and all other values using `EQL`. `(CHARPROPS-GET charprops name &key filter)` Given a property set `charprops`, which can be a plist, a hash table, or a value returned by `next-charprops` et. al., return the value given to property `name`, or `nil` if no value is given or if `name` is not covered by `filter`. `(CHARPROPS-SET charprops name value)` Given a property set `charprops`, which can be a plist, a hash table, or a value returned by `next-charprops` et. al., return a property set where `name` has value `value`. The original `charprops` may be destructively modified by the operation. `(CHARPROPS-EQUAL charprops1 charprops2 &key filter)` Returns true if `charprops1` and `charprops2` are equivalent on the domain specified by `filter`. No distinction is made between missing properties and properties whose value is `NIL`. `(CHARPROPS-AS-PLIST charprops &key filter)` Return the representation of `charprops` as a plist, including only the properties allowed by `filter`. The returned plist may be part of an internal representation of `charprops` and therefore must not be destructively modified by the user. `(CHARPROPS-AS-HASH charprops &key filter)` Return the representation of `charprops` as a hash table, including only the properties allowed by `filter`. The returned hash table may be part of an internal representation of `charprops` and therefore must not be destructively modified by the user. `(CHARPROPS-NAMES charprops &key filter)` Returns the set of property names of all properties present in `charprops` and allowed by `filter`. === Insertion === `(SET-BUFFER-CHARPROPS buffer charprops)` Sets the buffers default property set. This set is used when new text is inserted into the buffer, as described below. `(BUFFER-CHARPROPS buffer)` Returns the buffer default property set. `(INSERT-CHARACTER mark char &key charprops)` This existing Hemlock function is extended to accept a `:charprops` argument. This argument can be a property set, or it can be the keyword `:neighbor`, the default, in which case `(previous-charprops mark)` is used unless mark is at the begining of a line, in which case `(next-charprops mark)` is used. The specified property set is merged with the buffer default property set and applied to the inserted character. `(INSERT-STRING mark string &key charprops)` This existing Hemlock function is extended to accept a `:charprops` argument, as described for `insert-character` above. The specified property set is merged with the buffer default property set and applied to all characters in the inserted string. `(INSERT-REGION mark region)`[[BR]] `(NINSERT-REGION mark region)` These existing Hemlock functions are defined to copy the charprops from the source region. `(STRING-TO-REGION string &key charprops)` This existing Hemlock function is extended to accept a `:charprops` argument, which must be a property set. The specified property set is applied to all characters in the newly constructed region. == Future extensions == * A protocol to allow mapping from user-defined properties to predefined display properties. I.e. the user could mark up the buffer with `FOO` property, and then somewhere in another place specify that chars with the `FOO` property should be shown in blue. * A protocol to add a new display property (including a Cocoa-specific part to make display do something with it). * A way to associate a value comparison function with a user property. Might be as simple as declaring that `CHARPROP-EQUAL` is a generic function, but I just haven't thought about it yet. * A `:hidden` property to request the character be drawn at 0 width - to allow hiding parts of buffer. * Allow properties to be attached to regions as well as characters, lots of issues, but this would be a start on presentation support. * Support multiple overlays in general (view properties are just a special case of overlays). * Do not restrict view properties to colors and underlines, by not using Cocoa temporary attributes to implement them.