6

I've read What is inhibit-point-motion-hooks?.

Assume some minor-mode my-mode that wants to do point-motion-y things.

Assume my--point-entered and my--point-left functions that work fine in Emacs < 25, when my-mode sets point-entered and point-left props to use them.

Assume I'd like to have the mode keep working on Emacs < 25, but also do the right thing if it finds itself on 25+. What is the right thing to do?

I could (setq-local inhibit-point-motion-hooks nil) and call it a day. But that var is described as "obsolete", which seems stronger than "deprecated". So that seems like not the right thing.

Is the following a good template to use instead?

;; When mode is enabled
(when (fboundp 'cursor-sensor-mode)
  (cursor-sensor-mode 1))

;; When mode is disabled
(when (fboundp 'cursor-sensor-mode)
  (cursor-sensor-mode -1))

(defun my--cursor-sensor-function (window old dir)
  (let ((new (window-point window))) ;is this correct ???
    (pcase dir
      (`entered (my--point-entered old new))
      (`left    (my--point-left    old new)))))
;; where my--point-* are existing point motion functions

;; Where the props are added:
(let ((motion-props (if (fboundp 'cursor-sensor-mode)
                              (list 'cursor-sensor-functions
                                    (list #'my--cursor-sensor-function))
                            (list 'point-entered #'my--point-entered
                                  'point-left    #'my--point-left))))
  (add-text-properties beg
                       end
                       (append (list 'some-other-prop some-val)
                               motion-props)))

Or if that's not a good approach, what is the recommended way to work with both older and newer versions of Emacs?

Greg Hendershott
  • 1,483
  • 12
  • 17
  • 1. Your second sexp overrides the first one: if `cursor-sensor-mode` is defined then the function is ultimately called with a `nil` argument. 2. Calling it with a `nil` arg or a `t` arg has the same effect, anyway. Use `1` and `-1` to turn it on and off, respectively. – Drew Jan 04 '17 at 17:40
  • @Drew Oops. I (thought I) already knew that detail about mode functions but managed to get that wrong in my example. Thanks! I'll edit. – Greg Hendershott Jan 04 '17 at 18:58

1 Answers1

3

The two systems work in fundamentally different ways, so you can't easily have a 100% solution that unifies the two, but your approach looks OK. The only thing I'd recommend is to do the emulation the other way around: write your code for cursor-sensor-mode mostly and then write my-point-entered and my-point-left functions that call my-cursor-sensor-function. The reason for that is that it is "optimized for the future" rather than "optimized for the past".

Stefan
  • 26,154
  • 3
  • 46
  • 84
  • Thanks! I'll take your advice and reverse the emulation. Just to confirm, is it reliable to use `window-point` to get the `new` position (that's no longer provided as an argument); was that your intent? – Greg Hendershott Jan 05 '17 at 15:20
  • 1
    Yes, `window-point` is what you want for that. – Stefan Jan 05 '17 at 21:17
  • Sorry a follow-up point: I'm seeing `cursor-sensor-mode` work only when entering a region using forward motion. Backing into a region with e.g. `backward-char`, my cursor sensor function is not called. Is this as-expected, a bug, or a mistake on my end? – Greg Hendershott Jan 09 '17 at 16:25
  • @GregHendershott: your description is not precise enough for me to decide if it sounds like a bug or a misunderstanding. – Stefan Jan 09 '17 at 20:27
  • Actually the issue seems to be that c-s-m occurs one position sooner than a p-e when moving backwards. Something like treating the property `end` as inclusive vs. exclusive. Will report back with simpler recipe. – Greg Hendershott Jan 09 '17 at 22:20
  • @GregHendershott: Whether point is considered "inside" or "outside" depends on the stickiness of the property. For text-properties, stickiness of a property depends on the `front-sticky` and `rear-nonsticky` properties and for overlays it depends on the "front-advance" and "rear-advance" args that were passed to `make-overlay`. – Stefan Jan 09 '17 at 22:54
  • Alas adding `'rear-nonsticky` with value `'(cursor-sensor-functions)` doesn't help. It seems [this expression in `cursor-sensor--detect`](https://github.com/emacs-mirror/emacs/blob/65eee8392ff95f58f7b0bd036e1fe065523658c6/lisp/emacs-lisp/cursor-sensor.el#L117-L118) is hardcoded to try looking back one more position regardless. – Greg Hendershott Jan 10 '17 at 04:55
  • Hmm... indeed, according to the comment I didn't use the stickiness in the end, and instead I wrote the code so that if point is at either boundary it's always considered "inside". So, indeed, the property's end is "inclusive", just like the property's start. To the extent that `point` is always a position *between* characters whereas properties apply to the characters themselves, this should result in a "symmetric" behavior. So I'm still not sure why/where you see an asymmetry in your tests. – Stefan Jan 10 '17 at 05:03
  • It's awkward because my c-s-function uses `get-text-property` to find another prop -- but doesn't because _its_ `end` is treated as exclusive. It's also awkward when two c-s-m regions are adjacent, even with a space between them, the c-s-func is called as if they're one region. – Greg Hendershott Jan 10 '17 at 18:19
  • I'm starting to feel that adding a `(setq-local inhibit-motion-hooks nil)` hack is my least-worst option short-term. :( Maybe I need to do that as an initial fix, and loop back to using c-s-m later. – Greg Hendershott Jan 10 '17 at 18:22