This document describes a proposal for comment and review. It is not actually implemented anywhere.
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.
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:
- a string which names the font family or the specifc font, or one of :document-font, :fixed-font, :system-font.
- a real number, the size of the font
- one of :plain or :bold
- one of :condensed or :expanded
- one of :italic or :roman
- one of :single, :double, or :thick
- a string or integer value as in HTML, e.g. "Blue" or #x0000FF
- same as above
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.
(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.
(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.
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)
(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.
- 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.