Skipping words with C-<right> like other editors do

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

Skipping words with C-<right> like other editors do

R. Diez
Hi all:

I am not satisfied with the standard behaviour of C-<right> etc. I want it to work the way most "normal" editors do.

I tried the following with Mousepad under Linux (the default editor under Xfce):

text --- ^^^ *** /// ;;; aa-xx bb


I have marked with an exclamation mark all places where the cursor stops at when you repeatedly press Ctrl+right or Ctrl+left:


!text! ---! ^^^! ***! ///! ;;;! aa!-!xx! bb!

KDE's text editor Kate, Notepad++ under Windows, and Java environment NetBeans behave a little different with regards to the start/end word position:

!text !--- !^^^ !*** !/// !;;; !aa!-!xx !bb!

I think that this is the behaviour that I prefer.

I would prefer that the cursor only stopped once inside "aa-xx", like it is the case inside a text field in Firefox. In any case, I guess that, if Emacs' "superword-mode" is on, the cursor should not stop inside "aa-xx" at all.


I have tried everything I could think of to make Emacs behave that way: forward-word, forward-symbol, modify-syntax-entry.


I also tried this more elaborated solution:

https://emacs.stackexchange.com/questions/26417/custom-c-arrow-cursor-movement

But I just cannot get it right. Unfortunately, my Lips knowledge is too limited to come up with a more complex or flexible solution myself. After some years of frustration, I finally decided to post here.


Can anybody help?


Many thanks in advance,
  rdiez

Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

Emanuel Berg-4
R. Diez wrote:

> I am not satisfied with the standard
> behaviour of C-<right> etc. I want it to work
> the way most "normal" editors do.

Use these keys:

    C-f `forward-char'
    C-b `backward-char'
    M-f `forward-word'
    M-b `backward-word'
    C-e `move-end-of-line'
    C-a `move-beginning-of-line'

and so on.

There is a tutorial that helps you get the
basic finger habits going, I think, tho I never
did it myself. `C-h t' seems to start it.

--
underground experts united
http://user.it.uu.se/~embe8573
Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

Tim Johnson-2
* Emanuel Berg <[hidden email]> [180415 13:47]:

> R. Diez wrote:
>
> > I am not satisfied with the standard
> > behaviour of C-<right> etc. I want it to work
> > the way most "normal" editors do.
>
> Use these keys:
>
>     C-f `forward-char'
>     C-b `backward-char'
>     M-f `forward-word'
>     M-b `backward-word'
>     C-e `move-end-of-line'
>     C-a `move-beginning-of-line'
>
> and so on.
>
> There is a tutorial that helps you get the
> basic finger habits going, I think, tho I never
> did it myself. `C-h t' seems to start it.
  What Emanuel says.

  Furthermore - If you do
  c-h (or F1) - k
  then enter any one of the keys Emanuel listed.
  You will then get full documentation of the function it invokes.

  You can roll your own functions if not satisfied with behavior,
  and even rebind any keystroke to a new function.

  But do give emacs a chance to reveal itself in the "emacsen" way
  of doing things.

  cheers
--
Tim Johnson
http://www.akwebsoft.com, http://www.tj49.com

Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

Skip Montanaro
In reply to this post by R. Diez
While I agree with Emanuel's and Tim's comments (learning the basics
of Emacs' elementary cursor movement bindings is a good idea), I think
rdiez is actually complaining about how streams of characters are
divided into "words". I suspect the problem would exist with
forward-word. Right-word (target of C-right key binding) is little
more than a choice between forward-word and backward-word.

I think you probably want to tweak the relevant syntax table for the
editing mode you find yourself in most of the time. If you write
Python code, then overriding python-mode-syntax-table is probably what
you want. If, on the other hand, you mostly edit prose in text-mode,
then look at replacing text-mode-syntax-table. The key bit of
documentation you will want is the function documentation for
modify-syntax-entry. (C-h f modify-syntax-entry RET). The Emacs Lisp
reference manual has more detail:

https://www.gnu.org/software/emacs/manual/html_node/elisp/Syntax-Tables.html

I'd actually start there, maybe with an example syntax table for
something you are familiar with by your side.

Skip

Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

Emanuel Berg-4
In reply to this post by R. Diez
Skip Montanaro wrote:

> I think you probably want to tweak the
> relevant syntax table

You can use this (source last) as a template
for experimentation. Do `backward-word' and
`bwe' with point at the end of "g.args" and see
what happens.

This is done in the code with

    ?. "w"

which means, I think, that a point (full stop,
".") is considered a part of a word, so
`backward-word' shouldn't stop at it
but continue.

Perhaps there is a package that does what the
OP wants tho.

(defun backward-word-experiment ()
  (interactive)
  (let ((temp-st (make-syntax-table)))
    (modify-syntax-entry ?. "w" temp-st)
    (with-syntax-table temp-st
      (backward-word 1) )))
(defalias 'bwe 'backward-word-experiment)
;; never fear, g.args is here

--
underground experts united
http://user.it.uu.se/~embe8573
Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

James K. Lowden
In reply to this post by R. Diez
On Sun, 15 Apr 2018 18:49:47 +0000 (UTC)
"R. Diez" <[hidden email]> wrote:

> I have marked with an exclamation mark all places where the cursor
> stops at when you repeatedly press Ctrl+right or Ctrl+left:
>
>
> !text! ---! ^^^! ***! ///! ;;;! aa!-!xx! bb!
>
> KDE's text editor Kate, Notepad++ under Windows, and Java environment
> NetBeans behave a little different with regards to the start/end word
> position:
>
> !text !--- !^^^ !*** !/// !;;; !aa!-!xx !bb!

Somewhere in the documentation, a rational argument is made for emacs's
choice.  By defining forward-word and back-word asymetrically,
navigation in either direction is sped up.  To get to the beginning of
a word while going forward, just go to the end of the word you want,
and back to its beginning.  Editors that stop at the beginning of the
word in both directions have no good way to jump over arbitrary
whitespace.  

--jkl

Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

Yuri Khan-2
On Mon, Apr 16, 2018 at 6:34 AM, James K. Lowden <[hidden email]> wrote:
>> !text! ---! ^^^! ***! ///! ;;;! aa!-!xx! bb!
>> !text !--- !^^^ !*** !/// !;;; !aa!-!xx !bb!
>
> Somewhere in the documentation, a rational argument is made for emacs's
> choice.  By defining forward-word and back-word asymetrically,
> navigation in either direction is sped up.

Asymmetry is probably not the source of annoyance here. Speed is.

I tested the same line with Mousepad, Gedit, Midnight Commander,
Firefox, Vim, and Emacs. (Vim has a richer vocabulary of word motion
commands; I noted them separately.)

    Ctrl+right →
    text --- ^^^ *** /// ;;; aa-xx bb
    |   |                      |  |  |   Emacs *scratch*
    |   |   |   |   |   |   |  || |  |   Gedit, Mousepad
    |   |       |    |   |      | |  |   Firefox
    |    |   |   |   |   |   | ||  |     Midnight Commander, Vim w
    |    |   |   |   |   |   |     |     Vim W
    |  |   |   |   |   |   |  || |  |    Vim e
    |  |   |   |   |   |   |     |  |    Vim E

    Ctrl+left ←
    text --- ^^^ *** /// ;;; aa-xx bb
    |                        |  |  | |   Emacs *scratch*
    |        |      |   |    |  |  | |   Firefox
    |    |   |   |   |   |   | ||  | |   Gedit, Mousepad, MC, Vim b
    |    |   |   |   |   |   |     | |   Vim B
    |  |   |   |   |   |   |  || |   |   Vim ge
    |  |   |   |   |   |   |     |   |   Vim gE

So, observations:

* Most “reduced instruction set” editors have different stops for
forward and backward movement. Emacs is not the odd one here.

* Firefox does something that is very hard to describe.

* Emacs makes much fewer stops in comparison with other editors.
Namely, it stops only at transitions from letters to non-letters,
while most other editors stop at transitions from letters to
whitespace, letters to punctuation, and punctuation to whitespace.


I think it might be worthwhile to try implementing word motion
commands that takes into account both word-constituent and whitespace
syntax classes.

Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

Yuri Khan-2
On Mon, Apr 16, 2018 at 3:22 PM, Yuri Khan <[hidden email]> wrote:
>>> !text! ---! ^^^! ***! ///! ;;;! aa!-!xx! bb!
>>> !text !--- !^^^ !*** !/// !;;; !aa!-!xx !bb!

> * Emacs makes much fewer stops in comparison with other editors.
> Namely, it stops only at transitions from letters to non-letters,
> while most other editors stop at transitions from letters to
> whitespace, letters to punctuation, and punctuation to whitespace.

I came up with the following functions. Usage:

(require 'yk-word)
(global-set-key [remap forward-word] 'yk-word-forward)
(global-set-key [remap backward-word] 'yk-word-backward)
(global-set-key [remap left-word] 'yk-word-left)
(global-set-key [remap right-word] 'yk-word-right)
(global-set-key [remap kill-word] 'yk-word-kill-forward)
(global-set-key [remap backward-kill-word] 'yk-word-kill-backward)


=== : yk-word.el
(defun yk-word--motion (count skip char-at)
  "Move point COUNT words in the direction defined by SKIP and CHAR-AT."
  (let ((table (make-syntax-table (syntax-table))))
    (modify-syntax-entry ?\n "-" table)
    (with-syntax-table table
      (dotimes (_ count)
        (funcall skip "-")
        (pcase (funcall char-at (point))
          ('nil)
          ((app char-syntax ?w) (funcall skip "w"))
          (_ (funcall skip "^-w"))))))
  t)

(defun yk-word-forward (&optional count)
  "Move point COUNT words forward."
  (interactive "^p")
  (if (and count (> 0 count))
      (yk-word-backward (- count))
    (yk-word--motion (or count 1) #'skip-syntax-forward #'char-after)))

(defun yk-word-backward (&optional count)
  "Move point COUNT words backward."
  (interactive "^p")
  (if (and count (> 0 count))
      (yk-word-forward (- count))
    (yk-word--motion (or count 1) #'skip-syntax-backward #'char-before)))

(defun yk-word-right (&optional count)
  "Move point COUNT words to the right."
  (interactive "^p")
  (if (eq (current-bidi-paragraph-direction) 'left-to-right)
      (yk-word-forward n)
    (yk-word-backward n)))

(defun yk-word-left (&optional count)
  "Move point COUNT words to the left."
  (interactive "^p")
  (if (eq (current-bidi-paragraph-direction) 'left-to-right)
      (yk-word-backward n)
    (yk-word-forward n)))


(defun yk-word-kill-forward (count)
  "Kill COUNT words after point."
  (interactive "p")
  (let ((start (point)))
    (yk-word-forward count)
    (kill-region start (point))))

(defun yk-word-kill-backward (count)
  "Kill COUNT words before point."
  (interactive "p")
  (let ((start (point)))
    (yk-word-backward count)
    (kill-region start (point))))

(defun yk-word-delete-forward (count)
  "Delete COUNT words after point."
  (interactive "p")
  (let ((start (point)))
    (yk-word-forward count)
    (delete-region start (point))))

(defun yk-word-delete-backward (count)
  "Delete COUNT words before point."
  (interactive "p")
  (let ((start (point)))
    (yk-word-backward count)
    (delete-region start (point))))


(provide 'yk-word)

Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

Stefan Monnier
> I came up with the following functions. Usage:

Why not use find-word-boundary-function-table?


        Stefan


Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

Yuri Khan-2
On Tue, Apr 17, 2018 at 1:49 AM, Stefan Monnier
<[hidden email]> wrote:
>> I came up with the following functions. Usage:
>
> Why not use find-word-boundary-function-table?

That looks interesting. As I understand it, it lets me customize the
behavior of forward-word and backward-word. I will try it tomorrow.

Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

James K. Lowden
In reply to this post by James K. Lowden
On Mon, 16 Apr 2018 15:22:07 +0700
Yuri Khan <[hidden email]> wrote:

> I tested the same line with Mousepad, Gedit, Midnight Commander,
> Firefox, Vim, and Emacs.

Interesting analysis!

--jkl
Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

Yuri Khan-2
In reply to this post by Stefan Monnier
On Tue, Apr 17, 2018 at 1:49 AM, Stefan Monnier
<[hidden email]> wrote:
>> I came up with the following functions. Usage:
>
> Why not use find-word-boundary-function-table?

Hm, no luck.

Consider the following buffer text (with ‘|’ indicating point and
second line showing numeric positions):

    foo| *** +++ bar
    1.. .5...10....5

Invoking ‘forward-word’ here causes the function registered in
‘find-word-boundary-function-table’ to be called with arguments (13
16), but we wanted to stop at 8. By the time the driver asks if anyone
wants off the bus, we’re already way past our stop!

Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

Stefan Monnier
>>> I came up with the following functions. Usage:
>> Why not use find-word-boundary-function-table?
>
> Hm, no luck.
>
> Consider the following buffer text (with ‘|’ indicating point and
> second line showing numeric positions):
>
>     foo| *** +++ bar
>     1.. .5...10....5
>
> Invoking ‘forward-word’ here causes the function registered in
> ‘find-word-boundary-function-table’ to be called with arguments (13
> 16), but we wanted to stop at 8. By the time the driver asks if anyone
> wants off the bus, we’re already way past our stop!

I think this deserves a bug report, then.  You shouldn't need to
override umpteen commands to provide you own definition of what is a word.


        Stefan

Reply | Threaded
Open this post in threaded view
|

Re: Skipping words with C-<right> like other editors do

Yuri Khan-2
On Tue, Apr 17, 2018 at 7:09 PM, Stefan Monnier
<[hidden email]> wrote:
>>> Why not use find-word-boundary-function-table?
>>
>> Invoking ‘forward-word’ here causes the function registered in
>> ‘find-word-boundary-function-table’ to be called with arguments (13
>> 16), but we wanted to stop at 8. By the time the driver asks if anyone
>> wants off the bus, we’re already way past our stop!
>
> I think this deserves a bug report, then.  You shouldn't need to
> override umpteen commands to provide you own definition of what is a word.

Filed bug#31204.

For personal use, I could probably just override ‘forward-word’ with
advice. ‘backward-word’ and ‘kill-word’ are implemented in terms of
‘forward-word’; ‘left-word’ and ‘right-word’ are implemented in terms
of ‘forward-word’ and ‘backward-word’; and ‘backward-kill-word’ is
implemented in terms of ‘kill-word’; so everything would just follow
suit.

However, I’m a bit wary about making ‘forward-word’ follow that
definition. I have literally no idea how many things will change
behavior if I redefine “word” to mean something more like “token”. For
one, ‘transpose-words’ would then behave like this:

    foo *** +++ (|bar)
    foo *** +++ bar(|)

For some people, this will make sense. For some, probably not.