Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow custom 'word', 'symbol' definitions #596

Merged
merged 2 commits into from
Jun 13, 2024

Conversation

45mg
Copy link
Contributor

@45mg 45mg commented May 18, 2024

Allows users to customize the behavior of the commands related to marking and moving by words and symbols.

Make all commands related to words and symbols rely on forward-thing and bounds-of-thing-at-point. Then, define the 'thing's that these functions are called on in meow--word-thing and meow--symbol-thing. Now the user can define their own things and make Meow use them by setting these variables.

Meow users may find Emacs' default notions of 'word' and 'symbol' to be unsatisfactory for modal editing. For example, word movements tend to skip over non-alphanumeric characters, meaning that meow-next-word and meow-back-word will skip them when not expanding a selection. This commit allows users to redefine these notions via thingatpt.

With this change, every Meow motion is now customizable. The only exception is meow-line; it should not be necessary to change its behavior since Meow already provides meow-visual-line.

@45mg
Copy link
Contributor Author

45mg commented May 18, 2024

Here is an example of how this could be used to get 'word' behavior closer to Vim's:

(defun forward-vimlike-word (&optional arg)
  "Alternate `forward-word'. Essentially the same idea as Vim's 'e'."
  (interactive "^p")
  (setq arg (or arg 1))
  (cl-destructuring-bind (sign move-func char-func)
      (if (>= arg 0)
          '(1 skip-syntax-forward char-after)
        '(-1 skip-syntax-backward char-before))
    (with-syntax-table (standard-syntax-table)
      (let ((distance sign))
        (while (and distance (> (abs distance) 0) (> (* arg sign) 0))
          (setq distance
                (when-let ((next-char (funcall char-func))
                           (next-syntax (char-syntax next-char)))
                  (cond ((eq next-syntax ?w)
                         (funcall move-func "w"))
                        ((eq next-syntax ?\ )
                         (prog1
                             (funcall move-func " ")
                           (forward-vimlike-word sign)))
                        (t
                         (funcall move-func "^w ")))))
          (setq arg (- arg sign)))
        (and distance (> (abs distance) 0))))))

(put 'vimlike-word 'forward-op #'forward-vimlike-word)

(setq meow--word-thing 'vimlike-word)

@45mg 45mg force-pushed the custom-word-symbol-things branch from 911aeee to bf91bee Compare May 19, 2024 19:38
@eshrh
Copy link
Member

eshrh commented May 20, 2024

Looks good and works well. This is a useful abstraction to have! All the other meow commands are already dependent on thingatpt, i think this is good too.

Your old docstring seems better than the one you force pushed? If you feel like it's redundant I think it should at least have some words explaining that you can define your own things to customize behavior. Ideally, you should add a section in CUSTOMIZATIONS.org as well. It would be nice to include your vim word example in the docs.

I believe you also need to modify the forward-word calls in beacon mode. This section:

meow/meow-beacon.el

Lines 219 to 225 in 99e08c9

(while (forward-word 1)
(unless (= (point) orig)
(meow--beacon-add-overlay-at-point (meow--hack-cursor-pos (point)))))))
(save-mark-and-excursion
(goto-char (point-max))
(while (forward-word -1)

I briefly tested replacing the forward word calls with forward-thing and it seems to work.

@45mg 45mg force-pushed the custom-word-symbol-things branch 2 times, most recently from 614f9a3 to 58944d1 Compare May 22, 2024 10:12
@45mg
Copy link
Contributor Author

45mg commented May 22, 2024

Your old docstring seems better than the one you force pushed? If you feel ...

I wrote a new one. I also added a section to CUSTOMIZATIONS.org, with my example. It's definitely possible to come up with better word redefinitions - this one generates too many expansion hints because it considers single chars like hyphens between words to also be words - but for now I think it's fine as a proof-of-concept.

I believe you also need to modify the forward-word calls in beacon mode.

Good catch. Done.

@45mg 45mg force-pushed the custom-word-symbol-things branch from 58944d1 to b0c31c2 Compare May 22, 2024 10:44
@45mg
Copy link
Contributor Author

45mg commented May 22, 2024

I force-pushed to rename the variables to meow-word-thing and meow-symbol-thing, since they're not internal variables.

@45mg
Copy link
Contributor Author

45mg commented May 22, 2024

While fixing a few places where I forgot to replace forward-word and forward-symbol, I realized that a lot of Meow's logic for word and symbol marking/movement is duplicated across multiple functions. So I added a commit that combines all this code into a single set of functions that uses thingatpt.

Allows users to customize the behavior of the commands related to
marking and moving by words and symbols.

Make all commands related to words and symbols rely on `forward-thing'
and `bounds-of-thing-at-point'. Then, define the 'thing's that these
functions are called on in `meow-word-thing' and `meow-symbol-thing'.
Now the user can define their own things and make Meow use them by
setting these variables.

Meow users may find Emacs' default notions of 'word' and 'symbol' to be
unsatisfactory for modal editing. For example, word movements tend to
skip over non-alphanumeric characters, meaning that `meow-next-word' and
`meow-back-word' will skip them when not expanding a selection. This
commit allows users to redefine these notions via `thingatpt'.

With this change, every Meow motion is now customizable. The only
exception is `meow-line'; it should not be necessary to change its
behavior since Meow already provides `meow-visual-line'.
@45mg 45mg force-pushed the custom-word-symbol-things branch from 2a1268f to 3660038 Compare May 22, 2024 11:16
@45mg
Copy link
Contributor Author

45mg commented May 22, 2024

Force-pushed again to fix some typos (sigh). It should all work now.

In addition to all commands related to words and symbols now relying
`forward-thing' and `bounds-of-thing-at-point', which use the things
defined in `meow-word-thing' and `meow-symbol-thing', this commit
consolidates the logic used by these commands into `meow-mark-thing',
`meow-next-thing', `meow--fix-thing-selection-mark',
`meow--forward-thing-1', and `meow--backward-thing-1'. This results in
much less code duplication.
@45mg 45mg force-pushed the custom-word-symbol-things branch from 3660038 to f77341b Compare June 1, 2024 17:03
@45mg
Copy link
Contributor Author

45mg commented Jun 1, 2024

Force-pushed a small fix - the function to add word beacons no longer requires meow-forward-thing to return t when it moved successfully.

@eshrh
Copy link
Member

eshrh commented Jun 2, 2024

@DogLooksGood review? looks good to me.

@45mg
Copy link
Contributor Author

45mg commented Jun 13, 2024

Hope this can be merged soon. I had other ideas for PRs but I've been holding off on them, because I'd probably want to use the abstractions introduced in this one...

@eshrh eshrh merged commit bc05b04 into meow-edit:master Jun 13, 2024
eshrh pushed a commit that referenced this pull request Jul 12, 2024
Fixes regression from #596. Picks between a bound and the mark correctly when the mark is within bounds of the thing being selected.
@DogLooksGood
Copy link
Collaborator

DogLooksGood commented Oct 23, 2024

There could be something wrong, I haven't looked deeply.

The word/symbol forward and backward shouldn't select only the word/symbol.

The expected behavior is

foo| bar baz -> foo| bar| baz

foo| (bar baz) -> foo (|bar| baz)

By reading the comment of meow--fix-thing-selection-mark I think whitespaces are expected to be included, however current implementation drops them. I added an optional argument include-syntax to meow-next-thing, we can use this argument to specify how shrinking works.

Commit: c0878ac

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants