Skip to content

Instantly share code, notes, and snippets.

@jasonm23
Forked from Fuco1/text-property-api-org
Last active August 31, 2022 10:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jasonm23/88236a921997089a297f31337d028619 to your computer and use it in GitHub Desktop.
Save jasonm23/88236a921997089a297f31337d028619 to your computer and use it in GitHub Desktop.
Text property api for emacs

All these operations are very natural for buffer objects as well as strings, which leads me to the conclusion we should provide two flavours for each function, for buffers and for strings. The way emacs does it is by specifying an object argument. I find this suboptimal, but it is also possible solution (and would reduce the number of functions in half). Note that there are also different indexing conventions, see the Question below.

All functions come in buffer and string flavours. The “current position” is called point in buffer versions and offset in string versions. In fact, buffer implementation is the “default” one, the wrapper for strings is added like so

(with-temp-buffer
  (insert string)
  (goto-char (point-min))
  (call-buffer-flavour-of-function))

Insertion into buffers is very fast so there is virtually no performance hit.

Question: should be number everything from 0, from 1, or should we adhere to the “convention” in emacs (strings from 0, buffers from 1).

All range functions come with optional arguments beg and end. Since we most of the time want to operate on the entire string/buffer, these are put to the end to not bother us.

Naming conventions:

  • The suffix -p indicates a predicate. Functions marked so should have no side effects.
  • The suffix -at indicates the function takes a point, or defaults to position under cursor.
  • The suffix -with or -where indicates that we take name of a property. We use two suffices to make the name more natural in english.
  • The suffix -value indicates that we also take a value of the property and only operate on regions where property’s value match this.
  • The suffix -by indicates that we also take a predicate and only operate on regions where property’s value satisfies this.
  • [ ] s-property-at prop &optional point
    • Return value of property prop at point.
  • [ ] s-properties-at &optional point # text-properties-at
    • Return a plist of properties at point.
  • [ ] s-property-at-p prop &optional point
    • Return non-nil if prop is set at point.
  • [ ] s-properties-at-p props &optional point
    • Return non-nil if any property from props is set at point.
  • [ ] s-property-value-at-p
  • [ ] s-properties-value-at-p
  • [ ] s-property-by-at-p
  • [ ] s-properties-by-at-p
  • [ ] s-get-regions-with-property prop &optional beg end # message-text-with-property, gnus-find-text-property-region
    • Return list of (beg . end) values describing regions where prop is set.
  • [ ] s-get-regions-with-property-value
  • [ ] s-get-regions-with-property-by
  • [ ] s-alter-property prop fn &optional beg end # alter-text-property
    • Replace text property prop with result of calling fn on this property. fn takes two arguments: prop and its value.
  • [ ] s-alter-property-value
  • [ ] s-alter-property-by
  • [ ] s-map-regions-with-property prop fn &optional beg end # this can be used to implement s-alter-property
    • Replace all regions having prop with results of calling fn on these regions.
  • [ ] s-map-regions-with-property-value
  • [ ] s-map-regions-with-property-by
  • [ ] s-add-property prop value &optional beg end
    • Add prop with value.
  • [ ] s-add-properties props &optional beg end
    • Add props. props is a plist of property/value pairs.
  • [ ] s-add-property-at prop value &optional point
    • Add prop with value at point.
  • [ ] s-add-properties-at props &optional point
    • Add props at point. props is a plist of property/value pairs.
  • [ ] s-add-property-where prop new-prop val &optional beg end # gnus-add-text-properties-when
    • Add new-prop with val to all regions where prop is set.
  • [ ] s-add-property-where-value
  • [ ] s-add-property-where-by
  • [ ] s-add-properties-where prop props &optional beg end
    • Add props to all regions where prop is set. props is a plist of property/value pairs.
  • [ ] s-add-properties-where-value
  • [ ] s-add-properties-where-by
  • [ ] do we also want -set- flavours here?
    • It is the same as doing -remove- and then corresponding -add-
  • [ ] s-remove-property old-prop &optional beg end
  • [ ] s-remove-property-where prop old-prop &optional beg end # gnus-remove-text-properties-when
    • Remove old-prop from all regions where prop is set.
  • [ ] s-remove-property-where-value
  • [ ] s-remove-property-where-by
  • [ ] s-remove-properties props &optional beg end
    • Remove props.
  • [ ] s-remove-properties-where prop props &optional beg end
    • Remove props from all regions where prop is set.
  • [ ] s-remove-properties-where-value
  • [ ] s-remove-properties-where-by
  • [ ] s-strip-properties &optional beg end
    • Remove all properties.
  • [ ] s-has-property prop &optional beg end
    • Return the first position where prop is set or nil if it is never set.
  • [ ] s-has-property-p prop &optional beg end
    • Return non-nil if prop is set anywhere between beg and end or nil if it is never set.
  • [ ] s-has-property-value
  • [ ] s-has-property-value-p
  • [ ] s-has-property-by
  • [ ] s-has-property-by-p
  • [ ] s-lacks-property prop &optional beg end
    • Return the first position where prop is not set or nil if it is always set.
  • [ ] s-lacks-property-p prop &optional beg end
    • Return non-nil if prop is not set somewhere or nil if it is always set.
  • [ ] s-lacks-property-value
  • [ ] s-lacks-property-value-p
  • [ ] s-lacks-property-by
  • [ ] s-lacks-property-by-p
  • [ ] s-find-property prop &optional point limit
    • Return the first non-nil value of prop after point or nil if it is never set.
  • [ ] s-find-property-backward prop &optional point limit
    • Return the first non-nil value of prop before point or nil if it is never set.
  • [ ] s-next-property-change &optional point limit
    • Return the position of next property change or nil if none occurs.
  • [ ] s-previous-property-change &optional point limit
    • Return the position of previous property change or nil if none occurs.
  • [ ] s-next-property-change-where prop &optional point limit
  • [ ] s-previous-property-change-where
  • [ ] s-next-property-change-where-value
  • [ ] s-previous-property-change-where-value
  • [ ] s-next-property-change-where-by
  • [ ] s-previous-property-change-where-by
  • [ ] s-equal-including-properties-p
    • Return non-nil if two strings are equal, including properties.

More exotic properties we can implement later

  • font-lock-fillin-text-property
  • gnus-put-text-property-excluding-characters-with-faces ;; put property everywhere except on blocks with property (and value)
  • font-lock-prepend-text-property ;; add more general ‘map property’
  • font-lock-append-text-property
  • circe-highlight-extend-properties ;; this can also be implemented using a map
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment