hlissner / evil-snipe

2-char searching ala vim-sneak & vim-seek, for evil-mode
MIT License
341 stars 25 forks source link

Add option for making jumps not skip over invisible characters #93

Open srithon opened 1 year ago

srithon commented 1 year ago

Describe your request

I'd like to have an option for making evil-snipe not skip over invisible characters. I looked through the source and saw that the invisible-p conditions in the evil-snipe--seek-re function are responsible for this behavior. Commenting these checks out gave me the behavior that I wanted.

(defun evil-snipe--seek-re (data scope count)
  (let ((regex (mapconcat #'cdr data ""))
        result)
    (when (and evil-snipe-skip-leading-whitespace
               (looking-at-p "[ \t]+")
               (string-match-p "^[ \t]+" (mapconcat #'car data "")))
      (setq regex (concat regex "[^ \t]")))
    (when (setq result (re-search-forward regex scope t count))
      (if ;; (or (invisible-p (match-beginning 0))
          ;;     (invisible-p (1- (match-end 0))))
          nil
          (evil-snipe--seek-re data scope count)
        result))))

Briefly explain its use-case

Currently, evil-avy allows you to jump to invisible characters, which is very useful in Org Mode when org-hide-emphasis-markers is set. I'm using evil-avy for Vim-Sneak-like labelling with s/S, and evil-snipe for its single-char seeking. However, since evil-snipe skips over invisible characters, there's no way to seek to, for instance, a ~ delimiting an inline code block. In the following example, where | denotes the point, navigating to the tilde in Org Mode with emphasis markers hidden requires using avy or another search, while normally we could have simply used f.

|foo foo foo foo foo ~foo~ foo foo foo foo foo

I realized that the current behavior may be useful to skip over the invisible emphasis characters in the following example, but personally I would rather have them for the general case.

|... ~this is an inline code block~with a tilde inside of it; the inner tilde will be rendered normally since it does not delimit the code block~

This is a pretty easy change to make, but I wasn't sure if there were more reasons for the stock behavior which make my change incorrect in cases other than the ones I tested, so I didn't make a full PR.

Also, although this may not be the right place to put this, I originally wanted to have emphasis markers be temporarily unhidden when using evil-snipe to nullify the issue, but I couldn't get a solution completely working since I couldn't figure out how to hook onto evil-snipe exitting. Also, font-lock-update was quite slow and made the approach infeasible. Here's what I had:

(defun srithon/set-emphasis-marker-visibility (show)
  "Hides emphasis markers if nil, otherwise shows them"
  (interactive)
  (let ((current-hidden-state org-hide-emphasis-markers)
        (expected-hidden-state (not show)))
    (when (not (equal current-hidden-state expected-hidden-state))
      (setq org-hide-emphasis-markers expected-hidden-state)
      (font-lock-update))))

(defun srithon/make-emphasis-markers-visible (&rest args)
  (srithon/set-emphasis-marker-visibility t))

(defun srithon/make-emphasis-markers-hidden (&rest args)
  (srithon/set-emphasis-marker-visibility nil))

(advice-add #'evil-snipe--seek :before #'srithon/make-emphasis-markers-visible)

;; doesn't work as I thought it might
;; (advice-add #'evil-snipe--cleanup :after #'srithon/make-emphasis-markers-hidden)