Context Navigation

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-namescharprops).

(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
region, 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)(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.